From 18508fd5493011bbdf0d19664ab63a61a0dc036d Mon Sep 17 00:00:00 2001 From: Sijmen Schoon Date: Tue, 5 Feb 2019 14:29:33 +0100 Subject: [PATCH] Code cleanups --- api/projects.py | 9 ++++--- commands/__init__.py | 18 +++++++------- commands/_stories_info.py | 4 +-- commands/projects.py | 2 +- commands/stories.py | 52 +++++++++++++++++---------------------- 5 files changed, 40 insertions(+), 45 deletions(-) diff --git a/api/projects.py b/api/projects.py index 37de08b..92c1c64 100644 --- a/api/projects.py +++ b/api/projects.py @@ -44,10 +44,11 @@ def get_story_transitions(token: str, project_id: int, after: Optional[datetime] = None, before: Optional[datetime] = None) \ -> List[Dict[str, Any]]: - parameters = { - 'occurred_after': after.isoformat() if after else None, - 'occurred_before': before.isoformat() if before else None, - } + parameters = {} + if after: + parameters['occurred_after'] = after.isoformat() + if before: + parameters['occurred_before'] = before.isoformat() r = requests.get( f'https://www.pivotaltracker.com/services/v5/projects/{project_id}' diff --git a/commands/__init__.py b/commands/__init__.py index 965cac3..57bb165 100644 --- a/commands/__init__.py +++ b/commands/__init__.py @@ -1,5 +1,5 @@ import api.projects -from typing import Dict, Any +from typing import Dict, Any, Optional from color import Color COLOR_TITLE = Color(Color.YELLOW) @@ -14,15 +14,15 @@ COLOR_ACCEPTED = Color(Color.BRIGHT_GREEN) COLOR_REJECTED = Color(Color.BRIGHT_RED) -def _format_state(state: str) -> str: +def _format_state(state: str, header: Optional[bool] = False) -> str: STATES = { - 'accepted': COLOR_ACCEPTED.format('accepted'), - 'rejected': COLOR_REJECTED.format('rejected'), - 'delivered': COLOR_DELIVERED.format('delivered'), - 'finished': COLOR_FINISHED.format('finished'), - 'started': COLOR_STARTED.format('started'), - 'planned': COLOR_PLANNED.format('planned'), - 'unstarted': COLOR_PLANNED.format('unstarted'), + 'accepted': COLOR_ACCEPTED.format('Acc' if header else 'accepted'), + 'rejected': COLOR_REJECTED.format('Rej' if header else 'rejected'), + 'delivered': COLOR_DELIVERED.format('Del' if header else 'delivered'), + 'finished': COLOR_FINISHED.format('Fin' if header else 'finished'), + 'started': COLOR_STARTED.format('Sta' if header else 'started'), + 'planned': COLOR_PLANNED.format('Pln' if header else 'planned'), + 'unstarted': COLOR_PLANNED.format('Uns' if header else 'unstarted'), } return STATES[state] diff --git a/commands/_stories_info.py b/commands/_stories_info.py index 4d77268..0c4f2e9 100644 --- a/commands/_stories_info.py +++ b/commands/_stories_info.py @@ -133,13 +133,13 @@ def __print_blockers(token: str, project_id: int, story_id: int) -> None: print(f' [{resolved}] {desc}') -def stories_info(story: str) -> None: +def stories_info(story_b32: str) -> None: try: token = Config['user']['api_token'] except KeyError: sys.exit(1) - story_id = base32.decode(story) + story_id = base32.decode(story_b32) story = api.stories.get(token, story_id) project_id = story['project_id'] diff --git a/commands/projects.py b/commands/projects.py index e66a340..1a1f54e 100644 --- a/commands/projects.py +++ b/commands/projects.py @@ -30,7 +30,7 @@ def projects(context: click.Context) -> None: table = [] for project in sorted(projects_, key=lambda project_: project_['name']): code = base32.encode(project['id']) - alias_ = aliases.get(project['id']) + alias_ = aliases.get(project['id'], '') table.append((code, project['name'], alias_)) print(tabulate.tabulate(table, headers=('Code', 'Name', 'Alias'))) diff --git a/commands/stories.py b/commands/stories.py index 3c2bffe..1bc454e 100644 --- a/commands/stories.py +++ b/commands/stories.py @@ -13,8 +13,8 @@ from config import Config from util import require_login from . import COLOR_HEADER, COLOR_PLANNED, COLOR_STARTED, COLOR_FINISHED, \ - COLOR_DELIVERED, COLOR_ACCEPTED, COLOR_REJECTED, _format_state, \ - _get_persons + COLOR_DELIVERED, COLOR_ACCEPTED, COLOR_REJECTED, _format_state, \ + _get_persons from ._stories_info import stories_info from .cli import cli @@ -26,8 +26,8 @@ Persons = Dict[int, Dict[str, Any]] Totals = DefaultDict[int, Dict[str, int]] -def __ceil(value: float) -> int: - return int(math.ceil(value)) +def __burndown(color, letter, points): + return color.format(letter * int(math.ceil(points))) def __get_row(item: Tuple[int, Dict[str, int]], persons: Persons, @@ -37,17 +37,17 @@ def __get_row(item: Tuple[int, Dict[str, int]], persons: Persons, estimates = [points[state] for state in STATES] - progress = '[' + \ - COLOR_PLANNED.format('P' * __ceil(points['planned'])) + \ - COLOR_REJECTED.format('R' * __ceil(points['rejected'])) + \ - COLOR_STARTED.format('S' * __ceil(points['started'])) + \ - COLOR_FINISHED.format('F' * __ceil(points['finished'])) + \ - COLOR_DELIVERED.format('D' * __ceil(points['delivered'])) - + progress = '[' if show_accepted: - progress += COLOR_ACCEPTED.format('A' * __ceil(points['accepted'])) + progress += __burndown(COLOR_ACCEPTED, 'A', points['accepted']) - progress += ']' + progress += \ + __burndown(COLOR_DELIVERED, 'D', points['delivered']) + \ + __burndown(COLOR_FINISHED, 'F', points['finished']) + \ + __burndown(COLOR_STARTED, 'S', points['started']) + \ + __burndown(COLOR_REJECTED, 'R', points['rejected']) + \ + __burndown(COLOR_PLANNED, 'P', points['planned']) + \ + ']' return name, (*estimates), sum(estimates), progress @@ -96,7 +96,7 @@ def __print_totals(totals: Totals, persons: Persons, show_accepted: bool) \ -> None: COLOR_HEADER.print('Point totals:', end='\n\n') - state_headers = [_format_state(state) for state in STATES] + state_headers = [_format_state(state, header=True) for state in STATES] headers = ('Owner', *state_headers, 'Total', 'Progress') data = sorted((__get_row(item, persons, show_accepted) @@ -128,15 +128,15 @@ def __print_burndown(token: str, iteration: Dict[str, Any], continue progress = '' - if show_accepted: - progress += '\033[92m' + 'A' * round(counts[0] - accepted_points) - - progress += '\033[38;5;208m' + 'D' * round(counts[1]) - progress += '\033[94m' + 'F' * round(counts[2]) - progress += '\033[38;5;226m' + 'S' * round(counts[3]) - progress += '\033[90m' + 'P' * round(counts[5]) - progress += '\033[0m' + progress += __burndown(COLOR_ACCEPTED, 'A', + counts[0] - accepted_points) + progress += \ + __burndown(COLOR_DELIVERED, 'D', counts[1]) + \ + __burndown(COLOR_FINISHED, 'F', counts[2]) + \ + __burndown(COLOR_STARTED, 'S', counts[3]) + \ + __burndown(COLOR_PLANNED, 'P', counts[5]) + \ + __burndown(COLOR_PLANNED, 'U', counts[6]) print(f'{date}: {progress}') @@ -174,14 +174,8 @@ def _set_story_state(story: str, state: str) -> None: api.stories.put_story(token, story_id, current_state=state) -def _complete_projects(ctx: click.Context, args: List[str], incomplete: str) \ - -> List[str]: - return [alias for alias in Config['project_aliases'] - if alias.startswith(incomplete)] - @cli.command('stories') -@click.argument( - 'project', type=click.STRING, autocompletion=_complete_projects) +@click.argument('project', type=click.STRING) @click.argument('story', required=False) @click.argument('action', required=False) @click.option('--scope', default='current')