-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support due times #117
Support due times #117
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like this approach because we suppress the need to customize compact_detail
, which is ugly. 👍
todoman/confspec.ini
Outdated
@@ -14,6 +14,13 @@ color = option('always', 'auto', 'never', default='auto') | |||
# this option is not specified the system locale's is used. | |||
date_format = string(default='%x') | |||
|
|||
# The date format used both for displaying times, and parsing input times. | |||
# Default is `%H:%M`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no need to clarify this default due to how the doc is rendered (the one from below will be picked up and shown already).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
todoman/ui.py
Outdated
assert isinstance(date, datetime) | ||
if date.date() in self.special_dates: | ||
rv = self.special_dates[date.date()] | ||
assert type(date) is datetime.date |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't really need this assertion any more due to how we call this function (we've also made it sort of non-public now).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
todoman/ui.py
Outdated
return None | ||
def _format_time(self, time): | ||
if time: | ||
assert isinstance(time, datetime.time) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
todoman/confspec.ini
Outdated
time_format = string(default='%H:%M') | ||
|
||
# The string used to separate date and time when displaying and parsing. | ||
dt_separator = string(default=' ') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a default, I'd prefer to have:
if time_format:
return ' '
else:
return ''
This way, we avoid an extra space when there's no time_format
(I think it's burdensome for users to have to disable the separator when they don't use times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If one of time_format
or date_format
is an empty string, dt_separator
is not used. Hence the filter(bool, ...)
construction.
assert formatter.format_date(any_day) == any_day.strftime(DATE_FORMAT) | ||
assert formatter.format_datetime("") == " " | ||
assert formatter._format_date(today.date()) == " Today" | ||
assert formatter._format_date(tomorrow.date()) == "Tomorrow" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we also have a test for ' Tomorrow 12:00'
?
date_part = None | ||
time_part = None | ||
else: | ||
assert isinstance(dt, datetime.datetime) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we're doing this asserting, can't we do dt.strtime(self.datetime_format)
? Can a datetime
not have a time component?
To deal with special_dates
, we can just substitute 'Tomorrow
' with 'Tomorror' + SEPARATOR + TIME_FORMAT
(at construction time).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using dt.strftime
obliterates the entire special-casing done in #108
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not the way I was thinking it:
self.special_dates = {
self.now.date(): "today".rjust(self.date_width) + self.dt_separator + self.time_format,
Then, in format_datetime
:
if dt.date() in self.special_dates
rv = dt.strftime(self.special_dates[date.date()])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would limit our capability to add special strings for times in the future ("in one hour" comes to mind)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"In one hour" is a datetime format, not a time format. Eg: you'd never see 'Tomorrow in one hour". So this would actually make that simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just noticed that for "in one hour" we'd need an if-else chain, not just a mapping. In either case it's updated now.
@hobarrera I think I made all requested changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There some bits I'm a bit unsure of, but I think it's mostly me getting confused.
todoman/ui.py
Outdated
# Map special dates to the special string we need to return | ||
self.special_datetimes = {} | ||
for key, value in mapping: | ||
if isinstance(value, tuple): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this if
ever false?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. Left-over when I was trying to add "in one hour"
(but as said that would be only implementable as if-else
).
todoman/ui.py
Outdated
if dt in self.special_datetimes: | ||
format_string = self.special_datetimes[dt] | ||
elif dt.date() in self.special_datetimes: | ||
format_string = self.special_datetimes[dt.date()] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this exclude the time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, as you asked me to do, the format strings now include the time as well. E.g. there's a value like "Today %H:%M"
in that dictionary (assuming a particular time_format).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I completely misread this, yes, it makes sense.
I don't think the first bit of the if
is neccessary though, since we never format mere date
s.
todoman/ui.py
Outdated
return self.empty_date | ||
format_string = self.datetime_format | ||
if not dt: | ||
return format_string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be empty string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That'd miss the " "
-padding such that the columns are aligned properly. It is self.special_datetimes[None]
.
todoman/ui.py
Outdated
) | ||
rv = datetime.fromtimestamp(mktime(rv)) | ||
|
||
rv = self._parse_datetime_naive(dt) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can merge these functions now that they'd so much shorter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_parse_datetime_naive
has multiple return paths, those would all have to add the tzinfo. That's the only reason for the split. (BTW the parsing functions didn't change in my recent commits, they've been like that from the beginning)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
re ab7a995: Yeah, that's probably cleaner. |
Great, I just though it was faster to push it than explain it. 😄 |
Ok i think this is ready to merge |
tests/test_formatter.py
Outdated
assert formatter.format_date(tomorrow) == "Tomorrow" | ||
assert formatter.format_date(any_day) == any_day.strftime(DATE_FORMAT) | ||
assert formatter.format_datetime("") == " " | ||
assert "Today" in formatter.format_datetime(today.date()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the version with the string with spaces (eg: " Today"
), because it also checks that we don't break column width.
@@ -39,13 +39,13 @@ def __init__(self, todo, lists, formatter): | |||
|
|||
if todo.due: | |||
# TODO: use proper date_format |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this TODO
is old an obsolete?
Since you don't appear to be on IRC:
|
Yeah, I jump in and out of IRC, TBH. So, does any of the rest of the stack (rfc/icalendar/ |
No, it would all have to be refactored for that. My point is that this code will require more changes with your proposed implementation. |
You're right, this won't work formatting separately, sadly. :( I wonder if we might just as well using something like |
I've also had my eye on maya for some time now, and it might also be capable of doing some parsing (though we really should review it before changing anything). |
Possibly in the future, but that's a lot of code there. I think we should be more conservative about "humanizing" datetimes, preferrably without loss of precision |
Back to this PR though:
|
afc8f76
to
9bd20dd
Compare
I force-pushed the old variant. |
This will be complicated. Right now only datetimes are passed around. |
Sure, let's keep this simple and discuss more improvements in a separate issue. |
I pushed a commit that allows the user to enter |
I meant, "if it has a |
So to be clear, if I set |
My idea was that, basically, when a user sets a time (note: this is really pseuocode, not python), with something like if todo.due:
todo.due.set_time(time):
else:
todo.due = datetime(today, time) Does this seem too unintuitive (I'm biased because it's my idea)? |
In the CLI module |
Okay then, I won't distract any more, and let's aim to keep this simple. ^_^ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a changelog entry, otherwise, LGTM 🚀
I added a bit of validation to the config parsing code, please review again. |
todoman/configuration.py
Outdated
@@ -83,4 +83,18 @@ def load_config(): | |||
'Bad {} setting, {}'.format(key, error.args[0]) | |||
) | |||
|
|||
date_format = config['main']['date_format'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather see new validators that include this in this block (eg: like validate_colour
and validate_cache_path
.
Mostly for separation of concerns, and to avoid this function growing too much.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
I pushed the changes I was suggesting for the validation. |
Oops, sorry I didn't notice that there are already ConfigObj validators, or that ConfigObj even had that capability. |
LGTM, but since I pushed the last change, I'll also wait for you thumbs-up. |
I would but I cannot approve my own PR |
Feel free to merge 🚀 |
Travis triggers a |
b21183c
to
9022732
Compare
I squash-pushed this, travis should stop being dumb (I think it got confused when I pushed to |
Fix #109
dt_separator is necessary because of parsing due dates