Change from argparse to pocoo click
This commit is contained in:
parent
37346015a0
commit
70f00be2c8
7 changed files with 83 additions and 124 deletions
|
@ -130,13 +130,13 @@ def __print_blockers(token: str, project_id: int, story_id: int) -> None:
|
||||||
print(f' [{resolved}] {desc}')
|
print(f' [{resolved}] {desc}')
|
||||||
|
|
||||||
|
|
||||||
def _stories_info(args: argparse.Namespace) -> None:
|
def _stories_info(story: str) -> None:
|
||||||
try:
|
try:
|
||||||
token = Config['user']['api_token']
|
token = Config['user']['api_token']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
story_id = base32_crockford.decode(args.story)
|
story_id = base32_crockford.decode(story)
|
||||||
story = api.stories.get(token, story_id)
|
story = api.stories.get(token, story_id)
|
||||||
|
|
||||||
project_id = story['project_id']
|
project_id = story['project_id']
|
||||||
|
|
5
commands/cli.py
Normal file
5
commands/cli.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import click
|
||||||
|
|
||||||
|
@click.group()
|
||||||
|
def cli():
|
||||||
|
pass
|
|
@ -1,16 +1,19 @@
|
||||||
import argparse
|
import click
|
||||||
import getpass
|
|
||||||
|
|
||||||
import api.me
|
import api.me
|
||||||
from config import Config
|
from config import Config
|
||||||
|
from .cli import cli
|
||||||
|
|
||||||
|
|
||||||
def login(arguments: argparse.Namespace) -> None:
|
@cli.command('login')
|
||||||
username = input('E-mail: ')
|
@click.option('--email', prompt=True)
|
||||||
password = getpass.getpass()
|
@click.option('--password', prompt=True, hide_input=True)
|
||||||
|
def login(email: str, password: str) -> None:
|
||||||
|
user = api.me.get(email, password)
|
||||||
|
|
||||||
me = api.me.get(username, password)
|
print()
|
||||||
|
print(f"Logged in successfully as {user['name']} (@{user['username']}).")
|
||||||
|
|
||||||
Config['user']['api_token'] = me['api_token']
|
Config['user']['api_token'] = user['api_token']
|
||||||
Config['user']['initials'] = me['initials']
|
Config['user']['initials'] = user['initials']
|
||||||
Config.write()
|
Config.write()
|
||||||
|
|
|
@ -1,17 +1,25 @@
|
||||||
import argparse
|
|
||||||
import sys
|
import sys
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
import base32_crockford
|
import base32_crockford
|
||||||
|
import click
|
||||||
import tabulate
|
import tabulate
|
||||||
|
|
||||||
import api.projects
|
import api.projects
|
||||||
from config import Config
|
from config import Config
|
||||||
from util import require_login
|
from util import require_login
|
||||||
|
from .cli import cli
|
||||||
|
|
||||||
|
|
||||||
|
@cli.group('projects', invoke_without_command=True)
|
||||||
|
@click.pass_context
|
||||||
@require_login
|
@require_login
|
||||||
def list_projects(arguments: argparse.Namespace) -> None:
|
def projects(context: click.Context) -> None:
|
||||||
|
if context.invoked_subcommand is not None:
|
||||||
|
# click calls this function when a subcommand is
|
||||||
|
# invoked as well. In this case, do nothing.
|
||||||
|
return
|
||||||
|
|
||||||
projects = api.projects.get(Config['user']['api_token'])
|
projects = api.projects.get(Config['user']['api_token'])
|
||||||
projects.sort(key=lambda project: project['name'])
|
projects.sort(key=lambda project: project['name'])
|
||||||
|
|
||||||
|
@ -28,24 +36,36 @@ def list_projects(arguments: argparse.Namespace) -> None:
|
||||||
print(tabulate.tabulate(table, headers=('Code', 'Name', 'Alias')))
|
print(tabulate.tabulate(table, headers=('Code', 'Name', 'Alias')))
|
||||||
|
|
||||||
|
|
||||||
def alias(arguments: argparse.Namespace) -> None:
|
@projects.group('alias')
|
||||||
project_id = base32_crockford.decode(arguments.code)
|
def alias() -> None:
|
||||||
Config['project_aliases'][arguments.alias] = str(project_id)
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@alias.command('add')
|
||||||
|
@click.argument('code')
|
||||||
|
@click.argument('name')
|
||||||
|
def alias_add(code: str, name: str) -> None:
|
||||||
|
project_id = base32_crockford.decode(code)
|
||||||
|
Config['project_aliases'][name] = str(project_id)
|
||||||
Config.write()
|
Config.write()
|
||||||
|
|
||||||
|
|
||||||
def rmalias(arguments: argparse.Namespace) -> None:
|
@alias.command('rm')
|
||||||
del Config['project_aliases'][arguments.alias]
|
@click.argument('name')
|
||||||
|
def alias_rm(name: str) -> None:
|
||||||
|
del Config['project_aliases'][name]
|
||||||
Config.write()
|
Config.write()
|
||||||
|
|
||||||
|
|
||||||
def info(arguments: argparse.Namespace) -> None:
|
@projects.command('info')
|
||||||
|
@click.argument('name')
|
||||||
|
def info(name: str) -> None:
|
||||||
try:
|
try:
|
||||||
token = Config['user']['api_token']
|
token = Config['user']['api_token']
|
||||||
project_id = int(Config['project_aliases'][arguments.alias])
|
project_id = int(Config['project_aliases'][name])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
print(f'unknown alias {arguments.alias}')
|
print(f'unknown alias {name}')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
projects = api.projects.get_project(token, project_id).items()
|
project_info = api.projects.get_project(token, project_id)
|
||||||
print(tabulate.tabulate(projects))
|
print(tabulate.tabulate(project_info.items()))
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import argparse
|
import argparse
|
||||||
|
import click
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from typing import Any, DefaultDict, Dict, List, Sequence, Tuple
|
from typing import Any, DefaultDict, Dict, List, Sequence, Tuple, Optional
|
||||||
|
|
||||||
import base32_crockford
|
import base32_crockford
|
||||||
import tabulate
|
import tabulate
|
||||||
|
@ -13,6 +14,7 @@ from util import require_login
|
||||||
|
|
||||||
from . import COLOR_HEADER, _format_state, _get_persons
|
from . import COLOR_HEADER, _format_state, _get_persons
|
||||||
from ._stories_info import _stories_info
|
from ._stories_info import _stories_info
|
||||||
|
from .cli import cli
|
||||||
|
|
||||||
STATES = 'unstarted', 'planned', 'started', 'finished', 'delivered', 'accepted'
|
STATES = 'unstarted', 'planned', 'started', 'finished', 'delivered', 'accepted'
|
||||||
|
|
||||||
|
@ -126,34 +128,50 @@ def __print_burndown(token: str, iteration: Dict[str, Any], persons: Persons,
|
||||||
print()
|
print()
|
||||||
|
|
||||||
|
|
||||||
def _stories_current(arguments: argparse.Namespace) -> None:
|
def _stories_current(project: str, scope: str, show_accepted: bool) -> None:
|
||||||
try:
|
try:
|
||||||
project_id = int(Config['project_aliases'][arguments.project])
|
project_id = int(Config['project_aliases'][project])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
project_id = base32_crockford.decode(arguments.project)
|
project_id = base32_crockford.decode(project)
|
||||||
|
|
||||||
token = Config['user']['api_token']
|
token = Config['user']['api_token']
|
||||||
|
|
||||||
iterations = api.projects.get_iterations(
|
iterations = api.projects.get_iterations(
|
||||||
token, project_id, scope=arguments.scope)
|
token, project_id, scope=scope)
|
||||||
if not iterations:
|
if not iterations:
|
||||||
print('No current iteration.')
|
print('No current iteration.')
|
||||||
return
|
return
|
||||||
|
iteration = iterations[0]
|
||||||
|
|
||||||
persons = _get_persons(token, project_id=project_id)
|
persons = _get_persons(token, project_id=project_id)
|
||||||
totals: DefaultDict[int, Dict[str, int]] = \
|
totals: DefaultDict[int, Dict[str, int]] = \
|
||||||
defaultdict(lambda: dict((state, 0) for state in STATES))
|
defaultdict(lambda: dict((state, 0) for state in STATES))
|
||||||
|
|
||||||
iteration = iterations[0]
|
|
||||||
|
|
||||||
__print_stories(iteration['stories'], persons, totals)
|
__print_stories(iteration['stories'], persons, totals)
|
||||||
__print_totals(totals, persons)
|
__print_totals(totals, persons)
|
||||||
__print_burndown(token, iteration, persons, arguments.hide_accepted)
|
__print_burndown(token, iteration, persons, not show_accepted)
|
||||||
|
|
||||||
|
|
||||||
|
def _set_story_state(story: str, state: str) -> None:
|
||||||
|
token = Config['user']['api_token']
|
||||||
|
story_id = base32_crockford.decode(story)
|
||||||
|
api.stories.put_story(token, story_id, current_state=state)
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command('stories')
|
||||||
|
@click.argument('project')
|
||||||
|
@click.argument('story', required=False)
|
||||||
|
@click.option('--scope', default='current')
|
||||||
|
@click.option('--show-accepted/--hide-accepted', default=True)
|
||||||
|
@click.option('--set-state', type=click.Choice([
|
||||||
|
'started', 'finished', 'delivered', 'rejected', 'accepted']))
|
||||||
@require_login
|
@require_login
|
||||||
def stories(arguments: argparse.Namespace) -> None:
|
def stories(project: str, story: Optional[str], scope: str,
|
||||||
if arguments.story:
|
show_accepted: bool, set_state: str) -> None:
|
||||||
_stories_info(arguments)
|
if story is not None:
|
||||||
|
if set_state is not None:
|
||||||
|
_set_story_state(story, set_state)
|
||||||
|
else:
|
||||||
|
_stories_info(story)
|
||||||
else:
|
else:
|
||||||
_stories_current(arguments)
|
_stories_current(project, scope, show_accepted)
|
||||||
|
|
|
@ -1,96 +1,8 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import argparse
|
from commands.cli import cli
|
||||||
import commands.login as cmd_login
|
|
||||||
import commands.projects as cmd_projects
|
|
||||||
import commands.stories as cmd_stories
|
|
||||||
import api.stories
|
|
||||||
|
|
||||||
from config import Config
|
from config import Config
|
||||||
from base32_crockford import decode as b32_decode
|
|
||||||
|
|
||||||
|
|
||||||
def start_story(args) -> None:
|
|
||||||
story_set_state(args.story, 'finished')
|
|
||||||
|
|
||||||
|
|
||||||
def finish_story(args) -> None:
|
|
||||||
story_set_state(args.story, 'finished')
|
|
||||||
|
|
||||||
|
|
||||||
def deliver_story(args) -> None:
|
|
||||||
story_set_state(args.story, 'delivered')
|
|
||||||
|
|
||||||
|
|
||||||
def accept_story(args) -> None:
|
|
||||||
story_set_state(args.story, 'accepted')
|
|
||||||
|
|
||||||
|
|
||||||
def story_set_state(args, state: str) -> None:
|
|
||||||
token = Config['user']['api_token']
|
|
||||||
story_id = b32_decode(args.story)
|
|
||||||
api.stories.put_story(token, story_id, current_state=state)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments() -> None:
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.set_defaults(func=lambda _: parser.print_help())
|
|
||||||
commands = parser.add_subparsers(title='commands')
|
|
||||||
|
|
||||||
login_parser = commands.add_parser('login')
|
|
||||||
login_parser.set_defaults(func=cmd_login.login)
|
|
||||||
|
|
||||||
projects_parser = commands.add_parser('projects')
|
|
||||||
projects_parser.set_defaults(func=cmd_projects.list_projects)
|
|
||||||
|
|
||||||
projects_commands = projects_parser.add_subparsers(title='commands')
|
|
||||||
projects_list_parser = projects_commands.add_parser('list')
|
|
||||||
projects_list_parser.set_defaults(func=cmd_projects.list_projects)
|
|
||||||
|
|
||||||
projects_alias_parser = projects_commands.add_parser('alias')
|
|
||||||
projects_alias_parser.add_argument('code', type=str)
|
|
||||||
projects_alias_parser.add_argument('alias', type=str)
|
|
||||||
projects_alias_parser.set_defaults(func=cmd_projects.alias)
|
|
||||||
|
|
||||||
projects_rmalias_parser = projects_commands.add_parser('rmalias')
|
|
||||||
projects_rmalias_parser.add_argument('alias', type=str)
|
|
||||||
projects_rmalias_parser.set_defaults(func=cmd_projects.rmalias)
|
|
||||||
|
|
||||||
projects_info_parser = projects_commands.add_parser('info')
|
|
||||||
projects_info_parser.add_argument('alias', type=str)
|
|
||||||
projects_info_parser.set_defaults(func=cmd_projects.info)
|
|
||||||
|
|
||||||
stories_parser = commands.add_parser('stories', description='story stuff')
|
|
||||||
stories_parser.set_defaults(func=cmd_stories.stories)
|
|
||||||
stories_parser.add_argument('project', type=str)
|
|
||||||
stories_parser.add_argument('story', type=str, nargs='?', default=None)
|
|
||||||
stories_parser.add_argument('--scope', type=str, default='current')
|
|
||||||
stories_parser.add_argument('--hide-accepted', nargs='?', type=bool,
|
|
||||||
const=True, default=False)
|
|
||||||
|
|
||||||
story_start_parser = commands.add_parser('start')
|
|
||||||
story_start_parser.set_defaults(
|
|
||||||
func=lambda args: story_set_state(args, 'started'))
|
|
||||||
story_start_parser.add_argument('story', type=str)
|
|
||||||
|
|
||||||
story_finish_parser = commands.add_parser('finish')
|
|
||||||
story_finish_parser.set_defaults(
|
|
||||||
func=lambda args: story_set_state(args, 'finished'))
|
|
||||||
story_finish_parser.add_argument('story', type=str)
|
|
||||||
|
|
||||||
story_deliver_parser = commands.add_parser('deliver')
|
|
||||||
story_deliver_parser.set_defaults(
|
|
||||||
func=lambda args: story_set_state(args, 'delivered'))
|
|
||||||
story_deliver_parser.add_argument('story', type=str)
|
|
||||||
|
|
||||||
story_accept_parser = commands.add_parser('accept')
|
|
||||||
story_accept_parser.set_defaults(
|
|
||||||
func=lambda args: story_set_state(args, 'accepted'))
|
|
||||||
story_accept_parser.add_argument('story', type=str)
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
args.func(args)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
Config.read()
|
Config.read()
|
||||||
parse_arguments()
|
cli()
|
||||||
|
|
|
@ -35,3 +35,4 @@ urllib3==1.22
|
||||||
urwid==2.0.1
|
urwid==2.0.1
|
||||||
wcwidth==0.1.7
|
wcwidth==0.1.7
|
||||||
wrapt==1.10.11
|
wrapt==1.10.11
|
||||||
|
click=6.7
|
||||||
|
|
Loading…
Reference in a new issue