From 6a3a384fd0decac1203db6c2bddc58039b0390bc Mon Sep 17 00:00:00 2001 From: Peter Golm Date: Sat, 16 Mar 2013 17:28:56 +0100 Subject: [PATCH 1/6] this fixes #108 --- github/Github.py | 40 ++++ github/Notification.py | 171 ++++++++++++++++++ github/tests/Github_.py | 19 ++ .../ReplayData/Github.testGetNotification.txt | 4 + .../Github.testGetNotifications.txt | 4 + 5 files changed, 238 insertions(+) create mode 100644 github/Notification.py create mode 100644 github/tests/ReplayData/Github.testGetNotification.txt create mode 100644 github/tests/ReplayData/Github.testGetNotifications.txt diff --git a/github/Github.py b/github/Github.py index beb74a0e..4d256807 100644 --- a/github/Github.py +++ b/github/Github.py @@ -26,6 +26,7 @@ import Legacy import github.GithubObject import HookDescription import GitignoreTemplate +import Notification DEFAULT_BASE_URL = "https://api.github.com" @@ -153,6 +154,45 @@ class Github(object): None ) + def get_notification(self, id): + """ + :calls: `GET /notifications/threads/:id `_ + :rtype: :class:`github.Notification.Notification` + """ + + assert isinstance(id, (str, unicode)), id + headers, data = self.__requester.requestJsonAndCheck( + "GET", + "/notifications/threads/" + id, + None, + None + ) + print data + return github.Notification.Notification(self.__requester, data, completed=True) + + def get_notifications(self, all=False, participating=True): + """ + :calls: `GET /notifications `_ + :rtype: :class:`github.PaginatedList.PaginatedList` of :class:`github.Notification.Notification` + """ + + assert isinstance(all, (bool, )), all + assert isinstance(participating, (bool,)), participating + + params = dict() + if all: + params["all"] = "true" + if participating: + params["participating"] = "true" + # TODO: implement parameter "since" + + return github.PaginatedList.PaginatedList( + github.Notification.Notification, + self.__requester, + "/notifications", + params + ) + def legacy_search_repos(self, keyword, language=github.GithubObject.NotSet): """ :calls: `GET /legacy/repos/search/:keyword `_ diff --git a/github/Notification.py b/github/Notification.py new file mode 100644 index 00000000..e867efeb --- /dev/null +++ b/github/Notification.py @@ -0,0 +1,171 @@ +# -*- coding: utf-8 -*- + +# Copyright 2013 Peter Golm +# golm.peter@gmail.com + +# This file is part of PyGithub. http://jacquev6.github.com/PyGithub/ + +# PyGithub is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +# PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public License along with PyGithub. If not, see . + +import datetime + +import github.GithubObject +import github.PaginatedList + +import github.Repository + + +class Notification(github.GithubObject.GithubObject): + """ + http://developer.github.com/v3/todo + """ + + @property + def id(self): + """ + :type: string + """ + self._completeIfNotSet(self._id) + return self._NoneIfNotSet(self._id) + + @property + def repository(self): + """ + :type: class: `github.Repository.Repository` + """ + self._completeIfNotSet(self._repository) + return self._NoneIfNotSet(self._repository) + + @property + def subject(self): + """ + :type: class: `github.Notification.NotificationSubject` + """ + self._completeIfNotSet(self._subject) + return self._NoneIfNotSet(self._subject) + + @property + def reason(self): + """ + :type: string + """ + self._completeIfNotSet(self._reason) + return self._NoneIfNotSet(self._reason) + + @property + def unread(self): + """ + :type: bool + """ + self._completeIfNotSet(self._unread) + return self._NoneIfNotSet(self._unread) + + @property + def updated_at(self): + """ + :type: datetime.datetime + """ + self._completeIfNotSet(self._updated_at) + return self._NoneIfNotSet(self._updated_at) + + @property + def url(self): + """ + :type: string + """ + self._completeIfNotSet(self._url) + return self._NoneIfNotSet(self._url) + + def _initAttributes(self): + self._id = github.GithubObject.NotSet + self._repository = github.GithubObject.NotSet + self._reason = github.GithubObject.NotSet + self._unread = github.GithubObject.NotSet + self._updated_at = github.GithubObject.NotSet + self._url = github.GithubObject.NotSet + + def _useAttributes(self, attributes): + if "id" in attributes: + assert attributes["id"] is None or isinstance(attributes["id"], (str, unicode)), attributes["id"] + self._id = attributes["id"] + if "repository" in attributes: + assert attributes["repository"] is None or isinstance(attributes["repository"], (dict)), attributes["repository"] + self._repository = None if attributes["repository"] is None else github.Repository.Repository(self._requester, attributes["repository"], completed=False) + if "subject" in attributes: + assert attributes["subject"] is None or isinstance(attributes["subject"], (dict)), attributes["subject"] + self._subject = None if attributes["subject"] is None else NotificationSubject(self._requester, attributes["subject"], completed=False) + if "reason" in attributes: + assert attributes["reason"] is None or isinstance(attributes["reason"], (str, unicode)), attributes["reason"] + self._reason = attributes["reason"] + if "unread" in attributes: + assert attributes["unread"] is None or isinstance(attributes["unread"], (bool,)), attributes["unread"] + self._unread = attributes["unread"] + if "updated_at" in attributes: + assert attributes["updated_at"] is None or isinstance(attributes["updated_at"], (str, unicode)), attributes["updated_at"] + self._updated_at = datetime.datetime.strptime(attributes["updated_at"], "%Y-%m-%dT%H:%M:%SZ"); + if "url" in attributes: + assert attributes["url"] is None or isinstance(attributes["url"], (str, unicode)), attributes["url"] + self._url = attributes["url"] + +class NotificationSubject(github.GithubObject.GithubObject): + """ + http://developer.github.com/v3/todo + """ + + @property + def title(self): + """ + :type: string + """ + self._completeIfNotSet(self._title) + return self._NoneIfNotSet(self._title) + + @property + def url(self): + """ + :type: string + """ + self._completeIfNotSet(self._url) + return self._NoneIfNotSet(self._url) + + @property + def latest_comment_url(self): + """ + :type: string + """ + self._completeIfNotSet(self._latest_comment_url) + return self._NoneIfNotSet(self._latest_comment_url) + + @property + def type(self): + """ + :type: string + """ + self._completeIfNotSet(self._type) + return self._NoneIfNotSet(self._type) + + def _initAttributes(self): + self._title = github.GithubObject.NotSet + self._url = github.GithubObject.NotSet + self._latest_comment_url = github.GithubObject.NotSet + self._type = github.GithubObject.NotSet + + def _useAttributes(self, attributes): + if "title" in attributes: # pragma no branch + assert attributes["title"] is None or isinstance(attributes["title"], (str, unicode)), attributes["title"] + self._title = attributes["title"] + if "url" in attributes: # pragma no branch + assert attributes["url"] is None or isinstance(attributes["url"], (str, unicode)), attributes["url"] + self._url = attributes["url"] + if "latest_comment_url" in attributes: # pragma no branch + assert attributes["latest_comment_url"] is None or isinstance(attributes["latest_comment_url"], (str, unicode)), attributes["latest_comment_url"] + self._latest_comment_url = attributes["latest_comment_url"] + if "type" in attributes: # pragma no branch + assert attributes["type"] is None or isinstance(attributes["type"], (str, unicode)), attributes["type"] + self._type = attributes["type"] \ No newline at end of file diff --git a/github/tests/Github_.py b/github/tests/Github_.py index eb33b27c..4595a431 100644 --- a/github/tests/Github_.py +++ b/github/tests/Github_.py @@ -93,6 +93,25 @@ class Github(Framework.TestCase): self.assertEqual(hook.events, ["push"]) self.assertEqual(hook.schema, [["string", "url"], ["string", "token"], ["string", "project_id"], ["string", "milestone_id"], ["string", "category_id"]]) + def testGetNotification(self): + notification = self.g.get_notification("8406712") + self.assertEqual(notification.id, "8406712") + self.assertEqual(notification.unread, False) + self.assertEqual(notification.reason, "author") + self.assertEqual(notification.subject.title, "Feature/coveralls") + self.assertEqual(notification.subject.type, "PullRequest") + self.assertEqual(notification.repository.id, 8432784) + + def testGetNotifications(self): + notifications = self.g.get_notifications() + notification = notifications[0] + self.assertEqual(notification.id, "8406712") + self.assertEqual(notification.unread, False) + self.assertEqual(notification.reason, "author") + self.assertEqual(notification.subject.title, "Feature/coveralls") + self.assertEqual(notification.subject.type, "PullRequest") + self.assertEqual(notification.repository.id, 8432784) + def testGetRepoFromFullName(self): self.assertEqual(self.g.get_repo("jacquev6/PyGithub").description, "Python library implementing the full Github API v3") diff --git a/github/tests/ReplayData/Github.testGetNotification.txt b/github/tests/ReplayData/Github.testGetNotification.txt new file mode 100644 index 00000000..06739072 --- /dev/null +++ b/github/tests/ReplayData/Github.testGetNotification.txt @@ -0,0 +1,4 @@ +https GET api.github.com None /notifications/threads/8406712 {'Authorization': 'Basic login_and_password_removed'} null +200 +[('status', '200 OK'), ('x-ratelimit-remaining', '4999'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('x-ratelimit-limit', '5000'), ('vary', 'Accept, Authorization, Cookie'), ('content-length', '16567'), ('server', 'nginx'), ('last-modified', 'Fri, 24 Aug 2012 07:05:12 GMT'), ('connection', 'keep-alive'), ('etag', '"eb52c03081d2fc22f26ed2718921e500"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('date', 'Sat, 08 Sep 2012 17:26:28 GMT'), ('content-type', 'application/json; charset=utf-8')] +{"id": "8406712","unread": false,"reason": "author","updated_at": "2013-03-15T05:43:11Z","last_read_at": "2013-03-15T06:06:34Z","subject": {"title": "Feature/coveralls","type": "PullRequest"},"repository": {"id": 8432784}} diff --git a/github/tests/ReplayData/Github.testGetNotifications.txt b/github/tests/ReplayData/Github.testGetNotifications.txt new file mode 100644 index 00000000..81aa7eed --- /dev/null +++ b/github/tests/ReplayData/Github.testGetNotifications.txt @@ -0,0 +1,4 @@ +https GET api.github.com None /notifications?participating=true {'Authorization': 'Basic login_and_password_removed'} null +200 +[('status', '200 OK'), ('x-ratelimit-remaining', '4999'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('x-ratelimit-limit', '5000'), ('vary', 'Accept, Authorization, Cookie'), ('content-length', '16567'), ('server', 'nginx'), ('last-modified', 'Fri, 24 Aug 2012 07:05:12 GMT'), ('connection', 'keep-alive'), ('etag', '"eb52c03081d2fc22f26ed2718921e500"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('date', 'Sat, 08 Sep 2012 17:26:28 GMT'), ('content-type', 'application/json; charset=utf-8')] +[{"id": "8406712","unread": false,"reason": "author","updated_at": "2013-03-15T05:43:11Z","last_read_at": "2013-03-15T06:06:34Z","subject": {"title": "Feature/coveralls","type": "PullRequest"},"repository": {"id": 8432784}}] From 23d668f11bdd806a871e0979bf5295d001f66ef2 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Tue, 19 Mar 2013 21:26:28 +0100 Subject: [PATCH 2/6] Remove debug print (pull #148) --- github/MainClass.py | 1 - 1 file changed, 1 deletion(-) diff --git a/github/MainClass.py b/github/MainClass.py index 0c6d5faa..8783701b 100644 --- a/github/MainClass.py +++ b/github/MainClass.py @@ -180,7 +180,6 @@ class Github(object): None, None ) - print data return github.Notification.Notification(self.__requester, data, completed=True) def get_notifications(self, all=False, participating=True): From f25c54e1d4eefb11c18f3de85270a4b19edea3ce Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Tue, 19 Mar 2013 21:27:34 +0100 Subject: [PATCH 3/6] Fix documentation (pull #148) I had to separate class NotificationSubject in its own file, to cope with my basic doc generation. --- doc/conf.py | 2 +- github/Notification.py | 80 +++++------------------------------ github/NotificationSubject.py | 71 +++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 70 deletions(-) create mode 100644 github/NotificationSubject.py diff --git a/doc/conf.py b/doc/conf.py index 9e311aa9..958de460 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -252,7 +252,7 @@ with open("github_objects.rst", "w") as github_objects: github_objects.write("\n") github_objects.write(".. toctree::\n") - for obj in ["AuthenticatedUser", "Authorization", "AuthorizationApplication", "Branch", "Commit", "CommitComment", "CommitStats", "CommitStatus", "Comparison", "ContentFile", "Download", "Event", "File", "Gist", "GistComment", "GistFile", "GistHistoryState", "GitAuthor", "GitBlob", "GitCommit", "GitObject", "GitignoreTemplate", "GitRef", "GitTag", "GitTree", "GitTreeElement", "Hook", "HookDescription", "HookResponse", "Issue", "IssueComment", "IssueEvent", "IssuePullRequest", "Label", "Milestone", "NamedUser", "Organization", "Permissions", "Plan", "PullRequest", "PullRequestComment", "PullRequestMergeStatus", "PullRequestPart", "Repository", "RepositoryKey", "Tag", "Team", "UserKey"]: + for obj in ["AuthenticatedUser", "Authorization", "AuthorizationApplication", "Branch", "Commit", "CommitComment", "CommitStats", "CommitStatus", "Comparison", "ContentFile", "Download", "Event", "File", "Gist", "GistComment", "GistFile", "GistHistoryState", "GitAuthor", "GitBlob", "GitCommit", "GitObject", "GitignoreTemplate", "GitRef", "GitTag", "GitTree", "GitTreeElement", "Hook", "HookDescription", "HookResponse", "Issue", "IssueComment", "IssueEvent", "IssuePullRequest", "Label", "Milestone", "NamedUser", "Notification", "NotificationSubject", "Organization", "Permissions", "Plan", "PullRequest", "PullRequestComment", "PullRequestMergeStatus", "PullRequestPart", "Repository", "RepositoryKey", "Tag", "Team", "UserKey"]: github_objects.write(" github_objects/" + obj + "\n") with open("github_objects/" + obj + ".rst", "w") as github_object: github_object.write(obj + "\n") diff --git a/github/Notification.py b/github/Notification.py index e867efeb..42e15231 100644 --- a/github/Notification.py +++ b/github/Notification.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- -# Copyright 2013 Peter Golm +# Copyright 2013 Peter Golm and Vincent Jacques # golm.peter@gmail.com +# vincent@vincent-jacques.net # This file is part of PyGithub. http://jacquev6.github.com/PyGithub/ @@ -13,17 +14,15 @@ # You should have received a copy of the GNU Lesser General Public License along with PyGithub. If not, see . -import datetime - import github.GithubObject -import github.PaginatedList import github.Repository +import github.NotificationSubject class Notification(github.GithubObject.GithubObject): """ - http://developer.github.com/v3/todo + This class represents Notifications as returned for example by http://developer.github.com/v3/activity/notifications/#list-your-notifications """ @property @@ -37,7 +36,7 @@ class Notification(github.GithubObject.GithubObject): @property def repository(self): """ - :type: class: `github.Repository.Repository` + :type: :class:`github.Repository.Repository` """ self._completeIfNotSet(self._repository) return self._NoneIfNotSet(self._repository) @@ -45,7 +44,7 @@ class Notification(github.GithubObject.GithubObject): @property def subject(self): """ - :type: class: `github.Notification.NotificationSubject` + :type: :class:`github.NotificationSubject.NotificationSubject` """ self._completeIfNotSet(self._subject) return self._NoneIfNotSet(self._subject) @@ -95,77 +94,20 @@ class Notification(github.GithubObject.GithubObject): assert attributes["id"] is None or isinstance(attributes["id"], (str, unicode)), attributes["id"] self._id = attributes["id"] if "repository" in attributes: - assert attributes["repository"] is None or isinstance(attributes["repository"], (dict)), attributes["repository"] + assert attributes["repository"] is None or isinstance(attributes["repository"], dict), attributes["repository"] self._repository = None if attributes["repository"] is None else github.Repository.Repository(self._requester, attributes["repository"], completed=False) if "subject" in attributes: - assert attributes["subject"] is None or isinstance(attributes["subject"], (dict)), attributes["subject"] - self._subject = None if attributes["subject"] is None else NotificationSubject(self._requester, attributes["subject"], completed=False) + assert attributes["subject"] is None or isinstance(attributes["subject"], dict), attributes["subject"] + self._subject = None if attributes["subject"] is None else github.NotificationSubject.NotificationSubject(self._requester, attributes["subject"], completed=False) if "reason" in attributes: assert attributes["reason"] is None or isinstance(attributes["reason"], (str, unicode)), attributes["reason"] self._reason = attributes["reason"] if "unread" in attributes: - assert attributes["unread"] is None or isinstance(attributes["unread"], (bool,)), attributes["unread"] + assert attributes["unread"] is None or isinstance(attributes["unread"], bool), attributes["unread"] self._unread = attributes["unread"] if "updated_at" in attributes: assert attributes["updated_at"] is None or isinstance(attributes["updated_at"], (str, unicode)), attributes["updated_at"] - self._updated_at = datetime.datetime.strptime(attributes["updated_at"], "%Y-%m-%dT%H:%M:%SZ"); + self._updated_at = self._parseDatetime(attributes["updated_at"]); if "url" in attributes: assert attributes["url"] is None or isinstance(attributes["url"], (str, unicode)), attributes["url"] self._url = attributes["url"] - -class NotificationSubject(github.GithubObject.GithubObject): - """ - http://developer.github.com/v3/todo - """ - - @property - def title(self): - """ - :type: string - """ - self._completeIfNotSet(self._title) - return self._NoneIfNotSet(self._title) - - @property - def url(self): - """ - :type: string - """ - self._completeIfNotSet(self._url) - return self._NoneIfNotSet(self._url) - - @property - def latest_comment_url(self): - """ - :type: string - """ - self._completeIfNotSet(self._latest_comment_url) - return self._NoneIfNotSet(self._latest_comment_url) - - @property - def type(self): - """ - :type: string - """ - self._completeIfNotSet(self._type) - return self._NoneIfNotSet(self._type) - - def _initAttributes(self): - self._title = github.GithubObject.NotSet - self._url = github.GithubObject.NotSet - self._latest_comment_url = github.GithubObject.NotSet - self._type = github.GithubObject.NotSet - - def _useAttributes(self, attributes): - if "title" in attributes: # pragma no branch - assert attributes["title"] is None or isinstance(attributes["title"], (str, unicode)), attributes["title"] - self._title = attributes["title"] - if "url" in attributes: # pragma no branch - assert attributes["url"] is None or isinstance(attributes["url"], (str, unicode)), attributes["url"] - self._url = attributes["url"] - if "latest_comment_url" in attributes: # pragma no branch - assert attributes["latest_comment_url"] is None or isinstance(attributes["latest_comment_url"], (str, unicode)), attributes["latest_comment_url"] - self._latest_comment_url = attributes["latest_comment_url"] - if "type" in attributes: # pragma no branch - assert attributes["type"] is None or isinstance(attributes["type"], (str, unicode)), attributes["type"] - self._type = attributes["type"] \ No newline at end of file diff --git a/github/NotificationSubject.py b/github/NotificationSubject.py new file mode 100644 index 00000000..11846788 --- /dev/null +++ b/github/NotificationSubject.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- + +# Copyright 2013 Peter Golm and Vincent Jacques +# golm.peter@gmail.com +# vincent@vincent-jacques.net + +# This file is part of PyGithub. http://jacquev6.github.com/PyGithub/ + +# PyGithub is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +# PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public License along with PyGithub. If not, see . + +import github.GithubObject + + +class NotificationSubject(github.GithubObject.BasicGithubObject): + """ + This class represents Subjects of Notifications as returned for example by http://developer.github.com/v3/activity/notifications/#list-your-notifications + """ + + @property + def title(self): + """ + :type: string + """ + return self._NoneIfNotSet(self._title) + + @property + def url(self): + """ + :type: string + """ + return self._NoneIfNotSet(self._url) + + @property + def latest_comment_url(self): + """ + :type: string + """ + return self._NoneIfNotSet(self._latest_comment_url) + + @property + def type(self): + """ + :type: string + """ + return self._NoneIfNotSet(self._type) + + def _initAttributes(self): + self._title = github.GithubObject.NotSet + self._url = github.GithubObject.NotSet + self._latest_comment_url = github.GithubObject.NotSet + self._type = github.GithubObject.NotSet + + def _useAttributes(self, attributes): + if "title" in attributes: # pragma no branch + assert attributes["title"] is None or isinstance(attributes["title"], (str, unicode)), attributes["title"] + self._title = attributes["title"] + if "url" in attributes: # pragma no branch + assert attributes["url"] is None or isinstance(attributes["url"], (str, unicode)), attributes["url"] + self._url = attributes["url"] + if "latest_comment_url" in attributes: # pragma no branch + assert attributes["latest_comment_url"] is None or isinstance(attributes["latest_comment_url"], (str, unicode)), attributes["latest_comment_url"] + self._latest_comment_url = attributes["latest_comment_url"] + if "type" in attributes: # pragma no branch + assert attributes["type"] is None or isinstance(attributes["type"], (str, unicode)), attributes["type"] + self._type = attributes["type"] From edcf40bc7f25d1aff5c404406fbb37ad1bcf691e Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Tue, 19 Mar 2013 22:07:29 +0100 Subject: [PATCH 4/6] Move get_notification(s) to AuthenticatedUser (pull #148) --- github/AuthenticatedUser.py | 38 +++++++++++++++++++ github/MainClass.py | 38 ------------------- github/tests/AuthenticatedUser.py | 12 ++++++ github/tests/Github_.py | 19 ---------- ...AuthenticatedUser.testGetNotification.txt} | 0 ...uthenticatedUser.testGetNotifications.txt} | 2 +- 6 files changed, 51 insertions(+), 58 deletions(-) rename github/tests/ReplayData/{Github.testGetNotification.txt => AuthenticatedUser.testGetNotification.txt} (100%) rename github/tests/ReplayData/{Github.testGetNotifications.txt => AuthenticatedUser.testGetNotifications.txt} (92%) diff --git a/github/AuthenticatedUser.py b/github/AuthenticatedUser.py index 6665c669..0e3d52cf 100644 --- a/github/AuthenticatedUser.py +++ b/github/AuthenticatedUser.py @@ -617,6 +617,44 @@ class AuthenticatedUser(github.GithubObject.GithubObject): None ) + def get_notification(self, id): + """ + :calls: `GET /notifications/threads/:id `_ + :rtype: :class:`github.Notification.Notification` + """ + + assert isinstance(id, (str, unicode)), id + headers, data = self._requester.requestJsonAndCheck( + "GET", + "/notifications/threads/" + id, + None, + None + ) + return github.Notification.Notification(self._requester, data, completed=True) + + def get_notifications(self, all=github.GithubObject.NotSet, participating=github.GithubObject.NotSet): + """ + :calls: `GET /notifications `_ + :rtype: :class:`github.PaginatedList.PaginatedList` of :class:`github.Notification.Notification` + """ + + assert all is github.GithubObject.NotSet or isinstance(all, bool), all + assert participating is github.GithubObject.NotSet or isinstance(participating, bool), participating + + params = dict() + if all is not github.GithubObject.NotSet: + params["all"] = all + if participating is not github.GithubObject.NotSet: + params["participating"] = participating + # TODO: implement parameter "since" + + return github.PaginatedList.PaginatedList( + github.Notification.Notification, + self._requester, + "/notifications", + params + ) + def get_organization_events(self, org): """ :calls: `GET /users/:user/events/orgs/:org `_ diff --git a/github/MainClass.py b/github/MainClass.py index 8783701b..d0a97aec 100644 --- a/github/MainClass.py +++ b/github/MainClass.py @@ -167,44 +167,6 @@ class Github(object): None ) - def get_notification(self, id): - """ - :calls: `GET /notifications/threads/:id `_ - :rtype: :class:`github.Notification.Notification` - """ - - assert isinstance(id, (str, unicode)), id - headers, data = self.__requester.requestJsonAndCheck( - "GET", - "/notifications/threads/" + id, - None, - None - ) - return github.Notification.Notification(self.__requester, data, completed=True) - - def get_notifications(self, all=False, participating=True): - """ - :calls: `GET /notifications `_ - :rtype: :class:`github.PaginatedList.PaginatedList` of :class:`github.Notification.Notification` - """ - - assert isinstance(all, (bool, )), all - assert isinstance(participating, (bool,)), participating - - params = dict() - if all: - params["all"] = "true" - if participating: - params["participating"] = "true" - # TODO: implement parameter "since" - - return github.PaginatedList.PaginatedList( - github.Notification.Notification, - self.__requester, - "/notifications", - params - ) - def legacy_search_repos(self, keyword, language=github.GithubObject.NotSet): """ :calls: `GET /legacy/repos/search/:keyword `_ diff --git a/github/tests/AuthenticatedUser.py b/github/tests/AuthenticatedUser.py index 8ae20d7a..77bcae4d 100644 --- a/github/tests/AuthenticatedUser.py +++ b/github/tests/AuthenticatedUser.py @@ -185,3 +185,15 @@ class AuthenticatedUser(Framework.TestCase): def testCreateFork(self): repo = self.user.create_fork(self.g.get_user("nvie").get_repo("gitflow")) self.assertEqual(repo.source.full_name, "nvie/gitflow") + + def testGetNotification(self): + notification = self.user.get_notification("8406712") + self.assertEqual(notification.id, "8406712") + self.assertEqual(notification.unread, False) + self.assertEqual(notification.reason, "author") + self.assertEqual(notification.subject.title, "Feature/coveralls") + self.assertEqual(notification.subject.type, "PullRequest") + self.assertEqual(notification.repository.id, 8432784) + + def testGetNotifications(self): + self.assertListKeyBegin(self.user.get_notifications(participating=True), lambda n: n.id, ["8406712"]) diff --git a/github/tests/Github_.py b/github/tests/Github_.py index 46da42c7..149af2b8 100644 --- a/github/tests/Github_.py +++ b/github/tests/Github_.py @@ -93,25 +93,6 @@ class Github(Framework.TestCase): self.assertEqual(hook.events, ["push"]) self.assertEqual(hook.schema, [["string", "url"], ["string", "token"], ["string", "project_id"], ["string", "milestone_id"], ["string", "category_id"]]) - def testGetNotification(self): - notification = self.g.get_notification("8406712") - self.assertEqual(notification.id, "8406712") - self.assertEqual(notification.unread, False) - self.assertEqual(notification.reason, "author") - self.assertEqual(notification.subject.title, "Feature/coveralls") - self.assertEqual(notification.subject.type, "PullRequest") - self.assertEqual(notification.repository.id, 8432784) - - def testGetNotifications(self): - notifications = self.g.get_notifications() - notification = notifications[0] - self.assertEqual(notification.id, "8406712") - self.assertEqual(notification.unread, False) - self.assertEqual(notification.reason, "author") - self.assertEqual(notification.subject.title, "Feature/coveralls") - self.assertEqual(notification.subject.type, "PullRequest") - self.assertEqual(notification.repository.id, 8432784) - def testGetRepoFromFullName(self): self.assertEqual(self.g.get_repo("jacquev6/PyGithub").description, "Python library implementing the full Github API v3") diff --git a/github/tests/ReplayData/Github.testGetNotification.txt b/github/tests/ReplayData/AuthenticatedUser.testGetNotification.txt similarity index 100% rename from github/tests/ReplayData/Github.testGetNotification.txt rename to github/tests/ReplayData/AuthenticatedUser.testGetNotification.txt diff --git a/github/tests/ReplayData/Github.testGetNotifications.txt b/github/tests/ReplayData/AuthenticatedUser.testGetNotifications.txt similarity index 92% rename from github/tests/ReplayData/Github.testGetNotifications.txt rename to github/tests/ReplayData/AuthenticatedUser.testGetNotifications.txt index 81aa7eed..150f872a 100644 --- a/github/tests/ReplayData/Github.testGetNotifications.txt +++ b/github/tests/ReplayData/AuthenticatedUser.testGetNotifications.txt @@ -1,4 +1,4 @@ -https GET api.github.com None /notifications?participating=true {'Authorization': 'Basic login_and_password_removed'} null +https GET api.github.com None /notifications?participating=True {'Authorization': 'Basic login_and_password_removed'} null 200 [('status', '200 OK'), ('x-ratelimit-remaining', '4999'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('x-ratelimit-limit', '5000'), ('vary', 'Accept, Authorization, Cookie'), ('content-length', '16567'), ('server', 'nginx'), ('last-modified', 'Fri, 24 Aug 2012 07:05:12 GMT'), ('connection', 'keep-alive'), ('etag', '"eb52c03081d2fc22f26ed2718921e500"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('date', 'Sat, 08 Sep 2012 17:26:28 GMT'), ('content-type', 'application/json; charset=utf-8')] [{"id": "8406712","unread": false,"reason": "author","updated_at": "2013-03-15T05:43:11Z","last_read_at": "2013-03-15T06:06:34Z","subject": {"title": "Feature/coveralls","type": "PullRequest"},"repository": {"id": 8432784}}] From 0901df1a2bed3f993cfe6e0d4cff5923bbf6ce32 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Tue, 19 Mar 2013 22:07:42 +0100 Subject: [PATCH 5/6] Improve test coverage (pull #148) --- github/Notification.py | 14 +++++++------- github/tests/AuthenticatedUser.py | 9 ++++++++- ...User.testGetNotificationsWithOtherArguments.txt | 5 +++++ 3 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 github/tests/ReplayData/AuthenticatedUser.testGetNotificationsWithOtherArguments.txt diff --git a/github/Notification.py b/github/Notification.py index 42e15231..20b4a398 100644 --- a/github/Notification.py +++ b/github/Notification.py @@ -90,24 +90,24 @@ class Notification(github.GithubObject.GithubObject): self._url = github.GithubObject.NotSet def _useAttributes(self, attributes): - if "id" in attributes: + if "id" in attributes: # pragma no branch assert attributes["id"] is None or isinstance(attributes["id"], (str, unicode)), attributes["id"] self._id = attributes["id"] - if "repository" in attributes: + if "repository" in attributes: # pragma no branch assert attributes["repository"] is None or isinstance(attributes["repository"], dict), attributes["repository"] self._repository = None if attributes["repository"] is None else github.Repository.Repository(self._requester, attributes["repository"], completed=False) - if "subject" in attributes: + if "subject" in attributes: # pragma no branch assert attributes["subject"] is None or isinstance(attributes["subject"], dict), attributes["subject"] self._subject = None if attributes["subject"] is None else github.NotificationSubject.NotificationSubject(self._requester, attributes["subject"], completed=False) - if "reason" in attributes: + if "reason" in attributes: # pragma no branch assert attributes["reason"] is None or isinstance(attributes["reason"], (str, unicode)), attributes["reason"] self._reason = attributes["reason"] - if "unread" in attributes: + if "unread" in attributes: # pragma no branch assert attributes["unread"] is None or isinstance(attributes["unread"], bool), attributes["unread"] self._unread = attributes["unread"] - if "updated_at" in attributes: + if "updated_at" in attributes: # pragma no branch assert attributes["updated_at"] is None or isinstance(attributes["updated_at"], (str, unicode)), attributes["updated_at"] self._updated_at = self._parseDatetime(attributes["updated_at"]); - if "url" in attributes: + if "url" in attributes: # pragma no branch assert attributes["url"] is None or isinstance(attributes["url"], (str, unicode)), attributes["url"] self._url = attributes["url"] diff --git a/github/tests/AuthenticatedUser.py b/github/tests/AuthenticatedUser.py index 77bcae4d..42ef98fe 100644 --- a/github/tests/AuthenticatedUser.py +++ b/github/tests/AuthenticatedUser.py @@ -194,6 +194,13 @@ class AuthenticatedUser(Framework.TestCase): self.assertEqual(notification.subject.title, "Feature/coveralls") self.assertEqual(notification.subject.type, "PullRequest") self.assertEqual(notification.repository.id, 8432784) + self.assertEqual(notification.updated_at, datetime.datetime(2013, 3, 15, 5, 43, 11)) + self.assertEqual(notification.url, None) + self.assertEqual(notification.subject.url, None) + self.assertEqual(notification.subject.latest_comment_url, None) def testGetNotifications(self): - self.assertListKeyBegin(self.user.get_notifications(participating=True), lambda n: n.id, ["8406712"]) + self.assertListKeyEqual(self.user.get_notifications(participating=True), lambda n: n.id, ["8406712"]) + + def testGetNotificationsWithOtherArguments(self): + self.assertListKeyEqual(self.user.get_notifications(all=True), lambda n: n.id, []) diff --git a/github/tests/ReplayData/AuthenticatedUser.testGetNotificationsWithOtherArguments.txt b/github/tests/ReplayData/AuthenticatedUser.testGetNotificationsWithOtherArguments.txt new file mode 100644 index 00000000..88a78000 --- /dev/null +++ b/github/tests/ReplayData/AuthenticatedUser.testGetNotificationsWithOtherArguments.txt @@ -0,0 +1,5 @@ +https GET api.github.com None /notifications?all=True {'Authorization': 'Basic login_and_password_removed'} null +200 +[('status', '200 OK'), ('x-ratelimit-remaining', '4999'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('content-length', '2'), ('server', 'GitHub.com'), ('connection', 'keep-alive'), ('x-ratelimit-limit', '5000'), ('etag', '"d751713988987e9331980363e24189ce"'), ('cache-control', 'max-age=0, private, must-revalidate'), ('date', 'Tue, 19 Mar 2013 21:05:52 GMT'), ('content-type', 'application/json; charset=utf-8')] +[] + From ee29deddd27480401db484733ecde9e7b1df5eda Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Tue, 19 Mar 2013 22:36:35 +0100 Subject: [PATCH 6/6] Complete doc/apis.rst (pull #148) --- doc/apis.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/apis.rst b/doc/apis.rst index 48e4601c..738edb0a 100644 --- a/doc/apis.rst +++ b/doc/apis.rst @@ -104,6 +104,14 @@ APIs * GET: :meth:`github.Repository.Repository.get_network_events` +* ``/notifications`` + + * GET: :meth:`github.AuthenticatedUser.AuthenticatedUser.get_notifications` + +* ``/notifications/threads/:id`` + + * GET: :meth:`github.AuthenticatedUser.AuthenticatedUser.get_notification` + * ``/orgs/:org`` * GET: :meth:`github.MainClass.Github.get_organization`