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}}]