From 3af86c0080c0675344c7940f9cb7003f1274dde1 Mon Sep 17 00:00:00 2001 From: mapperr Date: Fri, 13 Dec 2019 17:14:26 +0100 Subject: [PATCH] Use names as bases for shortcuts --- trullo.py | 69 +++++++++++++++++++++++++++++++++++++++------ trullo/printer.py | 48 ++++++++++++++++++++++--------- trullo/shortener.py | 30 ++++++++++++++------ trullo/tclient.py | 23 ++++++++++----- trullo/trl_board.py | 6 +++- trullo/trl_card.py | 7 ++++- trullo/trl_list.py | 7 +++-- 7 files changed, 149 insertions(+), 41 deletions(-) diff --git a/trullo.py b/trullo.py index 9ef11d3..c3dbfc3 100644 --- a/trullo.py +++ b/trullo.py @@ -87,7 +87,7 @@ def edit_card(card_to_edit: TrlCard = None) -> (str, str): with open(tmpfile_path, 'r') as fd: lines = fd.readlines() return urllib.parse.quote(lines[1].replace('\n', ''), safe=''), \ - urllib.parse.quote(str.join('', lines[2:]), safe='') + urllib.parse.quote(str.join('', lines[2:]), safe='') if __name__ == '__main__': @@ -99,7 +99,8 @@ if __name__ == '__main__': selected_board_filepath = f'{tmpdir}/.trl-selected-board' if os.path.exists(selected_board_filepath): with open(selected_board_filepath, 'r') as fh: - selected_board_id, selected_board_name = fh.readline().split(' ', 1) + selected_board_id, selected_board_name = fh.readline().split( + ' ', 1) if args['g']: api_path = args[''] @@ -109,8 +110,18 @@ if __name__ == '__main__': if args['b']: boards = tclient.get_boards() if args['']: - board = [board for board in boards - if board.shortcut.lower().startswith(args[''])][0] + board_shortcut = args[''] + matching_boards = [board for board in boards + if board.get_normalized_name() + .startswith(board_shortcut)] + if len(matching_boards) > 1: + matching_names = \ + [board.get_normalized_name() for board in matching_boards] + print( + f'shortcut [{board_shortcut}] matches more than one board: ' + f'{matching_names}') + exit(1) + board = matching_boards[0] print(f'selected board {board.raw_data["name"]}') with open(selected_board_filepath, 'w') as fh: fh.write(f'{board.id} {board.raw_data["name"]}') @@ -143,13 +154,41 @@ if __name__ == '__main__': new_command = args['n'] if new_command: target_list_shortcut = args[''] - list_id = [list_.id for list_ in board.lists if list_.id.lower().endswith(target_list_shortcut)][0] + matching_lists = [list_ for list_ in board.lists if + list_.get_normalized_name().startswith( + target_list_shortcut)] + if len(matching_lists) > 1: + matching_names = \ + [list_.get_normalized_name() for list_ in matching_lists] + print( + f'shortcut [{target_list_shortcut}] ' + f'matches more than one list: ' + f'{matching_names}') + exit(1) + list_id = matching_lists[0].id + new_card_name, new_card_desc = edit_card() tclient.new_card(list_id, new_card_name, new_card_desc) else: card_shortcut = args[''] - card = tclient.get_card( - [card.id for card in board.cards if card.shortcut.lower().startswith(card_shortcut)][0]) + matching_cards = [ + card + for card in board.cards + if card.get_normalized_name().startswith(card_shortcut) + ] + + if len(matching_cards) > 1: + matching_names = \ + [matching_card.get_normalized_name() + for matching_card in matching_cards] + print( + f'shortcut [{card_shortcut}] ' + f'matches more than one card: ' + f'{matching_names}') + exit(1) + + selected_card = matching_cards[0] + card = tclient.get_card(selected_card.id) open_command = args['o'] move_command = args['m'] @@ -158,7 +197,21 @@ if __name__ == '__main__': subprocess.Popen(['xdg-open', card.raw_data['shortUrl']]) elif move_command: target_list_shortcut = args[''] - list_id = [list_.id for list_ in board.lists if list_.id.lower().endswith(target_list_shortcut)][0] + + matching_lists = [list_ for list_ in board.lists if + list_.get_normalized_name().startswith( + target_list_shortcut)] + if len(matching_lists) > 1: + matching_names = \ + [list_.get_normalized_name() for list_ in + matching_lists] + print( + f'shortcut [{target_list_shortcut}] ' + f'matches more than one list: ' + f'{matching_names}') + exit(1) + list_id = matching_lists[0].id + tclient.move_card(card.id, list_id) elif edit_command: card_new_name, card_new_desc = edit_card(card) diff --git a/trullo/printer.py b/trullo/printer.py index ecf09d6..9821d80 100644 --- a/trullo/printer.py +++ b/trullo/printer.py @@ -11,40 +11,59 @@ from trullo.trl_card import TrlCard class Printer: @staticmethod def print_boards(boards: List[TrlBoard]): - symbol_count = Shortener.get_min_symbols_to_uniq([board.shortcut.lower() for board in boards]) + symbol_count = Shortener. \ + get_min_symbols_to_uniq([board.get_normalized_name() + for board in boards]) + print(f'symbol count is {symbol_count}') for board in boards: - print(f"[{board.shortcut[0:symbol_count].lower()}] {board.raw_data['name']}") + print( + f"[{board.get_normalized_name()[0:symbol_count].lower()}] " + f"{board.raw_data['name']}") @staticmethod def print_board(board: TrlBoard, list_shortcut: str = None): - symbol_count_cards = Shortener.get_min_symbols_to_uniq([card.shortcut for card in board.cards]) - symbol_count_lists = Shortener.get_min_symbols_to_uniq([list_.id for list_ in board.lists], True) + cards_names = [card.get_normalized_name() for card in board.cards] + board_lists_names = \ + [list_.get_normalized_name() for list_ in board.lists] + + symbol_count_cards = Shortener.get_min_symbols_to_uniq(cards_names) + symbol_count_lists = \ + Shortener.get_min_symbols_to_uniq(board_lists_names) + print(f"{board.raw_data['shortUrl']}") print('------------------------------') print(f"{board.raw_data['name']}") print() if board.lists is not None: for list_ in board.lists: - if list_shortcut is not None and not list_.id.lower().endswith(list_shortcut): + if list_shortcut is not None \ + and not \ + list_.get_normalized_name().startswith(list_shortcut): continue - print( - f"[{list_.id[len(list_.id) - symbol_count_lists:len(list_.id)].lower()}] {list_.raw_data['name']}") + shortcut = \ + list_.get_normalized_name()[0:symbol_count_lists].lower() + print(f"[{shortcut}] {list_.raw_data['name']}") for card in board.cards: if card.raw_data['idList'] == list_.id: - print(f"\t[{card.shortcut[0:symbol_count_cards].lower()}] {card.raw_data['name']}") + card_shortcut = card.get_normalized_name()[ + 0:symbol_count_cards].lower() + print(f"\t[{card_shortcut}] " + f"{card.raw_data['name']}") print() @staticmethod def print_board_lists(board: TrlBoard): - symbol_count_lists = Shortener.get_min_symbols_to_uniq([list_.id for list_ in board.lists], True) + symbol_count_lists = Shortener.get_min_symbols_to_uniq( + [list_.get_normalized_name() for list_ in board.lists]) print(f"{board.raw_data['shortUrl']}") print('------------------------------') print(f"{board.raw_data['name']}") print() if board.lists is not None: for list_ in board.lists: - print( - f"[{list_.id[len(list_.id) - symbol_count_lists:len(list_.id)].lower()}] {list_.raw_data['name']}") + list_shortcut = \ + list_.get_normalized_name()[0:symbol_count_lists].lower() + print(f"[{list_shortcut}] {list_.raw_data['name']}") print() @staticmethod @@ -57,8 +76,11 @@ class Printer: print(f'{d["name"]}') if len(d['labels']) > 0: print() - for l in d['labels']: - print(f'({l["name"] if l["name"] is not None and l["name"] != "" else l["color"]}) ', end='') + for label in d['labels']: + label_name = label["name"] \ + if label["name"] is not None and label["name"] != "" \ + else label["color"] + print(f'({label_name}) ', end='') print() print(formatted_desc) print() diff --git a/trullo/shortener.py b/trullo/shortener.py index be759a0..6b12300 100644 --- a/trullo/shortener.py +++ b/trullo/shortener.py @@ -6,17 +6,29 @@ import attr @attr.s(auto_attribs=True) class Shortener: @staticmethod - def get_min_symbols_to_uniq(strings: List[str], end: bool = False) -> int: + def normalize(string: str) -> str: + result = '' + for char in string: + if char.lower() not in 'qwertyuiopasdfghjklzxcvbnm1234567890': + continue + result += char.lower() + return result + + @staticmethod + def get_min_symbols_to_uniq(strings: List[str]) -> int: symbol_counter = 1 longest_item_length = Shortener.get_longest_item_length(strings) - if end: - while symbol_counter < longest_item_length \ - and Shortener.are_there_duplicates([el[len(el)-symbol_counter:len(el)].lower() for el in strings]): - symbol_counter += 1 - else: - while symbol_counter < longest_item_length \ - and Shortener.are_there_duplicates([el[0:symbol_counter].lower() for el in strings]): - symbol_counter += 1 + string_list = [ + string_item[0:symbol_counter].lower() + for string_item in strings + ] + while symbol_counter < longest_item_length \ + and Shortener.are_there_duplicates(string_list): + symbol_counter += 1 + string_list = [ + string_item[0:symbol_counter].lower() + for string_item in strings + ] return symbol_counter @staticmethod diff --git a/trullo/tclient.py b/trullo/tclient.py index 0cd3533..b4ca605 100644 --- a/trullo/tclient.py +++ b/trullo/tclient.py @@ -14,8 +14,10 @@ logger = logging.getLogger(__name__) @attr.s(auto_attribs=True) class TClient: - trello_token: str = attr.ib(default=os.environ['TRELLO_TOKEN'] if 'TRELLO_TOKEN' in os.environ else '') - trello_api_key: str = attr.ib(default=os.environ['TRELLO_API_KEY'] if 'TRELLO_API_KEY' in os.environ else '') + trello_token: str = attr.ib(default=os.environ[ + 'TRELLO_TOKEN'] if 'TRELLO_TOKEN' in os.environ else '') + trello_api_key: str = attr.ib(default=os.environ[ + 'TRELLO_API_KEY'] if 'TRELLO_API_KEY' in os.environ else '') base_url: str = attr.ib(default='https://api.trello.com/1') def build_auth_params(self) -> Dict[str, str]: @@ -26,13 +28,16 @@ class TClient: return res.json() def get(self, path: str) -> Dict: - return self.handle_res(requests.get(self.base_url + path, self.build_auth_params())) + return self.handle_res( + requests.get(self.base_url + path, self.build_auth_params())) def post(self, path: str) -> Dict: - return self.handle_res(requests.post(self.base_url + path, self.build_auth_params())) + return self.handle_res( + requests.post(self.base_url + path, self.build_auth_params())) def put(self, path: str) -> Dict: - return self.handle_res(requests.put(self.base_url + path, self.build_auth_params())) + return self.handle_res( + requests.put(self.base_url + path, self.build_auth_params())) def get_boards(self) -> List[TrlBoard]: res = self.get('/members/me/boards?lists=open') @@ -49,11 +54,15 @@ class TClient: if k == 'lists': lists = self._extract_lists(v) if not board_closed: - boards.append(TrlBoard(board_id, raw_board['shortLink'], lists, [], raw_board)) + boards.append( + TrlBoard(board_id, raw_board['shortLink'], lists, [], + raw_board)) return boards def get_board(self, board_id: str) -> TrlBoard: - res = self.get(f'/batch?urls=/board/{board_id},/board/{board_id}/lists/open,/board/{board_id}/cards/open') + res = self.get(f'/batch?urls=/board/{board_id},' + f'/board/{board_id}/lists/open,' + f'/board/{board_id}/cards/open') board = TrlBoard(board_id, board_id, [], [], res[0]['200']) for item in res[1]['200']: list_ = TrlList(item['id'], item) diff --git a/trullo/trl_board.py b/trullo/trl_board.py index 0d87b5e..f313fd2 100644 --- a/trullo/trl_board.py +++ b/trullo/trl_board.py @@ -2,6 +2,7 @@ from typing import Dict, List import attr +from trullo.shortener import Shortener from trullo.trl_list import TrlList from trullo.trl_card import TrlCard @@ -9,7 +10,10 @@ from trullo.trl_card import TrlCard @attr.s(auto_attribs=True) class TrlBoard: id: str - shortcut: str + short_link: str lists: List[TrlList] cards: List[TrlCard] raw_data: Dict + + def get_normalized_name(self) -> str: + return Shortener.normalize(self.raw_data['name']) diff --git a/trullo/trl_card.py b/trullo/trl_card.py index d0bffe4..6bb7443 100644 --- a/trullo/trl_card.py +++ b/trullo/trl_card.py @@ -2,9 +2,14 @@ from typing import Dict import attr +from trullo.shortener import Shortener + @attr.s(auto_attribs=True) class TrlCard: id: str - shortcut: str + short_link: str raw_data: Dict + + def get_normalized_name(self): + return Shortener.normalize(self.raw_data['name']) diff --git a/trullo/trl_list.py b/trullo/trl_list.py index 91e0cb8..0a02978 100644 --- a/trullo/trl_list.py +++ b/trullo/trl_list.py @@ -1,11 +1,14 @@ -from typing import List, Dict +from typing import Dict import attr -from trullo.trl_card import TrlCard +from trullo.shortener import Shortener @attr.s(auto_attribs=True) class TrlList: id: str raw_data: Dict + + def get_normalized_name(self) -> str: + return Shortener.normalize(self.raw_data['name']) -- 2.34.2