Skip to content

Commit 7dd9b7b

Browse files
committed
feat: --since= on the command line, and since=DATE. #26
1 parent d1e96a0 commit 7dd9b7b

File tree

8 files changed

+72
-17
lines changed

8 files changed

+72
-17
lines changed

README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ clause sets defaults for the digest options in the rest of the file. Each
114114
units of weeks, days, hours, minutes and seconds, and can also be
115115
abbreviated, like ``1d6h``. Using ``since: forever`` will include all
116116
activity regardless of when it happened. If ``since`` is omitted, it
117-
defaults to one week.
117+
defaults to one week. You can specify ``--since=<SINCE>`` on the dinghy
118+
command line to provide an explicit value.
118119

119120
- The ``items`` setting is a list of things to report on, specified in a few
120121
different ways:

dev-requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
black
33
build
44
check-manifest
5+
freezegun
56
pylint
67
pytest
78
readme_renderer

scriv.d/20230730_211636_nedbat.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Added
2+
.....
3+
4+
- The ``since`` date can now be specified on the command line with ``--since``.
5+
This will override any specification in the YAML file.
6+
7+
- The ``since`` value can be specified as a specific ISO 8601 date,
8+
implementing part of `issue 26`_.
9+
10+
.. _issue 26: https://github.com/nedbat/dinghy/issues/26

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ package_dir =
3636
install_requires =
3737
aiofiles>=0.8
3838
aiohttp>3
39+
backports-datetime-fromisoformat
3940
click>8
4041
click-log>0.3
4142
emoji

src/dinghy/cli.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@ def main_run(coro):
4242
@click.command()
4343
@click_log.simple_verbosity_option(logger)
4444
@click.version_option()
45+
@click.option("--since", metavar="DELTA-OR-DATE", help="Specify a since date.")
4546
@click.argument("_input", metavar="[INPUT]", default="dinghy.yaml")
4647
@click.argument("digests", metavar="[DIGEST ...]", nargs=-1)
47-
def cli(_input, digests):
48+
def cli(since, _input, digests):
4849
"""
4950
Generate HTML digests of GitHub activity.
5051
@@ -58,6 +59,6 @@ def cli(_input, digests):
5859
if "://" in _input:
5960
coro = make_digest([_input])
6061
else:
61-
coro = make_digests_from_config(_input, digests or None)
62+
coro = make_digests_from_config(_input, digests or None, since=since)
6263

6364
main_run(coro)

src/dinghy/digest.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
from . import __version__
1818
from .graphql_helpers import build_query, GraphqlHelper
19-
from .helpers import DinghyError, json_save, parse_timedelta
19+
from .helpers import DinghyError, json_save, parse_since
2020
from .jinja_helpers import render_jinja_to_file
2121

2222

@@ -506,12 +506,8 @@ async def make_digest(items, since="1 week", digest="digest.html", **options):
506506
digest (str): the HTML file name to write.
507507
508508
"""
509-
if since == "forever":
510-
show_date = False
511-
since_date = datetime.datetime(year=1980, month=1, day=1)
512-
else:
513-
show_date = True
514-
since_date = datetime.datetime.now() - parse_timedelta(since)
509+
show_date = since != "forever"
510+
since_date = parse_since(since)
515511
digester = Digester(since=since_date, options=options)
516512

517513
coros = []
@@ -544,13 +540,14 @@ async def make_digest(items, since="1 week", digest="digest.html", **options):
544540
logger.info(f"Wrote digest: {digest}")
545541

546542

547-
async def make_digests_from_config(conf_file, digests=None):
543+
async def make_digests_from_config(conf_file, digests=None, since=None):
548544
"""
549545
Make all the digests specified by a configuration file.
550546
551547
Args:
552548
conf_file (str): a file path to read as a config file.
553-
549+
digests (list of str): the digest names to make.
550+
since (str): the spec for since when.
554551
"""
555552
try:
556553
with open(conf_file, encoding="utf-8") as cf:
@@ -567,6 +564,8 @@ async def make_digests_from_config(conf_file, digests=None):
567564
args = {**defaults, **spec}
568565
if digests is not None and args["digest"] not in digests:
569566
continue
567+
if since is not None:
568+
args["since"] = since
570569
coros.append(make_digest(**args))
571570
await asyncio.gather(*coros)
572571

src/dinghy/helpers.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
import re
88

99
import aiofiles
10+
from backports.datetime_fromisoformat import MonkeyPatch
11+
12+
MonkeyPatch.patch_fromisoformat()
1013

1114

1215
class DinghyError(Exception):
@@ -29,7 +32,7 @@ def parse_timedelta(timedelta_str):
2932
timedelta_str (str): A string identifying a duration, like "2h13m".
3033
3134
Returns:
32-
A datetime.timedelta object.
35+
A datetime.timedelta object, or None if it can't be parsed.
3336
3437
"""
3538
parts = re.match(
@@ -45,11 +48,34 @@ def parse_timedelta(timedelta_str):
4548
timedelta_str.replace(" ", ""),
4649
)
4750
if not timedelta_str or parts is None:
48-
raise ValueError(f"Couldn't parse time delta from {timedelta_str!r}")
51+
return None
4952
kwargs = {name: float(val) for name, val in parts.groupdict().items() if val}
5053
return datetime.timedelta(**kwargs)
5154

5255

56+
def parse_since(since):
57+
"""
58+
Parse a since specification:
59+
60+
- "forever" uses a long-ago date.
61+
- A time delta (like "1 week") computes that long ago.
62+
- A specific time (like "2023-07-30") is used as-is.
63+
64+
"""
65+
if since == "forever":
66+
since_date = datetime.datetime(year=1980, month=1, day=1)
67+
else:
68+
delta = parse_timedelta(since)
69+
if delta is not None:
70+
since_date = datetime.datetime.now() - delta
71+
else:
72+
try:
73+
since_date = datetime.datetime.fromisoformat(since)
74+
except ValueError:
75+
raise DinghyError("Can't parse since: {since!r}") from None
76+
return since_date
77+
78+
5379
def find_dict_with_key(d, key):
5480
"""Return the subdict of `d` that has `key`."""
5581
if key in d:

tests/test_helpers.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44

55
import datetime
66

7+
import freezegun
78
import pytest
89

9-
from dinghy.helpers import find_dict_with_key, parse_timedelta
10+
from dinghy.helpers import find_dict_with_key, parse_since, parse_timedelta
1011

1112

1213
@pytest.mark.parametrize(
@@ -37,8 +38,23 @@ def test_parse_timedelta(tds, kwargs):
3738
],
3839
)
3940
def test_bad_parse_timedelta(tds):
40-
with pytest.raises(ValueError, match=f"Couldn't parse time delta from {tds!r}"):
41-
parse_timedelta(tds)
41+
assert parse_timedelta(tds) is None
42+
43+
44+
@freezegun.freeze_time("2023-06-16")
45+
@pytest.mark.parametrize(
46+
"since, dtargs",
47+
[
48+
("20230730", (2023, 7, 30)),
49+
("2023-06-16T12:34:56", (2023, 6, 16, 12, 34, 56)),
50+
("forever", (1980, 1, 1)),
51+
("1day", (2023, 6, 15)),
52+
("2 weeks", (2023, 6, 2)),
53+
("1 week 1 day", (2023, 6, 8)),
54+
],
55+
)
56+
def test_parse_since(since, dtargs):
57+
assert parse_since(since) == datetime.datetime(*dtargs)
4258

4359

4460
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)