M trullo.py => trullo.py +61 -8
@@ 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['<api_path>']
@@ 109,8 110,18 @@ if __name__ == '__main__':
if args['b']:
boards = tclient.get_boards()
if args['<board_shortcut>']:
- board = [board for board in boards
- if board.shortcut.lower().startswith(args['<board_shortcut>'])][0]
+ board_shortcut = args['<board_shortcut>']
+ 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_shortcut>']
- 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_shortcut>']
- 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_shortcut>']
- 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)
M trullo/printer.py => trullo/printer.py +35 -13
@@ 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()
M trullo/shortener.py => trullo/shortener.py +21 -9
@@ 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
M trullo/tclient.py => trullo/tclient.py +16 -7
@@ 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)
M trullo/trl_board.py => trullo/trl_board.py +5 -1
@@ 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'])
M trullo/trl_card.py => trullo/trl_card.py +6 -1
@@ 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'])
M trullo/trl_list.py => trullo/trl_list.py +5 -2
@@ 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'])