Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9372df4

Browse files
committed
Merge branch 'notifications' into mock
Conflicts:github3/github.py
2 parentscb3a89d +b6c86c1 commit9372df4

File tree

14 files changed

+619
-9
lines changed

14 files changed

+619
-9
lines changed

‎github3/github.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
fromgithub3.reposimportRepository
1919
fromgithub3.usersimportUser,Key
2020
fromgithub3.decoratorsimportrequires_auth,requires_basic_auth
21+
fromgithub3.notificationsimportThread
2122

2223

2324
classGitHub(GitHubCore):
@@ -421,6 +422,26 @@ def iter_gists(self, username=None, number=-1):
421422
url=self._build_url('gists')
422423
returnself._iter(int(number),url,Gist)
423424

425+
@requires_auth
426+
defiter_notifications(self,all=False,participating=False,number=-1):
427+
"""Iterate over the user's notification.
428+
429+
:param bool all: (optional), iterate over all notifications
430+
:param bool participating: (optional), only iterate over notifications
431+
in which the user is participating
432+
:param int number: (optional), how many notifications to return
433+
:returns: generator of
434+
:class:`Thread <github3.notifications.Thread>`
435+
"""
436+
params=None
437+
ifall:
438+
params= {'all':all}
439+
elifparticipating:
440+
params= {'participating':participating}
441+
442+
url=self._build_url('notifications')
443+
returnself._iter(int(number),url,Thread,params)
444+
424445
@requires_auth
425446
defiter_org_issues(self,name,filter='',state='',labels='',sort='',
426447
direction='',since='',number=-1):

‎github3/models.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
fromrequestsimportsession
1212
fromreimportcompile
1313
fromgithub3.decoratorsimportrequires_auth
14+
fromgithub3.packages.PySO8601importparse
1415

1516
try:# (No coverage)
1617
# Python 2.x
@@ -36,10 +37,7 @@ def to_json(self):
3637

3738
def_strptime(self,time_str):
3839
"""Converts an ISO 8601 formatted string into a datetime object."""
39-
iftime_str:
40-
returndatetime.strptime(time_str,'%Y-%m-%dT%H:%M:%SZ')
41-
else:
42-
returnNone
40+
returnparse(time_str)iftime_strelseNone
4341

4442
@classmethod
4543
deffrom_json(cls,json):

‎github3/notifications.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
"""
2+
github3.notifications
3+
=====================
4+
5+
This module contains the classes relating to notifications.
6+
7+
"""
8+
9+
fromjsonimportdumps
10+
fromgithub3.modelsimportGitHubCore
11+
12+
13+
classThread(GitHubCore):
14+
def__init__(self,notif,session=None):
15+
super(Thread,self).__init__(notif,session)
16+
self._api=notif.get('url')
17+
#: Comment responsible for the notification
18+
self.comment=notif.get('comment', {})
19+
#: Thread information
20+
self.thread=notif.get('thread', {})
21+
22+
fromgithub3.reposimportRepository
23+
#: Repository the comment was made on
24+
self.repository=Repository(notif.get('repository', {}),self)
25+
#: When the thread was last updated
26+
self.updated_at=self._strptime(notif.get('updated_at'))
27+
#: Id of the thread
28+
self.id=notif.get('id')
29+
#: Dictionary of urls for the thread
30+
self.urls=notif.get('urls')
31+
#: datetime object representing the last time the user read the thread
32+
self.last_read_at=notif.get('last_read_at')
33+
ifself.last_read_at:
34+
self.last_read_at=self._strptime(self.last_read_at)
35+
#: The reason you're receiving the notification
36+
self.reason=notif.get('reason')
37+
#: Subject of the Notification, e.g., which issue/pull/diff is this in
38+
#: relation to. This is a dictionary
39+
self.subject=notif.get('subject')
40+
self._unread=notif.get('unread')
41+
42+
def__repr__(self):
43+
return'<Thread [{0}]>'.format(self.subject.get('title'))
44+
45+
defdelete_subscription(self):
46+
"""Delete subscription for this thread.
47+
48+
:returns: bool
49+
"""
50+
url=self._build_url('subscription',base_url=self._api)
51+
returnself._boolean(self._delete(url),204,404)
52+
53+
defis_unread(self):
54+
"""Tells you if the thread is unread or not."""
55+
returnself._unread
56+
57+
defmark(self):
58+
"""Mark the thread as read.
59+
60+
:returns: bool
61+
"""
62+
mark= {'read':True}
63+
returnself._boolean(self._patch(self._api,data=dumps(mark)),205,
64+
404)
65+
66+
defset_subscription(self,subscribed,ignored):
67+
"""Set the user's subscription for this thread
68+
69+
:param bool subscribed: (required), determines if notifications should
70+
be received from this thread.
71+
:param bool ignored: (required), determines if notifications should be
72+
ignored from this thread.
73+
:returns: :class;`Subscription <Subscription>`
74+
"""
75+
url=self._build_url('subscription',base_url=self._api)
76+
sub=dumps({'subscribed':subscribed,'ignored':ignored})
77+
json=self._json(self._put(url,data=sub),200)
78+
returnSubscription(json,self)ifjsonelseNone
79+
80+
defsubscription(self):
81+
"""Checks the status of the user's subscription to this thread.
82+
83+
:returns: :class:`Subscription <Subscription>`
84+
"""
85+
url=self._build_url('subscription',base_url=self._api)
86+
json=self._json(self._get(url),200)
87+
returnSubscription(json,self)ifjsonelseNone
88+
89+
90+
classSubscription(GitHubCore):
91+
def__init__(self,sub,session=None):
92+
super(Subscription,self).__init__(sub,session)
93+
self._api=sub.get('url')
94+
#: reason user is subscribed to this thread/repository
95+
self.reason=sub.get('reason')
96+
#: datetime representation of when the subscription was created
97+
self.created_at=self._strptime(sub.get('created_at'))
98+
#: API url of the thread if it exists
99+
self.thread_url=sub.get('thread_url')
100+
#: API url of the repository if it exists
101+
self.repository_url=sub.get('repository_url')
102+
self._ignored=sub.get('ignored',False)
103+
self._subscribed=sub.get('subscribed',False)
104+
105+
def__repr__(self):
106+
return'<Subscription [{0}]>'.format(self._subscribed)
107+
108+
defdelete(self):
109+
returnself._boolean(self._delete(self._api),204,404)
110+
111+
defis_ignored(self):
112+
returnself._ignored
113+
114+
defis_subscribed(self):
115+
returnself._subscribed
116+
117+
defset(self,subscribed,ignored):
118+
"""Set the user's subscription for this subscription
119+
120+
:param bool subscribed: (required), determines if notifications should
121+
be received from this thread.
122+
:param bool ignored: (required), determines if notifications should be
123+
ignored from this thread.
124+
"""
125+
sub=dumps({'subscribed':subscribed,'ignored':ignored})
126+
json=self._json(self._put(self._api,data=sub),200)
127+
self.__init__(json,self._session)

‎github3/packages/PySO8601/__init__.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from .utilityimportParseError
2+
from .datetimestampsimportparse_date,parse_time
3+
from .durationsimportparse_duration
4+
from .intervalsimportparse_interval
5+
from .timezonesimportTimezone
6+
from .__version__import__version__
7+
8+
__all__= ['parse',
9+
'parse_date',
10+
'parse_time',
11+
'parse_duration',
12+
'parse_interval',
13+
'Timezone',
14+
'ParseError',
15+
'__version__']
16+
17+
18+
defparse(representation):
19+
"""Attempts to parse an ISO8601 formatted ``representation`` string,
20+
which could be of any valid ISO8601 format (date, time, duration,
21+
interval).
22+
23+
Return value is specific to ``representation``.
24+
"""
25+
representation=str(representation).upper().strip()
26+
27+
if'/'inrepresentation:
28+
returnparse_interval(representation)
29+
30+
ifrepresentation[0]is'P':
31+
returnparse_duration(representation)
32+
33+
returnparse_date(representation)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
__author__='Phillip B Oldham'
2+
__author_email__='phillip.oldham@gmail.com'
3+
__version__='0.1.7'
4+
__licence__='MIT'
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
fromdatetimeimportdatetime,date,timedelta
2+
from .regexsimportTIME_FORMATS,DATE_FORMATS
3+
from .utilityimportParseError
4+
from .timezonesimportTimezone
5+
6+
ONE_DAY=timedelta(days=1)
7+
8+
9+
defparse_date(datestring):
10+
"""Attepmts to parse an ISO8601 formatted ``datestring``.
11+
12+
Returns a ``datetime.datetime`` object.
13+
"""
14+
datestring=str(datestring).strip()
15+
16+
ifnotdatestring[0].isdigit():
17+
raiseParseError()
18+
19+
forregex,patterninDATE_FORMATS:
20+
ifregex.match(datestring):
21+
found=regex.search(datestring).groupdict()
22+
23+
value=found['date']
24+
25+
if'W'infound['date'].upper():
26+
value=found['date'][:-1]+str(int(found['date'][-1:])-1)
27+
28+
if'separator'infound:
29+
value+=found['separator']
30+
31+
if'time'infound:
32+
value+=found['time']
33+
34+
dt=datetime.utcnow().strptime(value,pattern)
35+
36+
if'fraction'infoundandfound['fraction']isnotNone:
37+
dt=dt.replace(microsecond=int(found['fraction'][1:]))
38+
39+
if'timezone'infoundandfound['timezone']isnotNone:
40+
dt=dt.replace(tzinfo=Timezone(found.get('timezone','')))
41+
42+
returndt
43+
44+
returnparse_time(datestring)
45+
46+
47+
defparse_time(timestring):
48+
"""Attepmts to parse an ISO8601 formatted ``timestring``.
49+
50+
Returns a ``datetime.datetime`` object.
51+
"""
52+
timestring=str(timestring).strip()
53+
54+
forregex,patterninTIME_FORMATS:
55+
ifregex.match(timestring):
56+
found=regex.search(timestring).groupdict()
57+
58+
dt=datetime.utcnow().strptime(found['time'],pattern)
59+
dt=datetime.combine(date.today(),dt.time())
60+
61+
if'fraction'infoundandfound['fraction']isnotNone:
62+
dt=dt.replace(microsecond=int(found['fraction'][1:]))
63+
64+
if'timezone'infoundandfound['timezone']isnotNone:
65+
dt=dt.replace(tzinfo=Timezone(found.get('timezone','')))
66+
67+
returndt
68+
69+
raiseParseError()
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
importdatetime
2+
from .regexsimport (SIMPLE_DURATION,COMBINED_DURATION,ELEMENTS)
3+
from .utilityimportParseError
4+
5+
DAYS_IN_YEAR=365
6+
MONTHS_IN_YEAR=12
7+
8+
9+
def_years_to_days(years):
10+
returnyears*DAYS_IN_YEAR
11+
12+
13+
def_months_to_days(months):
14+
return (months*DAYS_IN_YEAR)/MONTHS_IN_YEAR
15+
16+
17+
defparse_duration(duration):
18+
"""Attepmts to parse an ISO8601 formatted ``duration``.
19+
20+
Returns a ``datetime.timedelta`` object.
21+
"""
22+
duration=str(duration).upper().strip()
23+
24+
elements=ELEMENTS.copy()
25+
26+
forpatternin (SIMPLE_DURATION,COMBINED_DURATION):
27+
ifpattern.match(duration):
28+
found=pattern.match(duration).groupdict()
29+
delfound['time']
30+
31+
elements.update(dict((k,int(vor0))
32+
fork,v
33+
infound.iteritems()))
34+
35+
returndatetime.timedelta(days=(elements['days']+
36+
_months_to_days(elements['months'])+
37+
_years_to_days(elements['years'])),
38+
hours=elements['hours'],
39+
minutes=elements['minutes'],
40+
seconds=elements['seconds'])
41+
42+
returnParseError()
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from .utilityimportParseError
2+
from .durationsimportparse_duration
3+
from .datetimestampsimportparse_date
4+
5+
6+
defparse_interval(interval):
7+
"""Attepmts to parse an ISO8601 formatted ``interval``.
8+
9+
Returns a tuple of ``datetime.datetime`` and ``datetime.timedelta``
10+
objects, order dependent on ``interval``.
11+
"""
12+
a,b=str(interval).upper().strip().split('/')
13+
14+
ifa[0]is'P'andb[0]is'P':
15+
raiseParseError()
16+
17+
ifa[0]is'P':
18+
a=parse_duration(a)
19+
else:
20+
a=parse_date(a)
21+
22+
ifb[0]is'P':
23+
b=parse_duration(b)
24+
else:
25+
b=parse_date(b)
26+
27+
returna,b

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp