Skip to content

Commit 44f6af5

Browse files
committed
Updating all timestamp parameters to accept either a datetime or an ISO-8601 date string
1 parent c084c59 commit 44f6af5

5 files changed

Lines changed: 69 additions & 32 deletions

File tree

github3/api.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,10 @@ def iter_repo_issues(owner, repository, milestone=None, state=None,
174174
api-default: created
175175
:param str direction: accepted values: ('asc', 'desc')
176176
api-default: desc
177-
:param str since: ISO 8601 formatted timestamp, e.g.,
178-
2012-05-20T23:10:27Z
177+
:param since: (optional), Only issues after this date will
178+
be returned. This can be a `datetime` or an `ISO8601` formatted
179+
date string, e.g., 2012-05-20T23:10:27Z
180+
:type since: datetime or string
179181
:param int number: (optional), number of issues to return.
180182
Default: -1 returns all issues
181183
:param str etag: (optional), ETag from a previous request to the same

github3/github.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from github3.users import User, Key
2020
from github3.decorators import requires_auth, requires_basic_auth
2121
from github3.notifications import Thread
22+
from github3.utils import timestamp_parameter
2223

2324

2425
class GitHub(GitHubCore):
@@ -493,7 +494,7 @@ def iter_notifications(self, all=False, participating=False, number=-1,
493494

494495
@requires_auth
495496
def iter_org_issues(self, name, filter='', state='', labels='', sort='',
496-
direction='', since='', number=-1, etag=None):
497+
direction='', since=None, number=-1, etag=None):
497498
"""Iterate over the organnization's issues if the authenticated user
498499
belongs to it.
499500
@@ -509,21 +510,24 @@ def iter_org_issues(self, name, filter='', state='', labels='', sort='',
509510
api-default: created
510511
:param str direction: accepted values: ('asc', 'desc')
511512
api-default: desc
512-
:param str since: ISO 8601 formatted timestamp, e.g.,
513-
2012-05-20T23:10:27Z
513+
:param since: (optional), Only issues after this date will
514+
be returned. This can be a `datetime` or an `ISO8601` formatted
515+
date string, e.g., 2012-05-20T23:10:27Z
516+
:type since: datetime or string
514517
:param int number: (optional), number of issues to return. Default:
515518
-1, returns all available issues
516519
:param str etag: (optional), ETag from a previous request to the same
517520
endpoint
518521
:returns: generator of :class:`Issue <github3.issues.Issue>`
519522
"""
520523
url = self._build_url('orgs', name, 'issues')
524+
# issue_params will handle the since parameter
521525
params = issue_params(filter, state, labels, sort, direction, since)
522526
return self._iter(int(number), url, Issue, params, etag)
523527

524528
@requires_auth
525529
def iter_issues(self, filter='', state='', labels='', sort='',
526-
direction='', since='', number=-1, etag=None):
530+
direction='', since=None, number=-1, etag=None):
527531
"""List all of the authenticated user's (and organization's) issues.
528532
529533
:param str filter: accepted values:
@@ -537,21 +541,24 @@ def iter_issues(self, filter='', state='', labels='', sort='',
537541
api-default: created
538542
:param str direction: accepted values: ('asc', 'desc')
539543
api-default: desc
540-
:param str since: ISO 8601 formatted timestamp, e.g.,
541-
2012-05-20T23:10:27Z
544+
:param since: (optional), Only issues after this date will
545+
be returned. This can be a `datetime` or an `ISO8601` formatted
546+
date string, e.g., 2012-05-20T23:10:27Z
547+
:type since: datetime or string
542548
:param int number: (optional), number of issues to return.
543549
Default: -1 returns all issues
544550
:param str etag: (optional), ETag from a previous request to the same
545551
endpoint
546552
:returns: generator of :class:`Issue <github3.issues.Issue>`
547553
"""
548554
url = self._build_url('issues')
555+
# issue_params will handle the since parameter
549556
params = issue_params(filter, state, labels, sort, direction, since)
550557
return self._iter(int(number), url, Issue, params, etag)
551558

552559
@requires_auth
553560
def iter_user_issues(self, filter='', state='', labels='', sort='',
554-
direction='', since='', number=-1, etag=None):
561+
direction='', since=None, number=-1, etag=None):
555562
"""List only the authenticated user's issues. Will not list
556563
organization's issues
557564
@@ -566,15 +573,18 @@ def iter_user_issues(self, filter='', state='', labels='', sort='',
566573
api-default: created
567574
:param str direction: accepted values: ('asc', 'desc')
568575
api-default: desc
569-
:param str since: ISO 8601 formatted timestamp, e.g.,
570-
2012-05-20T23:10:27Z
576+
:param since: (optional), Only issues after this date will
577+
be returned. This can be a `datetime` or an `ISO8601` formatted
578+
date string, e.g., 2012-05-20T23:10:27Z
579+
:type since: datetime or string
571580
:param int number: (optional), number of issues to return.
572581
Default: -1 returns all issues
573582
:param str etag: (optional), ETag from a previous request to the same
574583
endpoint
575584
:returns: generator of :class:`Issue <github3.issues.Issue>`
576585
"""
577586
url = self._build_url('user', 'issues')
587+
# issue_params will handle the since parameter
578588
params = issue_params(filter, state, labels, sort, direction, since)
579589
return self._iter(int(number), url, Issue, params, etag)
580590

@@ -598,8 +608,10 @@ def iter_repo_issues(self, owner, repository, milestone=None,
598608
api-default: created
599609
:param str direction: accepted values: ('asc', 'desc')
600610
api-default: desc
601-
:param str since: ISO 8601 formatted timestamp, e.g.,
602-
2012-05-20T23:10:27Z
611+
:param since: (optional), Only issues after this date will
612+
be returned. This can be a `datetime` or an `ISO8601` formatted
613+
date string, e.g., 2012-05-20T23:10:27Z
614+
:type since: datetime or string
603615
:param int number: (optional), number of issues to return.
604616
Default: -1 returns all issues
605617
:param str etag: (optional), ETag from a previous request to the same

github3/issues/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"""
99

1010
from re import match
11+
from github3.utils import timestamp_parameter
1112
from .issue import Issue
1213

1314
__all__ = [Issue]
@@ -30,7 +31,7 @@ def issue_params(filter, state, labels, sort, direction, since):
3031
if direction in ('asc', 'desc'):
3132
params['direction'] = direction
3233

33-
if since and match('\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$', since):
34-
params['since'] = since
34+
if since:
35+
params['since'] = timestamp_parameter(since)
3536

3637
return params

github3/repos/repo.py

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from github3.repos.stats import ContributorStats
3333
from github3.repos.tag import RepoTag
3434
from github3.users import User, Key
35+
from github3.utils import timestamp_parameter
3536

3637

3738
class Repository(GitHubCore):
@@ -992,16 +993,9 @@ def iter_commits(self, sha=None, path=None, author=None, number=-1,
992993
993994
:returns: generator of :class:`RepoCommit <RepoCommit>`\ s
994995
"""
995-
params = {'sha': sha, 'path': path, 'author': author}
996-
997-
if since is not None:
998-
if isinstance(since, datetime):
999-
since = since.isoformat()
1000-
params['since'] = since
1001-
if until is not None:
1002-
if isinstance(until, datetime):
1003-
until = until.isoformat()
1004-
params['until'] = until
996+
params = {'sha': sha, 'path': path, 'author': author,
997+
'since': timestamp_parameter(since),
998+
'until': timestamp_parameter(until)}
1005999

10061000
self._remove_none(params)
10071001
url = self._build_url('commits', base_url=self._api)
@@ -1127,7 +1121,10 @@ def iter_issues(self,
11271121
'bug,ui,@high' :param sort: accepted values:
11281122
('created', 'updated', 'comments', 'created')
11291123
:param str direction: (optional), accepted values: ('asc', 'desc')
1130-
:param str since: (optional), ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ
1124+
:param since: (optional), Only issues after this date will
1125+
be returned. This can be a `datetime` or an `ISO8601` formatted
1126+
date string, e.g., 2012-05-20T23:10:27Z
1127+
:type since: datetime or string
11311128
:param int number: (optional), Number of issues to return.
11321129
By default all issues are returned
11331130
:param str etag: (optional), ETag from a previous request to the same
@@ -1240,24 +1237,24 @@ def iter_network_events(self, number=-1, etag=None):
12401237
return self._iter(int(number), url, Event, etag)
12411238

12421239
@requires_auth
1243-
def iter_notifications(self, all=False, participating=False, since='',
1240+
def iter_notifications(self, all=False, participating=False, since=None,
12441241
number=-1, etag=None):
12451242
"""Iterates over the notifications for this repository.
12461243
12471244
:param bool all: (optional), show all notifications, including ones
12481245
marked as read
12491246
:param bool participating: (optional), show only the notifications the
12501247
user is participating in directly
1251-
:param str since: (optional), filters out any notifications updated
1252-
before the given time. The time should be passed in as UTC in the
1253-
ISO 8601 format: ``YYYY-MM-DDTHH:MM:SSZ``. Example:
1254-
"2012-10-09T23:39:01Z".
1248+
:param since: (optional), filters out any notifications updated
1249+
before the given time. This can be a `datetime` or an `ISO8601` formatted
1250+
date string, e.g., 2012-05-20T23:10:27Z
1251+
:type since: datetime or string
12551252
:param str etag: (optional), ETag from a previous request to the same
12561253
endpoint
12571254
:returns: generator of :class:`Thread <github3.notifications.Thread>`
12581255
"""
12591256
url = self._build_url('notifications', base_url=self._api)
1260-
params = {'all': all, 'participating': participating, 'since': since}
1257+
params = {'all': all, 'participating': participating, 'since': timestamp_parameter(since)}
12611258
for (k, v) in list(params.items()):
12621259
if not v:
12631260
del params[k]

github3/utils.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from datetime import datetime
2+
import re
3+
4+
# with thanks to https://code.google.com/p/jquery-localtime/issues/detail?id=4
5+
ISO_8601 = re.compile("^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[0-1]|0[1-9]|[1-2][0-9])"
6+
"T(2[0-3]|[0-1][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)?"
7+
"(Z|[+-](?:2[0-3]|[0-1][0-9]):[0-5][0-9])?$")
8+
9+
10+
def timestamp_parameter(timestamp, allow_none=True):
11+
12+
if timestamp is None:
13+
if allow_none:
14+
return None
15+
raise ValueError("Timestamp value cannot be None")
16+
17+
if isinstance(timestamp, datetime):
18+
return timestamp.isoformat()
19+
20+
if isinstance(timestamp, basestring):
21+
if not ISO_8601.match(timestamp):
22+
raise ValueError("Invalid timestamp: %s is not a valid ISO-8601 formatted date" % timestamp)
23+
return timestamp
24+
25+
raise ValueError("Cannot accept type %s for timestamp" % type(timestamp))

0 commit comments

Comments
 (0)