Skip to content

Commit

Permalink
Introduce options to configure the ordering of the projects and tags …
Browse files Browse the repository at this point in the history
…commands
  • Loading branch information
bendardenne committed Apr 13, 2020
1 parent d28a2bd commit 6950ae7
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 29 deletions.
30 changes: 22 additions & 8 deletions tests/test_watson.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,35 +681,49 @@ def json(self):
# projects

def test_projects(watson):
i = 0
for name in ('foo', 'bar', 'bar', 'bar', 'foo', 'lol'):
watson.frames.add(name, 4000, 4000)
watson.frames.add(name, 4000 + i, 4000 + i)
i += 1

assert watson.projects == ['bar', 'foo', 'lol']
watson.frames.add("oldest", 2000, 2005)
watson.frames.add("recent", 5000, 5005)

assert watson.projects() == ['bar', 'foo', 'lol', 'oldest', 'recent']
assert (watson.projects(orderby='start')
== ['oldest', 'bar', 'foo', 'lol', 'recent'])
assert (watson.projects(orderby='start', descending=True)
== ['recent', 'lol', 'foo', 'bar', 'oldest'])


def test_projects_no_frames(watson):
assert watson.projects == []
assert watson.projects() == []


# tags

def test_tags(watson):
samples = (
samples = [
('foo', ('A', 'D')),
('bar', ('A', 'C')),
('foo', ('B', 'C')),
('lol', ()),
('bar', ('C'))
)
]

i = 0
for name, tags in samples:
watson.frames.add(name, 4000, 4000, tags)
watson.frames.add(name, 4000 + i, 4000 + i, tags)
i += 1

assert watson.tags == ['A', 'B', 'C', 'D']
assert watson.tags() == ['A', 'B', 'C', 'D']
assert watson.tags(orderby='start') == ['D', 'A', 'B', 'C']
assert (watson.tags(orderby='start', descending=True)
== ['C', 'B', 'A', 'D'])


def test_tags_no_frames(watson):
assert watson.tags == []
assert watson.tags() == []


# merge
Expand Down
4 changes: 2 additions & 2 deletions watson/autocompletion.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def prepend_plus(tag_suggestions):
def get_projects(ctx, args, incomplete):
"""Function to return all projects matching the prefix."""
watson = _bypass_click_bug_to_ensure_watson(ctx)
for cur_project in watson.projects:
for cur_project in watson.projects():
if cur_project.startswith(incomplete):
yield cur_project

Expand Down Expand Up @@ -98,7 +98,7 @@ def get_rename_types(ctx, args, incomplete):
def get_tags(ctx, args, incomplete):
"""Function to return all tags matching the prefix."""
watson = _bypass_click_bug_to_ensure_watson(ctx)
for cur_tag in watson.tags:
for cur_tag in watson.tags():
if cur_tag.startswith(incomplete):
yield cur_tag

Expand Down
50 changes: 41 additions & 9 deletions watson/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,15 @@ def start(ctx, watson, confirm_new_project, confirm_new_tag, args, gap_=True):
# Confirm creation of new project if that option is set
if (watson.config.getboolean('options', 'confirm_new_project') or
confirm_new_project):
confirm_project(project, watson.projects)
confirm_project(project, watson.projects())

# Parse all the tags
tags = parse_tags(args)

# Confirm creation of new tag(s) if that option is set
if (watson.config.getboolean('options', 'confirm_new_tag') or
confirm_new_tag):
confirm_tags(tags, watson.tags)
confirm_tags(tags, watson.tags())

if project and watson.is_started and not gap_:
current = watson.current
Expand Down Expand Up @@ -1060,9 +1060,13 @@ def _final_print(lines):


@cli.command()
@click.option('-b', '--by', 'orderby', default='name',
help="Sort the ouput by either 'name' or 'time'")
@click.option('-r', '--reverse', 'descending', default=False, is_flag=True,
help="Reverse the output (sort by descending order)")
@click.pass_obj
@catch_watson_error
def projects(watson):
def projects(watson, orderby, descending):
"""
Display the list of all the existing projects.
Expand All @@ -1075,14 +1079,30 @@ def projects(watson):
voyager1
voyager2
"""
for project in watson.projects:
if orderby == 'name':
orderby = 'project'
elif orderby == 'time':
orderby = 'start'
else:
raise click.ClickException(style(
'error',
u'--by option can be either "name" or "time". '
u'You supplied "%s"' % orderby
))

projects = watson.projects(orderby=orderby, descending=descending)
for project in projects:
click.echo(style('project', project))


@cli.command()
@click.option('-b', '--by', 'orderby', default='name',
help="Sort the ouput by either 'name' or 'time'")
@click.option('-r', '--reverse', 'descending', default=False, is_flag=True,
help="Reverse the output (sort by descending order)")
@click.pass_obj
@catch_watson_error
def tags(watson):
def tags(watson, orderby, descending):
"""
Display the list of all the tags.
Expand All @@ -1103,7 +1123,19 @@ def tags(watson):
transmission
wheels
"""
for tag in watson.tags:
if orderby == 'name':
orderby = 'project'
elif orderby == 'time':
orderby = 'start'
else:
raise click.ClickException(style(
'error',
u'--by option can be either "name" or "time". '
u'You supplied "%s"' % orderby
))

tags = watson.tags(orderby=orderby, descending=descending)
for tag in tags:
click.echo(style('tag', tag))


Expand Down Expand Up @@ -1160,15 +1192,15 @@ def add(watson, args, from_, to, confirm_new_project, confirm_new_tag):
# Confirm creation of new project if that option is set
if (watson.config.getboolean('options', 'confirm_new_project') or
confirm_new_project):
confirm_project(project, watson.projects)
confirm_project(project, watson.projects())

# Parse all the tags
tags = parse_tags(args)

# Confirm creation of new tag(s) if that option is set
if (watson.config.getboolean('options', 'confirm_new_tag') or
confirm_new_tag):
confirm_tags(tags, watson.tags)
confirm_tags(tags, watson.tags())

# add a new frame, call watson save to update state files
frame = watson.add(project=project, tags=tags, from_date=from_, to_date=to)
Expand Down Expand Up @@ -1260,7 +1292,7 @@ def edit(watson, confirm_new_project, confirm_new_tag, id):
# Confirm creation of new tag(s) if that option is set
if (watson.config.getboolean('options', 'confirm_new_tag') or
confirm_new_tag):
confirm_tags(tags, watson.tags)
confirm_tags(tags, watson.tags())
start = arrow.get(data['start'], datetime_format).replace(
tzinfo=local_tz).to('utc')
stop = arrow.get(data['stop'], datetime_format).replace(
Expand Down
53 changes: 43 additions & 10 deletions watson/watson.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-

from collections import OrderedDict
import datetime
from functools import reduce
import json
Expand Down Expand Up @@ -303,19 +304,51 @@ def cancel(self):
self.current = None
return old_current

@property
def projects(self):
def projects(self, orderby="project", descending=False):
"""
Return the list of all the existing projects, sorted by name.
Return the list of all the existing projects.
"""
return sorted(set(self.frames['project']))

@property
def tags(self):
ordered_frames = sorted(self.frames, key=operator.attrgetter(orderby))
ordered_projects = list(map(operator.attrgetter("project"),
ordered_frames))

# Keep latest occurence only, so we feed a reversed list
# to the ordered set.
ordered_projects.reverse()

# Use OrderedDict as a set to remove duplicates by keep order.
result = list(OrderedDict.fromkeys(ordered_projects))

if not descending:
result.reverse()

return result

def tags(self, orderby="tag", descending=False):
"""
Return the list of the tags, sorted by name.
Return the list of the tags.
"""
return sorted(set(tag for tags in self.frames['tags'] for tag in tags))
if orderby == "tag":
tags = [tag for tags in self.frames['tags'] for tag in tags]
return sorted(set(tags))
else:
ordered_frames = sorted(self.frames,
key=operator.attrgetter(orderby))
ordered_tags = map(operator.attrgetter("tags"), ordered_frames)
flat_tags = [tag for tags in ordered_tags for tag in tags]

# Keep latest occurence only, so we feed a reversed list
# to the ordered set.
flat_tags.reverse()

result = list(OrderedDict.fromkeys(flat_tags))

if not descending:
result.reverse()

# Use OrderedDict as a set to remove duplicates keep order.
return result

def _get_request_info(self, route):
config = self.config
Expand Down Expand Up @@ -542,7 +575,7 @@ def report(self, from_, to, current=None, projects=None, tags=None,

def rename_project(self, old_project, new_project):
"""Rename a project in all affected frames."""
if old_project not in self.projects:
if old_project not in self.projects():
raise WatsonError(u'Project "%s" does not exist' % old_project)

updated_at = arrow.utcnow()
Expand All @@ -559,7 +592,7 @@ def rename_project(self, old_project, new_project):

def rename_tag(self, old_tag, new_tag):
"""Rename a tag in all affected frames."""
if old_tag not in self.tags:
if old_tag not in self.tags():
raise WatsonError(u'Tag "%s" does not exist' % old_tag)

updated_at = arrow.utcnow()
Expand Down

0 comments on commit 6950ae7

Please sign in to comment.