diff --git a/.gitignore b/.gitignore index 6ff70a1d..fa4ed127 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,4 @@ GithubCredentials.py *.cfg *.bat +*.py~ diff --git a/README.rst b/README.rst index 22fd4ef3..32e67f35 100644 --- a/README.rst +++ b/README.rst @@ -16,8 +16,11 @@ Thank you, dear stargazers! Starting today (September 05th, 2013), we now need more than 8 bits to store the number of `stargazers `_! Thank you so much! -`Version 1.19.0 `_ (?? ??th, 2013) +`Version 1.19.0 `_ (September ??th, 2013) (AKFish's edition) +----------------------------------------------------------------------------------------------------------------------------------- +* Implement `conditional requests `_ by the method ``GithubObject.update``. Thank you very much `akfish `_ for the pull request and your collaboration! +* Implement persistence of PyGithub objects: ``Github.save`` and ``Github.load``. Don't forget to ``update`` your objects after loading them, it won't decrease your rate limiting quota if nothing has changed. Again, thank you `akfish `_ * Implement ``Github.get_repos`` to get all public repositories * Implement ``NamedUser.has_in_following`` * Technical change: HTTP headers are now stored in retrieved objects. This is a base for new functionalities. Thank you `akfish `_ for the pull request diff --git a/github/AuthenticatedUser.py b/github/AuthenticatedUser.py index e035f9a1..d403893f 100644 --- a/github/AuthenticatedUser.py +++ b/github/AuthenticatedUser.py @@ -258,6 +258,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "POST", "/user/emails", None, + None, post_parameters ) @@ -272,6 +273,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "PUT", "/user/following/" + following._identity, None, + None, None ) @@ -286,6 +288,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "PUT", "/user/starred/" + starred._identity, None, + None, None ) @@ -300,6 +303,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "PUT", "/user/subscriptions/" + subscription._identity, None, + None, None ) @@ -314,6 +318,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "PUT", "/user/watched/" + watched._identity, None, + None, None ) @@ -347,6 +352,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "POST", "/authorizations", None, + None, post_parameters ) return github.Authorization.Authorization(self._requester, headers, data, completed=True) @@ -362,6 +368,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "POST", "/repos/" + repo.owner.login + "/" + repo.name + "/forks", None, + None, None ) return github.Repository.Repository(self._requester, headers, data, completed=True) @@ -387,6 +394,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "POST", "/gists", None, + None, post_parameters ) return github.Gist.Gist(self._requester, headers, data, completed=True) @@ -408,6 +416,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "POST", "/user/keys", None, + None, post_parameters ) return github.UserKey.UserKey(self._requester, headers, data, completed=True) @@ -458,6 +467,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "POST", "/user/repos", None, + None, post_parameters ) return github.Repository.Repository(self._requester, headers, data, completed=True) @@ -500,6 +510,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "PATCH", "/user", None, + None, post_parameters ) self._useAttributes(data) @@ -515,6 +526,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "GET", "/authorizations/" + str(id), None, + None, None ) return github.Authorization.Authorization(self._requester, headers, data, completed=True) @@ -540,6 +552,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "GET", "/user/emails", None, + None, None ) return data @@ -679,6 +692,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "GET", "/user/keys/" + str(id), None, + None, None ) return github.UserKey.UserKey(self._requester, headers, data, completed=True) @@ -706,6 +720,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "GET", "/notifications/threads/" + id, None, + None, None ) return github.Notification.Notification(self._requester, headers, data, completed=True) @@ -770,6 +785,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "GET", "/repos/" + self.login + "/" + name, None, + None, None ) return github.Repository.Repository(self._requester, headers, data, completed=True) @@ -858,6 +874,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "GET", "/user/following/" + following._identity, None, + None, None ) return status == 204 @@ -873,6 +890,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "GET", "/user/starred/" + starred._identity, None, + None, None ) return status == 204 @@ -888,6 +906,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "GET", "/user/subscriptions/" + subscription._identity, None, + None, None ) return status == 204 @@ -903,6 +922,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "GET", "/user/watched/" + watched._identity, None, + None, None ) return status == 204 @@ -919,6 +939,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "DELETE", "/user/emails", None, + None, post_parameters ) @@ -933,6 +954,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "DELETE", "/user/following/" + following._identity, None, + None, None ) @@ -947,6 +969,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "DELETE", "/user/starred/" + starred._identity, None, + None, None ) @@ -961,6 +984,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "DELETE", "/user/subscriptions/" + subscription._identity, None, + None, None ) @@ -975,6 +999,7 @@ class AuthenticatedUser(github.GithubObject.CompletableGithubObject): "DELETE", "/user/watched/" + watched._identity, None, + None, None ) diff --git a/github/Authorization.py b/github/Authorization.py index 2289fd34..f287a2b6 100644 --- a/github/Authorization.py +++ b/github/Authorization.py @@ -115,6 +115,7 @@ class Authorization(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -148,6 +149,7 @@ class Authorization(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) diff --git a/github/Commit.py b/github/Commit.py index 5e909213..ad744e39 100644 --- a/github/Commit.py +++ b/github/Commit.py @@ -131,6 +131,7 @@ class Commit(github.GithubObject.CompletableGithubObject): "POST", self.url + "/comments", None, + None, post_parameters ) return github.CommitComment.CommitComment(self._requester, headers, data, completed=True) @@ -157,6 +158,7 @@ class Commit(github.GithubObject.CompletableGithubObject): "POST", self._parentUrl(self._parentUrl(self.url)) + "/statuses/" + self.sha, None, + None, post_parameters ) return github.CommitStatus.CommitStatus(self._requester, headers, data, completed=True) diff --git a/github/CommitComment.py b/github/CommitComment.py index 55c2cf86..061737bf 100644 --- a/github/CommitComment.py +++ b/github/CommitComment.py @@ -131,6 +131,7 @@ class CommitComment(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -148,6 +149,7 @@ class CommitComment(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) diff --git a/github/Consts.py b/github/Consts.py new file mode 100644 index 00000000..b3b47914 --- /dev/null +++ b/github/Consts.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +############################ Copyrights and license ############################ +# # +# Copyright 2013 AKFish # +# # +# 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 . # +# # +################################################################################ + +# #193: Line endings should be linux style + +# TODO: As of Thu Aug 21 22:40:13 (BJT) Chinese Standard Time 2013 +# lots of consts in this project are explict +# should realy round them up and reference them by consts +# EDIT: well, maybe :-) + +################################################################################ +# Request Header # +# (Case sensitive) # +################################################################################ +REQ_IF_NONE_MATCH = "If-None-Match" +REQ_IF_MODIFIED_SINCE = "If-Modified-Since" + +################################################################################ +# Response Header # +# (Lower Case) # +################################################################################ +RES_ETAG = "etag" +RES_LAST_MODIFED = "last-modified" diff --git a/github/Download.py b/github/Download.py index 86b7ae44..a4b3b656 100644 --- a/github/Download.py +++ b/github/Download.py @@ -201,6 +201,7 @@ class Download(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) diff --git a/github/Gist.py b/github/Gist.py index a1497685..de4ded9e 100644 --- a/github/Gist.py +++ b/github/Gist.py @@ -173,6 +173,7 @@ class Gist(github.GithubObject.CompletableGithubObject): "POST", self.url + "/comments", None, + None, post_parameters ) return github.GistComment.GistComment(self._requester, headers, data, completed=True) @@ -186,6 +187,7 @@ class Gist(github.GithubObject.CompletableGithubObject): "POST", self.url + "/forks", None, + None, None ) return Gist(self._requester, headers, data, completed=True) @@ -199,6 +201,7 @@ class Gist(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -220,6 +223,7 @@ class Gist(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) @@ -235,6 +239,7 @@ class Gist(github.GithubObject.CompletableGithubObject): "GET", self.url + "/comments/" + str(id), None, + None, None ) return github.GistComment.GistComment(self._requester, headers, data, completed=True) @@ -260,6 +265,7 @@ class Gist(github.GithubObject.CompletableGithubObject): "GET", self.url + "/star", None, + None, None ) return status == 204 @@ -273,6 +279,7 @@ class Gist(github.GithubObject.CompletableGithubObject): "DELETE", self.url + "/star", None, + None, None ) @@ -285,6 +292,7 @@ class Gist(github.GithubObject.CompletableGithubObject): "PUT", self.url + "/star", None, + None, None ) diff --git a/github/GistComment.py b/github/GistComment.py index 6c7e2461..f0b5c80c 100644 --- a/github/GistComment.py +++ b/github/GistComment.py @@ -91,6 +91,7 @@ class GistComment(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -108,6 +109,7 @@ class GistComment(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) diff --git a/github/GitRef.py b/github/GitRef.py index a666156b..84ec00c5 100644 --- a/github/GitRef.py +++ b/github/GitRef.py @@ -67,6 +67,7 @@ class GitRef(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -88,6 +89,7 @@ class GitRef(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) diff --git a/github/GithubException.py b/github/GithubException.py index 12c9af62..02e7a75e 100644 --- a/github/GithubException.py +++ b/github/GithubException.py @@ -4,6 +4,7 @@ # # # Copyright 2012 Vincent Jacques # # Copyright 2012 Zearin # +# Copyright 2013 AKFish # # Copyright 2013 Vincent Jacques # # # # This file is part of PyGithub. http://jacquev6.github.com/PyGithub/ # diff --git a/github/GithubObject.py b/github/GithubObject.py index fcf36c29..c2ae7f6d 100644 --- a/github/GithubObject.py +++ b/github/GithubObject.py @@ -27,6 +27,7 @@ import datetime import GithubException +import Consts class _NotSetType: @@ -51,20 +52,20 @@ class GithubObject(object): def __init__(self, requester, headers, attributes, completed): self._requester = requester - # Make sure headers are signed before any operations on attributes - # Object creatation requires headers as parameter - self._headers = headers; self._initAttributes() - self._storeAndUseAttributes(attributes) + self._storeAndUseAttributes(headers, attributes) # Ask requester to do some checking, for debug and test purpose # Since it's most handy to access and kinda all-knowing - if (self.CHECK_AFTER_INIT_FLAG): - requester.check_me(self); + if self.CHECK_AFTER_INIT_FLAG: # pragma no branch (Flag always set in tests) + requester.check_me(self) - def _storeAndUseAttributes(self, attributes): - self._useAttributes(attributes) + def _storeAndUseAttributes(self, headers, attributes): + # Make sure headers are assigned before calling _useAttributes + # (Some derived classes will use headers in _useAttributes) + self._headers = headers self._rawData = attributes + self._useAttributes(attributes) @property def raw_data(self): @@ -74,6 +75,14 @@ class GithubObject(object): self._completeIfNeeded() return self._rawData + @property + def raw_headers(self): + """ + :type: dict + """ + self._completeIfNeeded() + return self._headers + @staticmethod def _parentUrl(url): return "/".join(url.split("/")[: -1]) @@ -96,6 +105,20 @@ class GithubObject(object): else: return datetime.datetime.strptime(s, "%Y-%m-%dT%H:%M:%SZ") + @property + def etag(self): + ''' + :type str + ''' + return self._headers.get(Consts.RES_ETAG) + + @property + def last_modified(self): + ''' + :type str + ''' + return self._headers.get(Consts.RES_LAST_MODIFED) + class NonCompletableGithubObject(GithubObject): def _completeIfNeeded(self): @@ -120,8 +143,34 @@ class CompletableGithubObject(GithubObject): "GET", self._url, None, + None, None ) - self._headers = headers - self._storeAndUseAttributes(data) + self._storeAndUseAttributes(headers, data) self.__completed = True + + def update(self): + ''' + Check and update the object with conditional request + :rtype: Boolean value indicating whether the object is changed + ''' + conditionalRequestHeader = dict() + if self.etag is not None: + conditionalRequestHeader[Consts.REQ_IF_NONE_MATCH] = self.etag + if self.last_modified is not None: + conditionalRequestHeader[Consts.REQ_IF_MODIFIED_SINCE] = self.last_modified + + status, responseHeaders, output = self._requester.requestJson( + "GET", + self._url, + None, + conditionalRequestHeader, + None + ) + if status == 304: + return False + else: + headers, data = self._requester._Requester__check(status, responseHeaders, output) + self._storeAndUseAttributes(headers, data) + self.__completed = True + return True diff --git a/github/Hook.py b/github/Hook.py index 721bdd7a..ea0be67b 100644 --- a/github/Hook.py +++ b/github/Hook.py @@ -115,6 +115,7 @@ class Hook(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -151,6 +152,7 @@ class Hook(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) @@ -164,6 +166,7 @@ class Hook(github.GithubObject.CompletableGithubObject): "POST", self.url + "/tests", None, + None, None ) diff --git a/github/Issue.py b/github/Issue.py index 1cdcc6bb..260967d3 100644 --- a/github/Issue.py +++ b/github/Issue.py @@ -204,6 +204,7 @@ class Issue(github.GithubObject.CompletableGithubObject): "POST", self.url + "/labels", None, + None, post_parameters ) @@ -221,6 +222,7 @@ class Issue(github.GithubObject.CompletableGithubObject): "POST", self.url + "/comments", None, + None, post_parameters ) return github.IssueComment.IssueComment(self._requester, headers, data, completed=True) @@ -234,6 +236,7 @@ class Issue(github.GithubObject.CompletableGithubObject): "DELETE", self.url + "/labels", None, + None, None ) @@ -271,6 +274,7 @@ class Issue(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) @@ -286,6 +290,7 @@ class Issue(github.GithubObject.CompletableGithubObject): "GET", self._parentUrl(self.url) + "/comments/" + str(id), None, + None, None ) return github.IssueComment.IssueComment(self._requester, headers, data, completed=True) @@ -337,6 +342,7 @@ class Issue(github.GithubObject.CompletableGithubObject): "DELETE", self.url + "/labels/" + label._identity, None, + None, None ) @@ -352,6 +358,7 @@ class Issue(github.GithubObject.CompletableGithubObject): "PUT", self.url + "/labels", None, + None, post_parameters ) diff --git a/github/IssueComment.py b/github/IssueComment.py index 5a3c62da..c1af97f8 100644 --- a/github/IssueComment.py +++ b/github/IssueComment.py @@ -100,6 +100,7 @@ class IssueComment(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -117,6 +118,7 @@ class IssueComment(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) diff --git a/github/Label.py b/github/Label.py index b3c75501..b961af18 100644 --- a/github/Label.py +++ b/github/Label.py @@ -68,6 +68,7 @@ class Label(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -88,6 +89,7 @@ class Label(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) diff --git a/github/Legacy.py b/github/Legacy.py index 1ed760e2..a0e3493f 100644 --- a/github/Legacy.py +++ b/github/Legacy.py @@ -59,6 +59,7 @@ class PaginatedList(github.PaginatedList.PaginatedListBase): "GET", self.__url, args, + None, None ) self.__continue = len(data[self.__key]) > 0 diff --git a/github/MainClass.py b/github/MainClass.py index ae1f612f..3efde171 100644 --- a/github/MainClass.py +++ b/github/MainClass.py @@ -26,6 +26,7 @@ ################################################################################ import urllib +import pickle from Requester import Requester import AuthenticatedUser @@ -106,6 +107,7 @@ class Github(object): 'GET', '/rate_limit', None, + None, None ) return self.__requester.rate_limiting @@ -121,6 +123,7 @@ class Github(object): 'GET', '/rate_limit', None, + None, None ) return self.__requester.rate_limiting_resettime @@ -146,6 +149,7 @@ class Github(object): "GET", "/users/" + login, None, + None, None ) return github.NamedUser.NamedUser(self.__requester, headers, data, completed=True) @@ -178,6 +182,7 @@ class Github(object): "GET", "/orgs/" + login, None, + None, None ) return github.Organization.Organization(self.__requester, headers, data, completed=True) @@ -192,6 +197,7 @@ class Github(object): "GET", "/repos/" + full_name, None, + None, None ) return Repository.Repository(self.__requester, headers, data, completed=True) @@ -224,6 +230,7 @@ class Github(object): "GET", "/gists/" + id, None, + None, None ) return github.Gist.Gist(self.__requester, headers, data, completed=True) @@ -286,6 +293,7 @@ class Github(object): "GET", "/legacy/user/email/" + email, None, + None, None ) return github.NamedUser.NamedUser(self.__requester, headers, Legacy.convertUser(data["user"]), completed=False) @@ -309,6 +317,7 @@ class Github(object): "POST", "/markdown", None, + None, post_parameters ) return data @@ -322,6 +331,7 @@ class Github(object): "GET", "/hooks", None, + None, None ) return [HookDescription.HookDescription(self.__requester, headers, attributes, completed=True) for attributes in data] @@ -335,6 +345,7 @@ class Github(object): "GET", "/gitignore/templates", None, + None, None ) return data @@ -349,16 +360,40 @@ class Github(object): "GET", "/gitignore/templates/" + name, None, + None, None ) return GitignoreTemplate.GitignoreTemplate(self.__requester, headers, attributes, completed=True) def create_from_raw_data(self, klass, raw_data, headers={}): """ - Creates an object from raw_data previously obtained by :attr:`github.GithubObject.GithubObject.raw_data` + Creates an object from raw_data previously obtained by :attr:`github.GithubObject.GithubObject.raw_data`, + and optionaly headers previously obtained by :attr:`github.GithubObject.GithubObject.raw_headers`. :param klass: the class of the object to create :param raw_data: dict + :param headers: dict :rtype: instance of class ``klass`` """ return klass(self.__requester, headers, raw_data, completed=True) + + def dump(self, obj, file, protocol=0): + """ + Dumps (pickles) a PyGithub object to a file-like object. + Some effort is made to not pickle sensitive informations like the Github credentials used in the :class:`Github` instance. + But NO EFFORT is made to remove sensitive information from the object's attributes. + + :param obj: the object to pickle + :param file: the file-like object to pickle to + :param protocol: the `pickling protocol `_ + """ + pickle.dump((obj.__class__, obj.raw_data, obj.raw_headers), file, protocol) + + def load(self, f): + """ + Loads (unpickles) a PyGithub object from a file-like object. + + :param f: the file-like object to unpickle from + :return: the unpickled object + """ + return self.create_from_raw_data(*pickle.load(f)) diff --git a/github/Milestone.py b/github/Milestone.py index db38437f..0f23eb78 100644 --- a/github/Milestone.py +++ b/github/Milestone.py @@ -136,6 +136,7 @@ class Milestone(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -165,6 +166,7 @@ class Milestone(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) diff --git a/github/NamedUser.py b/github/NamedUser.py index ca29d38e..435b1bf2 100644 --- a/github/NamedUser.py +++ b/github/NamedUser.py @@ -270,6 +270,7 @@ class NamedUser(github.GithubObject.CompletableGithubObject): "POST", self.url + "/gists", None, + None, post_parameters ) return github.Gist.Gist(self._requester, headers, data, completed=True) @@ -393,6 +394,7 @@ class NamedUser(github.GithubObject.CompletableGithubObject): "GET", "/repos/" + self.login + "/" + name, None, + None, None ) return github.Repository.Repository(self._requester, headers, data, completed=True) @@ -461,6 +463,7 @@ class NamedUser(github.GithubObject.CompletableGithubObject): "GET", self.url + "/following/" + following._identity, None, + None, None ) return status == 204 diff --git a/github/Organization.py b/github/Organization.py index d252a054..aa904fce 100644 --- a/github/Organization.py +++ b/github/Organization.py @@ -246,6 +246,7 @@ class Organization(github.GithubObject.CompletableGithubObject): "PUT", self.url + "/public_members/" + public_member._identity, None, + None, None ) @@ -263,6 +264,7 @@ class Organization(github.GithubObject.CompletableGithubObject): "POST", "/repos/" + repo.owner.login + "/" + repo.name + "/forks", url_parameters, + None, None ) return github.Repository.Repository(self._requester, headers, data, completed=True) @@ -317,6 +319,7 @@ class Organization(github.GithubObject.CompletableGithubObject): "POST", self.url + "/repos", None, + None, post_parameters ) return github.Repository.Repository(self._requester, headers, data, completed=True) @@ -343,6 +346,7 @@ class Organization(github.GithubObject.CompletableGithubObject): "POST", self.url + "/teams", None, + None, post_parameters ) return github.Team.Team(self._requester, headers, data, completed=True) @@ -381,6 +385,7 @@ class Organization(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) @@ -470,6 +475,7 @@ class Organization(github.GithubObject.CompletableGithubObject): "GET", "/repos/" + self.login + "/" + name, None, + None, None ) return github.Repository.Repository(self._requester, headers, data, completed=True) @@ -502,6 +508,7 @@ class Organization(github.GithubObject.CompletableGithubObject): "GET", "/teams/" + str(id), None, + None, None ) return github.Team.Team(self._requester, headers, data, completed=True) @@ -529,6 +536,7 @@ class Organization(github.GithubObject.CompletableGithubObject): "GET", self.url + "/members/" + member._identity, None, + None, None ) return status == 204 @@ -544,6 +552,7 @@ class Organization(github.GithubObject.CompletableGithubObject): "GET", self.url + "/public_members/" + public_member._identity, None, + None, None ) return status == 204 @@ -559,6 +568,7 @@ class Organization(github.GithubObject.CompletableGithubObject): "DELETE", self.url + "/members/" + member._identity, None, + None, None ) @@ -573,6 +583,7 @@ class Organization(github.GithubObject.CompletableGithubObject): "DELETE", self.url + "/public_members/" + public_member._identity, None, + None, None ) diff --git a/github/PaginatedList.py b/github/PaginatedList.py index e450dfd8..45b2546d 100644 --- a/github/PaginatedList.py +++ b/github/PaginatedList.py @@ -119,7 +119,13 @@ class PaginatedList(PaginatedListBase): self._reversed = False def _getLastPageUrl(self): - headers, data = self.__requester.requestJsonAndCheck("GET", self.__firstUrl, self.__nextParams, None) + headers, data = self.__requester.requestJsonAndCheck( + "GET", + self.__firstUrl, + self.__nextParams, + None, + None + ) links = self.__parseLinkHeader(headers) lastUrl = links.get("last") return lastUrl @@ -140,7 +146,13 @@ class PaginatedList(PaginatedListBase): return self.__nextUrl is not None def _fetchNextPage(self): - headers, data = self.__requester.requestJsonAndCheck("GET", self.__nextUrl, self.__nextParams, None) + headers, data = self.__requester.requestJsonAndCheck( + "GET", + self.__nextUrl, + self.__nextParams, + None, + None + ) self.__nextUrl = None if len(data) > 0: @@ -177,7 +189,13 @@ class PaginatedList(PaginatedListBase): params["page"] = page + 1 if self.__requester.per_page != 30: params["per_page"] = self.__requester.per_page - headers, data = self.__requester.requestJsonAndCheck("GET", self.__firstUrl, params, None) + headers, data = self.__requester.requestJsonAndCheck( + "GET", + self.__firstUrl, + params, + None, + None + ) return [ self.__contentClass(self.__requester, headers, element, completed=False) diff --git a/github/PullRequest.py b/github/PullRequest.py index 8ea72e55..2b9b022b 100644 --- a/github/PullRequest.py +++ b/github/PullRequest.py @@ -293,6 +293,7 @@ class PullRequest(github.GithubObject.CompletableGithubObject): "POST", self.url + "/comments", None, + None, post_parameters ) return github.PullRequestComment.PullRequestComment(self._requester, headers, data, completed=True) @@ -311,6 +312,7 @@ class PullRequest(github.GithubObject.CompletableGithubObject): "POST", self._parentUrl(self._parentUrl(self.url)) + "/issues/" + str(self.number) + "/comments", None, + None, post_parameters ) return github.IssueComment.IssueComment(self._requester, headers, data, completed=True) @@ -337,6 +339,7 @@ class PullRequest(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) @@ -360,6 +363,7 @@ class PullRequest(github.GithubObject.CompletableGithubObject): "GET", self._parentUrl(self.url) + "/comments/" + str(id), None, + None, None ) return github.PullRequestComment.PullRequestComment(self._requester, headers, data, completed=True) @@ -418,6 +422,7 @@ class PullRequest(github.GithubObject.CompletableGithubObject): "GET", self._parentUrl(self._parentUrl(self.url)) + "/issues/comments/" + str(id), None, + None, None ) return github.IssueComment.IssueComment(self._requester, headers, data, completed=True) @@ -443,6 +448,7 @@ class PullRequest(github.GithubObject.CompletableGithubObject): "GET", self.url + "/merge", None, + None, None ) return status == 204 @@ -461,6 +467,7 @@ class PullRequest(github.GithubObject.CompletableGithubObject): "PUT", self.url + "/merge", None, + None, post_parameters ) return github.PullRequestMergeStatus.PullRequestMergeStatus(self._requester, headers, data, completed=True) diff --git a/github/PullRequestComment.py b/github/PullRequestComment.py index efc520cf..4d250d56 100644 --- a/github/PullRequestComment.py +++ b/github/PullRequestComment.py @@ -141,6 +141,7 @@ class PullRequestComment(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -158,6 +159,7 @@ class PullRequestComment(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) diff --git a/github/Repository.py b/github/Repository.py index ed5934d5..9a62e13d 100644 --- a/github/Repository.py +++ b/github/Repository.py @@ -319,6 +319,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "PUT", self.url + "/collaborators/" + collaborator._identity, None, + None, None ) @@ -335,6 +336,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/compare/" + base + "..." + head, None, + None, None ) return github.Comparison.Comparison(self._requester, headers, data, completed=True) @@ -364,6 +366,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/downloads", None, + None, post_parameters ) return github.Download.Download(self._requester, headers, data, completed=True) @@ -385,6 +388,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/git/blobs", None, + None, post_parameters ) return github.GitBlob.GitBlob(self._requester, headers, data, completed=True) @@ -417,6 +421,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/git/commits", None, + None, post_parameters ) return github.GitCommit.GitCommit(self._requester, headers, data, completed=True) @@ -438,6 +443,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/git/refs", None, + None, post_parameters ) return github.GitRef.GitRef(self._requester, headers, data, completed=True) @@ -469,6 +475,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/git/tags", None, + None, post_parameters ) return github.GitTag.GitTag(self._requester, headers, data, completed=True) @@ -491,6 +498,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/git/trees", None, + None, post_parameters ) return github.GitTree.GitTree(self._requester, headers, data, completed=True) @@ -520,6 +528,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/hooks", None, + None, post_parameters ) return github.Hook.Hook(self._requester, headers, data, completed=True) @@ -554,6 +563,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/issues", None, + None, post_parameters ) return github.Issue.Issue(self._requester, headers, data, completed=True) @@ -575,6 +585,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/keys", None, + None, post_parameters ) return github.RepositoryKey.RepositoryKey(self._requester, headers, data, completed=True, repoUrl=self._url) @@ -596,6 +607,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/labels", None, + None, post_parameters ) return github.Label.Label(self._requester, headers, data, completed=True) @@ -626,6 +638,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/milestones", None, + None, post_parameters ) return github.Milestone.Milestone(self._requester, headers, data, completed=True) @@ -664,6 +677,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/pulls", None, + None, post_parameters ) return github.PullRequest.PullRequest(self._requester, headers, data, completed=True) @@ -677,6 +691,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -722,6 +737,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) @@ -742,6 +758,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", url, None, + None, None ) return headers["location"] @@ -769,6 +786,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/branches/" + branch, None, + None, None ) return github.Branch.Branch(self._requester, headers, data, completed=True) @@ -808,6 +826,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/comments/" + str(id), None, + None, None ) return github.CommitComment.CommitComment(self._requester, headers, data, completed=True) @@ -835,6 +854,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/commits/" + sha, None, + None, None ) return github.Commit.Commit(self._requester, headers, data, completed=True) @@ -893,6 +913,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/contents" + path, url_parameters, + None, None ) return github.ContentFile.ContentFile(self._requester, headers, data, completed=True) @@ -913,6 +934,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/contents" + path, url_parameters, + None, None ) @@ -922,6 +944,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", headers['location'], url_parameters, + None, None ) @@ -953,6 +976,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/downloads/" + str(id), None, + None, None ) return github.Download.Download(self._requester, headers, data, completed=True) @@ -1004,6 +1028,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/git/blobs/" + sha, None, + None, None ) return github.GitBlob.GitBlob(self._requester, headers, data, completed=True) @@ -1019,6 +1044,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/git/commits/" + sha, None, + None, None ) return github.GitCommit.GitCommit(self._requester, headers, data, completed=True) @@ -1037,6 +1063,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + prefix + ref, None, + None, None ) return github.GitRef.GitRef(self._requester, headers, data, completed=True) @@ -1064,6 +1091,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/git/tags/" + sha, None, + None, None ) return github.GitTag.GitTag(self._requester, headers, data, completed=True) @@ -1084,6 +1112,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/git/trees/" + sha, url_parameters, + None, None ) return github.GitTree.GitTree(self._requester, headers, data, completed=True) @@ -1099,6 +1128,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/hooks/" + str(id), None, + None, None ) return github.Hook.Hook(self._requester, headers, data, completed=True) @@ -1126,6 +1156,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/issues/" + str(number), None, + None, None ) return github.Issue.Issue(self._requester, headers, data, completed=True) @@ -1217,6 +1248,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/issues/events/" + str(id), None, + None, None ) return github.IssueEvent.IssueEvent(self._requester, headers, data, completed=True) @@ -1244,6 +1276,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/keys/" + str(id), None, + None, None ) return github.RepositoryKey.RepositoryKey(self._requester, headers, data, completed=True, repoUrl=self._url) @@ -1271,6 +1304,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/labels/" + urllib.quote(name), None, + None, None ) return github.Label.Label(self._requester, headers, data, completed=True) @@ -1296,6 +1330,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/languages", None, + None, None ) return data @@ -1311,6 +1346,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/milestones/" + str(number), None, + None, None ) return github.Milestone.Milestone(self._requester, headers, data, completed=True) @@ -1363,6 +1399,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/pulls/" + str(number), None, + None, None ) return github.PullRequest.PullRequest(self._requester, headers, data, completed=True) @@ -1433,6 +1470,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/readme", url_parameters, + None, None ) return github.ContentFile.ContentFile(self._requester, headers, data, completed=True) @@ -1508,6 +1546,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/assignees/" + assignee._identity, None, + None, None ) return status == 204 @@ -1523,6 +1562,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", self.url + "/collaborators/" + collaborator._identity, None, + None, None ) return status == 204 @@ -1540,6 +1580,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "GET", "/legacy/issues/search/" + self.owner.login + "/" + self.name + "/" + state + "/" + urllib.quote(keyword), None, + None, None ) return [ @@ -1568,6 +1609,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", self.url + "/merges", None, + None, post_parameters ) if data is None: @@ -1586,6 +1628,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "DELETE", self.url + "/collaborators/" + collaborator._identity, None, + None, None ) @@ -1627,6 +1670,7 @@ class Repository(github.GithubObject.CompletableGithubObject): "POST", "/hub", None, + None, post_parameters, ) diff --git a/github/RepositoryKey.py b/github/RepositoryKey.py index 074985d8..22b59621 100644 --- a/github/RepositoryKey.py +++ b/github/RepositoryKey.py @@ -91,6 +91,7 @@ class RepositoryKey(github.GithubObject.CompletableGithubObject): "DELETE", self.__customUrl, None, + None, None ) @@ -112,6 +113,7 @@ class RepositoryKey(github.GithubObject.CompletableGithubObject): "PATCH", self.__customUrl, None, + None, post_parameters ) self._useAttributes(data) diff --git a/github/Requester.py b/github/Requester.py index c2e53b91..27f871e5 100644 --- a/github/Requester.py +++ b/github/Requester.py @@ -38,6 +38,7 @@ import base64 import urllib import urlparse import sys +import Consts atLeastPython26 = sys.hexversion >= 0x02060000 atLeastPython3 = sys.hexversion >= 0x03000000 @@ -89,30 +90,26 @@ class Requester: The structure of a frame: [requestHeader, statusCode, responseHeader, raw_data] Some of them may be None ''' - if not self.DEBUG_FLAG: - return + if self.DEBUG_FLAG: # pragma no branch (Flag always set in tests) + new_frame = [requestHeader, None, None, None] + if self._frameCount < self.DEBUG_FRAME_BUFFER_SIZE - 1: # pragma no branch (Should be covered) + self._frameBuffer.append(new_frame) + else: + self._frameBuffer[0] = new_frame # pragma no cover (Should be covered) - new_frame = [requestHeader, None, None, None] - if self._frameCount < self.DEBUG_FRAME_BUFFER_SIZE - 1: - self._frameBuffer.append(new_frame) - else: - self._frameBuffer[0] = new_frame - - self._frameCount = len(self._frameBuffer) - 1 + self._frameCount = len(self._frameBuffer) - 1 def DEBUG_ON_RESPONSE(self, statusCode, responseHeader, data): ''' Update current frame with response Current frame index will be attached to responseHeader ''' - if not self.DEBUG_FLAG: - return - - self._frameBuffer[self._frameCount][1:4] = [statusCode, responseHeader, data] - responseHeader[self.DEBUG_HEADER_KEY] = self._frameCount + if self.DEBUG_FLAG: # pragma no branch (Flag always set in tests) + self._frameBuffer[self._frameCount][1:4] = [statusCode, responseHeader, data] + responseHeader[self.DEBUG_HEADER_KEY] = self._frameCount def check_me(self, obj): - if self.DEBUG_FLAG and self.ON_CHECK_ME is not None: + if self.DEBUG_FLAG and self.ON_CHECK_ME is not None: # pragma no branch (Flag always set in tests) frame = None if self.DEBUG_HEADER_KEY in obj._headers: frame_index = obj._headers[self.DEBUG_HEADER_KEY] @@ -167,17 +164,14 @@ class Requester: 'See http://developer.github.com/v3/#user-agent-required' self.__userAgent = user_agent - def requestJsonAndCheck(self, verb, url, parameters, input): - return self.__check(*self.requestJson(verb, url, parameters, input)) + def requestJsonAndCheck(self, verb, url, parameters, headers, input): + return self.__check(*self.requestJson(verb, url, parameters, headers, input)) - def requestMultipartAndCheck(self, verb, url, parameters, input): - return self.__check(*self.requestMultipart(verb, url, parameters, input)) + def requestMultipartAndCheck(self, verb, url, parameters, headers, input): + return self.__check(*self.requestMultipart(verb, url, parameters, headers, input)) def __check(self, status, responseHeaders, output): output = self.__structuredFromJson(output) - # Log frame - self.DEBUG_ON_RESPONSE(status, responseHeaders, output) - if status >= 400: raise self.__createException(status, output) return responseHeaders, output @@ -206,13 +200,13 @@ class Requester: except ValueError, e: return {'data': data} - def requestJson(self, verb, url, parameters, input): + def requestJson(self, verb, url, parameters, headers, input): def encode(input): return "application/json", json.dumps(input) - return self.__requestEncode(verb, url, parameters, input, encode) + return self.__requestEncode(verb, url, parameters, headers, input, encode) - def requestMultipart(self, verb, url, parameters, input): + def requestMultipart(self, verb, url, parameters, headers, input): def encode(input): boundary = "----------------------------3c3ba8b523b2" eol = "\r\n" @@ -226,14 +220,15 @@ class Requester: encoded_input += "--" + boundary + "--" + eol return "multipart/form-data; boundary=" + boundary, encoded_input - return self.__requestEncode(verb, url, parameters, input, encode) + return self.__requestEncode(verb, url, parameters, headers, input, encode) - def __requestEncode(self, verb, url, parameters, input, encode): + def __requestEncode(self, verb, url, parameters, requestHeaders, input, encode): assert verb in ["HEAD", "GET", "POST", "PATCH", "PUT", "DELETE"] if parameters is None: parameters = dict() + if requestHeaders is None: + requestHeaders = dict() - requestHeaders = dict() self.__authenticate(url, requestHeaders, parameters) requestHeaders["User-Agent"] = self.__userAgent @@ -256,6 +251,8 @@ class Requester: if "x-oauth-scopes" in responseHeaders: self.oauth_scopes = responseHeaders["x-oauth-scopes"].split(", ") + self.DEBUG_ON_RESPONSE(status, responseHeaders, output) + return status, responseHeaders, output def __requestRaw(self, verb, url, requestHeaders, input): diff --git a/github/Team.py b/github/Team.py index 804ed3ab..d8fb7379 100644 --- a/github/Team.py +++ b/github/Team.py @@ -96,6 +96,7 @@ class Team(github.GithubObject.CompletableGithubObject): "PUT", self.url + "/members/" + member._identity, None, + None, None ) @@ -110,6 +111,7 @@ class Team(github.GithubObject.CompletableGithubObject): "PUT", self.url + "/repos/" + repo._identity, None, + None, None ) @@ -122,6 +124,7 @@ class Team(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -143,6 +146,7 @@ class Team(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) @@ -182,6 +186,7 @@ class Team(github.GithubObject.CompletableGithubObject): "GET", self.url + "/members/" + member._identity, None, + None, None ) return status == 204 @@ -197,6 +202,7 @@ class Team(github.GithubObject.CompletableGithubObject): "GET", self.url + "/repos/" + repo._identity, None, + None, None ) return status == 204 @@ -212,6 +218,7 @@ class Team(github.GithubObject.CompletableGithubObject): "DELETE", self.url + "/members/" + member._identity, None, + None, None ) @@ -226,6 +233,7 @@ class Team(github.GithubObject.CompletableGithubObject): "DELETE", self.url + "/repos/" + repo._identity, None, + None, None ) diff --git a/github/UserKey.py b/github/UserKey.py index 44cc5808..83a26009 100644 --- a/github/UserKey.py +++ b/github/UserKey.py @@ -82,6 +82,7 @@ class UserKey(github.GithubObject.CompletableGithubObject): "DELETE", self.url, None, + None, None ) @@ -103,6 +104,7 @@ class UserKey(github.GithubObject.CompletableGithubObject): "PATCH", self.url, None, + None, post_parameters ) self._useAttributes(data) diff --git a/github/tests/AllTests.py b/github/tests/AllTests.py index a9e156ff..5c2ce6da 100644 --- a/github/tests/AllTests.py +++ b/github/tests/AllTests.py @@ -79,3 +79,6 @@ from Issue140 import * # from Issue142 import * # Deactivated for Travis-CI because Github has lowered the rate limitations from Issue158 import * from Issue174 import * + +from ConditionalRequestUpdate import ConditionalRequestUpdate +from Persistence import Persistence diff --git a/github/tests/ConditionalRequestUpdate.py b/github/tests/ConditionalRequestUpdate.py new file mode 100644 index 00000000..bfd3f87d --- /dev/null +++ b/github/tests/ConditionalRequestUpdate.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +############################ Copyrights and license ############################ +# # +# Copyright 2013 AKFish # +# # +# 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 . # +# # +################################################################################ + +# #193: Line endings should be linux style + +import Framework +import github + + +class ConditionalRequestUpdate(Framework.TestCase): + def setUp(self): + Framework.TestCase.setUp(self) + self.repo = self.g.get_repo("akfish/PyGithub") + + def testDidNotUpdate(self): + self.assertFalse(self.repo.update(), msg="The repo is not changes. But update() != False") + + def testDidUpdate(self): + self.assertTrue(self.repo.update(), msg="The repo should be changed by now. But update() != True") + + def testUpdateObjectWithoutEtag(self): + r = self.g.get_repo("jacquev6/PyGithub") + self.assertTrue(r.update()) diff --git a/github/tests/Persistence.py b/github/tests/Persistence.py new file mode 100644 index 00000000..c20f9a7c --- /dev/null +++ b/github/tests/Persistence.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- + +############################ Copyrights and license ############################ +# # +# Copyright 2013 Vincent Jacques # +# # +# 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 Framework +import github + +if Framework.atLeastPython26: + from io import BytesIO as IO +else: + from StringIO import StringIO as IO + +class Persistence(Framework.TestCase): + def setUp(self): + Framework.TestCase.setUp(self) + self.repo = self.g.get_repo("akfish/PyGithub") + + self.dumpedRepo = IO() + self.g.dump(self.repo, self.dumpedRepo) + self.dumpedRepo.seek(0) + + def tearDown(self): + self.dumpedRepo.close() + + def testLoad(self): + loadedRepo = self.g.load(self.dumpedRepo) + self.assertTrue(isinstance(loadedRepo, github.Repository.Repository)) + self.assertTrue(loadedRepo._requester is self.repo._requester) + self.assertTrue(loadedRepo.owner._requester is self.repo._requester) + self.assertEqual(loadedRepo.name, "PyGithub") + self.assertEqual(loadedRepo.url, "https://api.github.com/repos/akfish/PyGithub") + + def testLoadAndUpdate(self): + loadedRepo = self.g.load(self.dumpedRepo) + self.assertTrue(loadedRepo.update()) diff --git a/github/tests/ReplayData/ConditionalRequestUpdate.setUp.txt b/github/tests/ReplayData/ConditionalRequestUpdate.setUp.txt new file mode 100644 index 00000000..dfc62ba2 --- /dev/null +++ b/github/tests/ReplayData/ConditionalRequestUpdate.setUp.txt @@ -0,0 +1,11 @@ +https +GET +api.github.com +None +/repos/akfish/PyGithub +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +null +200 +[('status', '200 OK'), ('x-ratelimit-remaining', '4988'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes'), ('access-control-allow-credentials', 'true'), ('vary', 'Accept, Authorization, Cookie, Accept-Encoding'), ('content-length', '13698'), ('server', 'GitHub.com'), ('last-modified', 'Thu, 22 Aug 2013 02:09:11 GMT'), ('x-ratelimit-limit', '5000'), ('etag', '"8600bedcb7fed1d8065e1693e05529ce"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('date', 'Thu, 22 Aug 2013 02:13:08 GMT'), ('access-control-allow-origin', '*'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1377140429')] +{"id":12156762,"name":"PyGithub","full_name":"akfish/PyGithub","owner":{"login":"akfish","id":922715,"avatar_url":"https://1.gravatar.com/avatar/12a1b44d4e5c19cee59618084602b112?d=https%3A%2F%2Fidenticons.github.com%2F6eb90fb68a77fb5a5a997c6264bedf35.png","gravatar_id":"12a1b44d4e5c19cee59618084602b112","url":"https://api.github.com/users/akfish","html_url":"https://github.com/akfish","followers_url":"https://api.github.com/users/akfish/followers","following_url":"https://api.github.com/users/akfish/following{/other_user}","gists_url":"https://api.github.com/users/akfish/gists{/gist_id}","starred_url":"https://api.github.com/users/akfish/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akfish/subscriptions","organizations_url":"https://api.github.com/users/akfish/orgs","repos_url":"https://api.github.com/users/akfish/repos","events_url":"https://api.github.com/users/akfish/events{/privacy}","received_events_url":"https://api.github.com/users/akfish/received_events","type":"User"},"private":false,"html_url":"https://github.com/akfish/PyGithub","description":"Python library implementing the full Github API v3","fork":true,"url":"https://api.github.com/repos/akfish/PyGithub","forks_url":"https://api.github.com/repos/akfish/PyGithub/forks","keys_url":"https://api.github.com/repos/akfish/PyGithub/keys{/key_id}","collaborators_url":"https://api.github.com/repos/akfish/PyGithub/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/akfish/PyGithub/teams","hooks_url":"https://api.github.com/repos/akfish/PyGithub/hooks","issue_events_url":"https://api.github.com/repos/akfish/PyGithub/issues/events{/number}","events_url":"https://api.github.com/repos/akfish/PyGithub/events","assignees_url":"https://api.github.com/repos/akfish/PyGithub/assignees{/user}","branches_url":"https://api.github.com/repos/akfish/PyGithub/branches{/branch}","tags_url":"https://api.github.com/repos/akfish/PyGithub/tags","blobs_url":"https://api.github.com/repos/akfish/PyGithub/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/akfish/PyGithub/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/akfish/PyGithub/git/refs{/sha}","trees_url":"https://api.github.com/repos/akfish/PyGithub/git/trees{/sha}","statuses_url":"https://api.github.com/repos/akfish/PyGithub/statuses/{sha}","languages_url":"https://api.github.com/repos/akfish/PyGithub/languages","stargazers_url":"https://api.github.com/repos/akfish/PyGithub/stargazers","contributors_url":"https://api.github.com/repos/akfish/PyGithub/contributors","subscribers_url":"https://api.github.com/repos/akfish/PyGithub/subscribers","subscription_url":"https://api.github.com/repos/akfish/PyGithub/subscription","commits_url":"https://api.github.com/repos/akfish/PyGithub/commits{/sha}","git_commits_url":"https://api.github.com/repos/akfish/PyGithub/git/commits{/sha}","comments_url":"https://api.github.com/repos/akfish/PyGithub/comments{/number}","issue_comment_url":"https://api.github.com/repos/akfish/PyGithub/issues/comments/{number}","contents_url":"https://api.github.com/repos/akfish/PyGithub/contents/{+path}","compare_url":"https://api.github.com/repos/akfish/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/akfish/PyGithub/merges","archive_url":"https://api.github.com/repos/akfish/PyGithub/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/akfish/PyGithub/downloads","issues_url":"https://api.github.com/repos/akfish/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/akfish/PyGithub/pulls{/number}","milestones_url":"https://api.github.com/repos/akfish/PyGithub/milestones{/number}","notifications_url":"https://api.github.com/repos/akfish/PyGithub/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/akfish/PyGithub/labels{/name}","created_at":"2013-08-16T10:56:11Z","updated_at":"2013-08-22T02:09:11Z","pushed_at":"2013-08-22T02:09:09Z","git_url":"git://github.com/akfish/PyGithub.git","ssh_url":"git@github.com:akfish/PyGithub.git","clone_url":"https://github.com/akfish/PyGithub.git","svn_url":"https://github.com/akfish/PyGithub","homepage":"http://jacquev6.github.com/PyGithub","size":6736,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"master_branch":"master","default_branch":"master","permissions":{"admin":true,"push":true,"pull":true},"network_count":70,"parent":{"id":3544490,"name":"PyGithub","full_name":"jacquev6/PyGithub","owner":{"login":"jacquev6","id":327146,"avatar_url":"https://0.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https%3A%2F%2Fidenticons.github.com%2Ffadfb5f7088ef66579d198a3c9a4935e.png","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","url":"https://api.github.com/users/jacquev6","html_url":"https://github.com/jacquev6","followers_url":"https://api.github.com/users/jacquev6/followers","following_url":"https://api.github.com/users/jacquev6/following{/other_user}","gists_url":"https://api.github.com/users/jacquev6/gists{/gist_id}","starred_url":"https://api.github.com/users/jacquev6/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacquev6/subscriptions","organizations_url":"https://api.github.com/users/jacquev6/orgs","repos_url":"https://api.github.com/users/jacquev6/repos","events_url":"https://api.github.com/users/jacquev6/events{/privacy}","received_events_url":"https://api.github.com/users/jacquev6/received_events","type":"User"},"private":false,"html_url":"https://github.com/jacquev6/PyGithub","description":"Python library implementing the full Github API v3","fork":false,"url":"https://api.github.com/repos/jacquev6/PyGithub","forks_url":"https://api.github.com/repos/jacquev6/PyGithub/forks","keys_url":"https://api.github.com/repos/jacquev6/PyGithub/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jacquev6/PyGithub/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jacquev6/PyGithub/teams","hooks_url":"https://api.github.com/repos/jacquev6/PyGithub/hooks","issue_events_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/events{/number}","events_url":"https://api.github.com/repos/jacquev6/PyGithub/events","assignees_url":"https://api.github.com/repos/jacquev6/PyGithub/assignees{/user}","branches_url":"https://api.github.com/repos/jacquev6/PyGithub/branches{/branch}","tags_url":"https://api.github.com/repos/jacquev6/PyGithub/tags","blobs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jacquev6/PyGithub/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/refs{/sha}","trees_url":"https://api.github.com/repos/jacquev6/PyGithub/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jacquev6/PyGithub/statuses/{sha}","languages_url":"https://api.github.com/repos/jacquev6/PyGithub/languages","stargazers_url":"https://api.github.com/repos/jacquev6/PyGithub/stargazers","contributors_url":"https://api.github.com/repos/jacquev6/PyGithub/contributors","subscribers_url":"https://api.github.com/repos/jacquev6/PyGithub/subscribers","subscription_url":"https://api.github.com/repos/jacquev6/PyGithub/subscription","commits_url":"https://api.github.com/repos/jacquev6/PyGithub/commits{/sha}","git_commits_url":"https://api.github.com/repos/jacquev6/PyGithub/git/commits{/sha}","comments_url":"https://api.github.com/repos/jacquev6/PyGithub/comments{/number}","issue_comment_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/comments/{number}","contents_url":"https://api.github.com/repos/jacquev6/PyGithub/contents/{+path}","compare_url":"https://api.github.com/repos/jacquev6/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jacquev6/PyGithub/merges","archive_url":"https://api.github.com/repos/jacquev6/PyGithub/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jacquev6/PyGithub/downloads","issues_url":"https://api.github.com/repos/jacquev6/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/jacquev6/PyGithub/pulls{/number}","milestones_url":"https://api.github.com/repos/jacquev6/PyGithub/milestones{/number}","notifications_url":"https://api.github.com/repos/jacquev6/PyGithub/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jacquev6/PyGithub/labels{/name}","created_at":"2012-02-25T12:53:47Z","updated_at":"2013-08-21T20:32:08Z","pushed_at":"2013-08-21T20:31:45Z","git_url":"git://github.com/jacquev6/PyGithub.git","ssh_url":"git@github.com:jacquev6/PyGithub.git","clone_url":"https://github.com/jacquev6/PyGithub.git","svn_url":"https://github.com/jacquev6/PyGithub","homepage":"http://jacquev6.github.com/PyGithub","size":7437,"watchers_count":248,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":70,"mirror_url":null,"open_issues_count":17,"forks":70,"open_issues":17,"watchers":248,"master_branch":"master","default_branch":"master"},"source":{"id":3544490,"name":"PyGithub","full_name":"jacquev6/PyGithub","owner":{"login":"jacquev6","id":327146,"avatar_url":"https://0.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https%3A%2F%2Fidenticons.github.com%2Ffadfb5f7088ef66579d198a3c9a4935e.png","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","url":"https://api.github.com/users/jacquev6","html_url":"https://github.com/jacquev6","followers_url":"https://api.github.com/users/jacquev6/followers","following_url":"https://api.github.com/users/jacquev6/following{/other_user}","gists_url":"https://api.github.com/users/jacquev6/gists{/gist_id}","starred_url":"https://api.github.com/users/jacquev6/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacquev6/subscriptions","organizations_url":"https://api.github.com/users/jacquev6/orgs","repos_url":"https://api.github.com/users/jacquev6/repos","events_url":"https://api.github.com/users/jacquev6/events{/privacy}","received_events_url":"https://api.github.com/users/jacquev6/received_events","type":"User"},"private":false,"html_url":"https://github.com/jacquev6/PyGithub","description":"Python library implementing the full Github API v3","fork":false,"url":"https://api.github.com/repos/jacquev6/PyGithub","forks_url":"https://api.github.com/repos/jacquev6/PyGithub/forks","keys_url":"https://api.github.com/repos/jacquev6/PyGithub/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jacquev6/PyGithub/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jacquev6/PyGithub/teams","hooks_url":"https://api.github.com/repos/jacquev6/PyGithub/hooks","issue_events_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/events{/number}","events_url":"https://api.github.com/repos/jacquev6/PyGithub/events","assignees_url":"https://api.github.com/repos/jacquev6/PyGithub/assignees{/user}","branches_url":"https://api.github.com/repos/jacquev6/PyGithub/branches{/branch}","tags_url":"https://api.github.com/repos/jacquev6/PyGithub/tags","blobs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jacquev6/PyGithub/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/refs{/sha}","trees_url":"https://api.github.com/repos/jacquev6/PyGithub/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jacquev6/PyGithub/statuses/{sha}","languages_url":"https://api.github.com/repos/jacquev6/PyGithub/languages","stargazers_url":"https://api.github.com/repos/jacquev6/PyGithub/stargazers","contributors_url":"https://api.github.com/repos/jacquev6/PyGithub/contributors","subscribers_url":"https://api.github.com/repos/jacquev6/PyGithub/subscribers","subscription_url":"https://api.github.com/repos/jacquev6/PyGithub/subscription","commits_url":"https://api.github.com/repos/jacquev6/PyGithub/commits{/sha}","git_commits_url":"https://api.github.com/repos/jacquev6/PyGithub/git/commits{/sha}","comments_url":"https://api.github.com/repos/jacquev6/PyGithub/comments{/number}","issue_comment_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/comments/{number}","contents_url":"https://api.github.com/repos/jacquev6/PyGithub/contents/{+path}","compare_url":"https://api.github.com/repos/jacquev6/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jacquev6/PyGithub/merges","archive_url":"https://api.github.com/repos/jacquev6/PyGithub/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jacquev6/PyGithub/downloads","issues_url":"https://api.github.com/repos/jacquev6/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/jacquev6/PyGithub/pulls{/number}","milestones_url":"https://api.github.com/repos/jacquev6/PyGithub/milestones{/number}","notifications_url":"https://api.github.com/repos/jacquev6/PyGithub/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jacquev6/PyGithub/labels{/name}","created_at":"2012-02-25T12:53:47Z","updated_at":"2013-08-21T20:32:08Z","pushed_at":"2013-08-21T20:31:45Z","git_url":"git://github.com/jacquev6/PyGithub.git","ssh_url":"git@github.com:jacquev6/PyGithub.git","clone_url":"https://github.com/jacquev6/PyGithub.git","svn_url":"https://github.com/jacquev6/PyGithub","homepage":"http://jacquev6.github.com/PyGithub","size":7437,"watchers_count":248,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":70,"mirror_url":null,"open_issues_count":17,"forks":70,"open_issues":17,"watchers":248,"master_branch":"master","default_branch":"master"}} + diff --git a/github/tests/ReplayData/ConditionalRequestUpdate.testDidNotUpdate.txt b/github/tests/ReplayData/ConditionalRequestUpdate.testDidNotUpdate.txt new file mode 100755 index 00000000..025aee8c --- /dev/null +++ b/github/tests/ReplayData/ConditionalRequestUpdate.testDidNotUpdate.txt @@ -0,0 +1,11 @@ +https +GET +api.github.com +None +/repos/akfish/PyGithub +{'If-None-Match': '"8600bedcb7fed1d8065e1693e05529ce"', 'User-Agent': 'PyGithub/Python', 'Authorization': 'Basic login_and_password_removed', 'If-Modified-Since': 'Thu, 22 Aug 2013 02:09:11 GMT'} +null +304 +[('status', '304 Not Modified'), ('x-ratelimit-remaining', '4988'), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes'), ('access-control-allow-credentials', 'true'), ('vary', 'Accept-Encoding'), ('server', 'GitHub.com'), ('last-modified', 'Thu, 22 Aug 2013 02:09:11 GMT'), ('x-ratelimit-limit', '5000'), ('etag', '"8600bedcb7fed1d8065e1693e05529ce"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('date', 'Thu, 22 Aug 2013 02:13:10 GMT'), ('access-control-allow-origin', '*'), ('x-ratelimit-reset', '1377140429')] + + diff --git a/github/tests/ReplayData/ConditionalRequestUpdate.testDidUpdate.txt b/github/tests/ReplayData/ConditionalRequestUpdate.testDidUpdate.txt new file mode 100644 index 00000000..b6d8aeec --- /dev/null +++ b/github/tests/ReplayData/ConditionalRequestUpdate.testDidUpdate.txt @@ -0,0 +1,11 @@ +https +GET +api.github.com +None +/repos/akfish/PyGithub +{'If-None-Match': '"8600bedcb7fed1d8065e1693e05529ce"', 'User-Agent': 'PyGithub/Python', 'Authorization': 'Basic login_and_password_removed', 'If-Modified-Since': 'Thu, 22 Aug 2013 02:09:11 GMT'} +null +200 +[('status', '200 OK'), ('x-ratelimit-remaining', '4987'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes'), ('access-control-allow-credentials', 'true'), ('vary', 'Accept, Authorization, Cookie, Accept-Encoding'), ('content-length', '13712'), ('server', 'GitHub.com'), ('last-modified', 'Thu, 22 Aug 2013 02:14:54 GMT'), ('x-ratelimit-limit', '5000'), ('etag', '"ef281ef0e821c18f80da36902727160b"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('date', 'Thu, 22 Aug 2013 02:15:01 GMT'), ('access-control-allow-origin', '*'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1377140429')] +{"id":12156762,"name":"PyGithub","full_name":"akfish/PyGithub","owner":{"login":"akfish","id":922715,"avatar_url":"https://0.gravatar.com/avatar/12a1b44d4e5c19cee59618084602b112?d=https%3A%2F%2Fidenticons.github.com%2F6eb90fb68a77fb5a5a997c6264bedf35.png","gravatar_id":"12a1b44d4e5c19cee59618084602b112","url":"https://api.github.com/users/akfish","html_url":"https://github.com/akfish","followers_url":"https://api.github.com/users/akfish/followers","following_url":"https://api.github.com/users/akfish/following{/other_user}","gists_url":"https://api.github.com/users/akfish/gists{/gist_id}","starred_url":"https://api.github.com/users/akfish/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akfish/subscriptions","organizations_url":"https://api.github.com/users/akfish/orgs","repos_url":"https://api.github.com/users/akfish/repos","events_url":"https://api.github.com/users/akfish/events{/privacy}","received_events_url":"https://api.github.com/users/akfish/received_events","type":"User"},"private":false,"html_url":"https://github.com/akfish/PyGithub","description":"Python library implementing the full Github API v3 - AKFish Fork","fork":true,"url":"https://api.github.com/repos/akfish/PyGithub","forks_url":"https://api.github.com/repos/akfish/PyGithub/forks","keys_url":"https://api.github.com/repos/akfish/PyGithub/keys{/key_id}","collaborators_url":"https://api.github.com/repos/akfish/PyGithub/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/akfish/PyGithub/teams","hooks_url":"https://api.github.com/repos/akfish/PyGithub/hooks","issue_events_url":"https://api.github.com/repos/akfish/PyGithub/issues/events{/number}","events_url":"https://api.github.com/repos/akfish/PyGithub/events","assignees_url":"https://api.github.com/repos/akfish/PyGithub/assignees{/user}","branches_url":"https://api.github.com/repos/akfish/PyGithub/branches{/branch}","tags_url":"https://api.github.com/repos/akfish/PyGithub/tags","blobs_url":"https://api.github.com/repos/akfish/PyGithub/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/akfish/PyGithub/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/akfish/PyGithub/git/refs{/sha}","trees_url":"https://api.github.com/repos/akfish/PyGithub/git/trees{/sha}","statuses_url":"https://api.github.com/repos/akfish/PyGithub/statuses/{sha}","languages_url":"https://api.github.com/repos/akfish/PyGithub/languages","stargazers_url":"https://api.github.com/repos/akfish/PyGithub/stargazers","contributors_url":"https://api.github.com/repos/akfish/PyGithub/contributors","subscribers_url":"https://api.github.com/repos/akfish/PyGithub/subscribers","subscription_url":"https://api.github.com/repos/akfish/PyGithub/subscription","commits_url":"https://api.github.com/repos/akfish/PyGithub/commits{/sha}","git_commits_url":"https://api.github.com/repos/akfish/PyGithub/git/commits{/sha}","comments_url":"https://api.github.com/repos/akfish/PyGithub/comments{/number}","issue_comment_url":"https://api.github.com/repos/akfish/PyGithub/issues/comments/{number}","contents_url":"https://api.github.com/repos/akfish/PyGithub/contents/{+path}","compare_url":"https://api.github.com/repos/akfish/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/akfish/PyGithub/merges","archive_url":"https://api.github.com/repos/akfish/PyGithub/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/akfish/PyGithub/downloads","issues_url":"https://api.github.com/repos/akfish/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/akfish/PyGithub/pulls{/number}","milestones_url":"https://api.github.com/repos/akfish/PyGithub/milestones{/number}","notifications_url":"https://api.github.com/repos/akfish/PyGithub/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/akfish/PyGithub/labels{/name}","created_at":"2013-08-16T10:56:11Z","updated_at":"2013-08-22T02:14:54Z","pushed_at":"2013-08-22T02:09:09Z","git_url":"git://github.com/akfish/PyGithub.git","ssh_url":"git@github.com:akfish/PyGithub.git","clone_url":"https://github.com/akfish/PyGithub.git","svn_url":"https://github.com/akfish/PyGithub","homepage":"http://jacquev6.github.com/PyGithub","size":6736,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"master_branch":"master","default_branch":"master","permissions":{"admin":true,"push":true,"pull":true},"network_count":70,"parent":{"id":3544490,"name":"PyGithub","full_name":"jacquev6/PyGithub","owner":{"login":"jacquev6","id":327146,"avatar_url":"https://0.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https%3A%2F%2Fidenticons.github.com%2Ffadfb5f7088ef66579d198a3c9a4935e.png","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","url":"https://api.github.com/users/jacquev6","html_url":"https://github.com/jacquev6","followers_url":"https://api.github.com/users/jacquev6/followers","following_url":"https://api.github.com/users/jacquev6/following{/other_user}","gists_url":"https://api.github.com/users/jacquev6/gists{/gist_id}","starred_url":"https://api.github.com/users/jacquev6/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacquev6/subscriptions","organizations_url":"https://api.github.com/users/jacquev6/orgs","repos_url":"https://api.github.com/users/jacquev6/repos","events_url":"https://api.github.com/users/jacquev6/events{/privacy}","received_events_url":"https://api.github.com/users/jacquev6/received_events","type":"User"},"private":false,"html_url":"https://github.com/jacquev6/PyGithub","description":"Python library implementing the full Github API v3","fork":false,"url":"https://api.github.com/repos/jacquev6/PyGithub","forks_url":"https://api.github.com/repos/jacquev6/PyGithub/forks","keys_url":"https://api.github.com/repos/jacquev6/PyGithub/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jacquev6/PyGithub/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jacquev6/PyGithub/teams","hooks_url":"https://api.github.com/repos/jacquev6/PyGithub/hooks","issue_events_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/events{/number}","events_url":"https://api.github.com/repos/jacquev6/PyGithub/events","assignees_url":"https://api.github.com/repos/jacquev6/PyGithub/assignees{/user}","branches_url":"https://api.github.com/repos/jacquev6/PyGithub/branches{/branch}","tags_url":"https://api.github.com/repos/jacquev6/PyGithub/tags","blobs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jacquev6/PyGithub/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/refs{/sha}","trees_url":"https://api.github.com/repos/jacquev6/PyGithub/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jacquev6/PyGithub/statuses/{sha}","languages_url":"https://api.github.com/repos/jacquev6/PyGithub/languages","stargazers_url":"https://api.github.com/repos/jacquev6/PyGithub/stargazers","contributors_url":"https://api.github.com/repos/jacquev6/PyGithub/contributors","subscribers_url":"https://api.github.com/repos/jacquev6/PyGithub/subscribers","subscription_url":"https://api.github.com/repos/jacquev6/PyGithub/subscription","commits_url":"https://api.github.com/repos/jacquev6/PyGithub/commits{/sha}","git_commits_url":"https://api.github.com/repos/jacquev6/PyGithub/git/commits{/sha}","comments_url":"https://api.github.com/repos/jacquev6/PyGithub/comments{/number}","issue_comment_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/comments/{number}","contents_url":"https://api.github.com/repos/jacquev6/PyGithub/contents/{+path}","compare_url":"https://api.github.com/repos/jacquev6/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jacquev6/PyGithub/merges","archive_url":"https://api.github.com/repos/jacquev6/PyGithub/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jacquev6/PyGithub/downloads","issues_url":"https://api.github.com/repos/jacquev6/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/jacquev6/PyGithub/pulls{/number}","milestones_url":"https://api.github.com/repos/jacquev6/PyGithub/milestones{/number}","notifications_url":"https://api.github.com/repos/jacquev6/PyGithub/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jacquev6/PyGithub/labels{/name}","created_at":"2012-02-25T12:53:47Z","updated_at":"2013-08-21T20:32:08Z","pushed_at":"2013-08-21T20:31:45Z","git_url":"git://github.com/jacquev6/PyGithub.git","ssh_url":"git@github.com:jacquev6/PyGithub.git","clone_url":"https://github.com/jacquev6/PyGithub.git","svn_url":"https://github.com/jacquev6/PyGithub","homepage":"http://jacquev6.github.com/PyGithub","size":7437,"watchers_count":248,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":70,"mirror_url":null,"open_issues_count":17,"forks":70,"open_issues":17,"watchers":248,"master_branch":"master","default_branch":"master"},"source":{"id":3544490,"name":"PyGithub","full_name":"jacquev6/PyGithub","owner":{"login":"jacquev6","id":327146,"avatar_url":"https://0.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https%3A%2F%2Fidenticons.github.com%2Ffadfb5f7088ef66579d198a3c9a4935e.png","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","url":"https://api.github.com/users/jacquev6","html_url":"https://github.com/jacquev6","followers_url":"https://api.github.com/users/jacquev6/followers","following_url":"https://api.github.com/users/jacquev6/following{/other_user}","gists_url":"https://api.github.com/users/jacquev6/gists{/gist_id}","starred_url":"https://api.github.com/users/jacquev6/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacquev6/subscriptions","organizations_url":"https://api.github.com/users/jacquev6/orgs","repos_url":"https://api.github.com/users/jacquev6/repos","events_url":"https://api.github.com/users/jacquev6/events{/privacy}","received_events_url":"https://api.github.com/users/jacquev6/received_events","type":"User"},"private":false,"html_url":"https://github.com/jacquev6/PyGithub","description":"Python library implementing the full Github API v3","fork":false,"url":"https://api.github.com/repos/jacquev6/PyGithub","forks_url":"https://api.github.com/repos/jacquev6/PyGithub/forks","keys_url":"https://api.github.com/repos/jacquev6/PyGithub/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jacquev6/PyGithub/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jacquev6/PyGithub/teams","hooks_url":"https://api.github.com/repos/jacquev6/PyGithub/hooks","issue_events_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/events{/number}","events_url":"https://api.github.com/repos/jacquev6/PyGithub/events","assignees_url":"https://api.github.com/repos/jacquev6/PyGithub/assignees{/user}","branches_url":"https://api.github.com/repos/jacquev6/PyGithub/branches{/branch}","tags_url":"https://api.github.com/repos/jacquev6/PyGithub/tags","blobs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jacquev6/PyGithub/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/refs{/sha}","trees_url":"https://api.github.com/repos/jacquev6/PyGithub/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jacquev6/PyGithub/statuses/{sha}","languages_url":"https://api.github.com/repos/jacquev6/PyGithub/languages","stargazers_url":"https://api.github.com/repos/jacquev6/PyGithub/stargazers","contributors_url":"https://api.github.com/repos/jacquev6/PyGithub/contributors","subscribers_url":"https://api.github.com/repos/jacquev6/PyGithub/subscribers","subscription_url":"https://api.github.com/repos/jacquev6/PyGithub/subscription","commits_url":"https://api.github.com/repos/jacquev6/PyGithub/commits{/sha}","git_commits_url":"https://api.github.com/repos/jacquev6/PyGithub/git/commits{/sha}","comments_url":"https://api.github.com/repos/jacquev6/PyGithub/comments{/number}","issue_comment_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/comments/{number}","contents_url":"https://api.github.com/repos/jacquev6/PyGithub/contents/{+path}","compare_url":"https://api.github.com/repos/jacquev6/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jacquev6/PyGithub/merges","archive_url":"https://api.github.com/repos/jacquev6/PyGithub/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jacquev6/PyGithub/downloads","issues_url":"https://api.github.com/repos/jacquev6/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/jacquev6/PyGithub/pulls{/number}","milestones_url":"https://api.github.com/repos/jacquev6/PyGithub/milestones{/number}","notifications_url":"https://api.github.com/repos/jacquev6/PyGithub/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jacquev6/PyGithub/labels{/name}","created_at":"2012-02-25T12:53:47Z","updated_at":"2013-08-21T20:32:08Z","pushed_at":"2013-08-21T20:31:45Z","git_url":"git://github.com/jacquev6/PyGithub.git","ssh_url":"git@github.com:jacquev6/PyGithub.git","clone_url":"https://github.com/jacquev6/PyGithub.git","svn_url":"https://github.com/jacquev6/PyGithub","homepage":"http://jacquev6.github.com/PyGithub","size":7437,"watchers_count":248,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":70,"mirror_url":null,"open_issues_count":17,"forks":70,"open_issues":17,"watchers":248,"master_branch":"master","default_branch":"master"}} + diff --git a/github/tests/ReplayData/ConditionalRequestUpdate.testUpdateObjectWithoutEtag.txt b/github/tests/ReplayData/ConditionalRequestUpdate.testUpdateObjectWithoutEtag.txt new file mode 100755 index 00000000..6ef154b5 --- /dev/null +++ b/github/tests/ReplayData/ConditionalRequestUpdate.testUpdateObjectWithoutEtag.txt @@ -0,0 +1,22 @@ +https +GET +api.github.com +None +/repos/jacquev6/PyGithub +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +null +200 +[('status', '200 OK'), ('x-ratelimit-remaining', '4911'), ('content-length', '1129'), ('server', 'nginx/1.0.13'), ('connection', 'keep-alive'), ('x-ratelimit-limit', '5000'), ('date', 'Sun, 27 May 2012 07:17:09 GMT'), ('content-type', 'application/json; charset=utf-8')] +{"clone_url":"https://github.com/jacquev6/PyGithub.git","has_downloads":true,"watchers":15,"git_url":"git://github.com/jacquev6/PyGithub.git","updated_at":"2012-05-27T06:55:28Z","permissions":{"pull":true,"admin":true,"push":true},"homepage":"http://vincent-jacques.net/PyGithub","url":"https://api.github.com/repos/jacquev6/PyGithub","mirror_url":null,"has_wiki":false,"has_issues":true,"fork":false,"forks":3,"size":308,"private":false,"open_issues":16,"svn_url":"https://github.com/jacquev6/PyGithub","owner":{"url":"https://api.github.com/users/jacquev6","avatar_url":"https://secure.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","login":"jacquev6","id":327146},"name":"PyGithub","language":"Python","description":"Python library implementing the full Github API v3","ssh_url":"git@github.com:jacquev6/PyGithub.git","pushed_at":"2012-05-27T06:00:28Z","created_at":"2012-02-25T12:53:47Z","id":3544490,"html_url":"https://github.com/jacquev6/PyGithub","full_name":"jacquev6/PyGithub"} + +https +GET +api.github.com +None +/repos/jacquev6/PyGithub +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +null +200 +[('status', '200 OK'), ('x-ratelimit-remaining', '4911'), ('content-length', '1129'), ('server', 'nginx/1.0.13'), ('connection', 'keep-alive'), ('x-ratelimit-limit', '5000'), ('date', 'Sun, 27 May 2012 07:17:09 GMT'), ('content-type', 'application/json; charset=utf-8')] +{"clone_url":"https://github.com/jacquev6/PyGithub.git","has_downloads":true,"watchers":15,"git_url":"git://github.com/jacquev6/PyGithub.git","updated_at":"2012-05-27T06:55:28Z","permissions":{"pull":true,"admin":true,"push":true},"homepage":"http://vincent-jacques.net/PyGithub","url":"https://api.github.com/repos/jacquev6/PyGithub","mirror_url":null,"has_wiki":false,"has_issues":true,"fork":false,"forks":3,"size":308,"private":false,"open_issues":16,"svn_url":"https://github.com/jacquev6/PyGithub","owner":{"url":"https://api.github.com/users/jacquev6","avatar_url":"https://secure.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-140.png","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","login":"jacquev6","id":327146},"name":"PyGithub","language":"Python","description":"Python library implementing the full Github API v3","ssh_url":"git@github.com:jacquev6/PyGithub.git","pushed_at":"2012-05-27T06:00:28Z","created_at":"2012-02-25T12:53:47Z","id":3544490,"html_url":"https://github.com/jacquev6/PyGithub","full_name":"jacquev6/PyGithub"} + diff --git a/github/tests/ReplayData/Persistence.setUp.txt b/github/tests/ReplayData/Persistence.setUp.txt new file mode 100644 index 00000000..dfc62ba2 --- /dev/null +++ b/github/tests/ReplayData/Persistence.setUp.txt @@ -0,0 +1,11 @@ +https +GET +api.github.com +None +/repos/akfish/PyGithub +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +null +200 +[('status', '200 OK'), ('x-ratelimit-remaining', '4988'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes'), ('access-control-allow-credentials', 'true'), ('vary', 'Accept, Authorization, Cookie, Accept-Encoding'), ('content-length', '13698'), ('server', 'GitHub.com'), ('last-modified', 'Thu, 22 Aug 2013 02:09:11 GMT'), ('x-ratelimit-limit', '5000'), ('etag', '"8600bedcb7fed1d8065e1693e05529ce"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('date', 'Thu, 22 Aug 2013 02:13:08 GMT'), ('access-control-allow-origin', '*'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1377140429')] +{"id":12156762,"name":"PyGithub","full_name":"akfish/PyGithub","owner":{"login":"akfish","id":922715,"avatar_url":"https://1.gravatar.com/avatar/12a1b44d4e5c19cee59618084602b112?d=https%3A%2F%2Fidenticons.github.com%2F6eb90fb68a77fb5a5a997c6264bedf35.png","gravatar_id":"12a1b44d4e5c19cee59618084602b112","url":"https://api.github.com/users/akfish","html_url":"https://github.com/akfish","followers_url":"https://api.github.com/users/akfish/followers","following_url":"https://api.github.com/users/akfish/following{/other_user}","gists_url":"https://api.github.com/users/akfish/gists{/gist_id}","starred_url":"https://api.github.com/users/akfish/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akfish/subscriptions","organizations_url":"https://api.github.com/users/akfish/orgs","repos_url":"https://api.github.com/users/akfish/repos","events_url":"https://api.github.com/users/akfish/events{/privacy}","received_events_url":"https://api.github.com/users/akfish/received_events","type":"User"},"private":false,"html_url":"https://github.com/akfish/PyGithub","description":"Python library implementing the full Github API v3","fork":true,"url":"https://api.github.com/repos/akfish/PyGithub","forks_url":"https://api.github.com/repos/akfish/PyGithub/forks","keys_url":"https://api.github.com/repos/akfish/PyGithub/keys{/key_id}","collaborators_url":"https://api.github.com/repos/akfish/PyGithub/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/akfish/PyGithub/teams","hooks_url":"https://api.github.com/repos/akfish/PyGithub/hooks","issue_events_url":"https://api.github.com/repos/akfish/PyGithub/issues/events{/number}","events_url":"https://api.github.com/repos/akfish/PyGithub/events","assignees_url":"https://api.github.com/repos/akfish/PyGithub/assignees{/user}","branches_url":"https://api.github.com/repos/akfish/PyGithub/branches{/branch}","tags_url":"https://api.github.com/repos/akfish/PyGithub/tags","blobs_url":"https://api.github.com/repos/akfish/PyGithub/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/akfish/PyGithub/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/akfish/PyGithub/git/refs{/sha}","trees_url":"https://api.github.com/repos/akfish/PyGithub/git/trees{/sha}","statuses_url":"https://api.github.com/repos/akfish/PyGithub/statuses/{sha}","languages_url":"https://api.github.com/repos/akfish/PyGithub/languages","stargazers_url":"https://api.github.com/repos/akfish/PyGithub/stargazers","contributors_url":"https://api.github.com/repos/akfish/PyGithub/contributors","subscribers_url":"https://api.github.com/repos/akfish/PyGithub/subscribers","subscription_url":"https://api.github.com/repos/akfish/PyGithub/subscription","commits_url":"https://api.github.com/repos/akfish/PyGithub/commits{/sha}","git_commits_url":"https://api.github.com/repos/akfish/PyGithub/git/commits{/sha}","comments_url":"https://api.github.com/repos/akfish/PyGithub/comments{/number}","issue_comment_url":"https://api.github.com/repos/akfish/PyGithub/issues/comments/{number}","contents_url":"https://api.github.com/repos/akfish/PyGithub/contents/{+path}","compare_url":"https://api.github.com/repos/akfish/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/akfish/PyGithub/merges","archive_url":"https://api.github.com/repos/akfish/PyGithub/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/akfish/PyGithub/downloads","issues_url":"https://api.github.com/repos/akfish/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/akfish/PyGithub/pulls{/number}","milestones_url":"https://api.github.com/repos/akfish/PyGithub/milestones{/number}","notifications_url":"https://api.github.com/repos/akfish/PyGithub/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/akfish/PyGithub/labels{/name}","created_at":"2013-08-16T10:56:11Z","updated_at":"2013-08-22T02:09:11Z","pushed_at":"2013-08-22T02:09:09Z","git_url":"git://github.com/akfish/PyGithub.git","ssh_url":"git@github.com:akfish/PyGithub.git","clone_url":"https://github.com/akfish/PyGithub.git","svn_url":"https://github.com/akfish/PyGithub","homepage":"http://jacquev6.github.com/PyGithub","size":6736,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"master_branch":"master","default_branch":"master","permissions":{"admin":true,"push":true,"pull":true},"network_count":70,"parent":{"id":3544490,"name":"PyGithub","full_name":"jacquev6/PyGithub","owner":{"login":"jacquev6","id":327146,"avatar_url":"https://0.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https%3A%2F%2Fidenticons.github.com%2Ffadfb5f7088ef66579d198a3c9a4935e.png","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","url":"https://api.github.com/users/jacquev6","html_url":"https://github.com/jacquev6","followers_url":"https://api.github.com/users/jacquev6/followers","following_url":"https://api.github.com/users/jacquev6/following{/other_user}","gists_url":"https://api.github.com/users/jacquev6/gists{/gist_id}","starred_url":"https://api.github.com/users/jacquev6/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacquev6/subscriptions","organizations_url":"https://api.github.com/users/jacquev6/orgs","repos_url":"https://api.github.com/users/jacquev6/repos","events_url":"https://api.github.com/users/jacquev6/events{/privacy}","received_events_url":"https://api.github.com/users/jacquev6/received_events","type":"User"},"private":false,"html_url":"https://github.com/jacquev6/PyGithub","description":"Python library implementing the full Github API v3","fork":false,"url":"https://api.github.com/repos/jacquev6/PyGithub","forks_url":"https://api.github.com/repos/jacquev6/PyGithub/forks","keys_url":"https://api.github.com/repos/jacquev6/PyGithub/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jacquev6/PyGithub/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jacquev6/PyGithub/teams","hooks_url":"https://api.github.com/repos/jacquev6/PyGithub/hooks","issue_events_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/events{/number}","events_url":"https://api.github.com/repos/jacquev6/PyGithub/events","assignees_url":"https://api.github.com/repos/jacquev6/PyGithub/assignees{/user}","branches_url":"https://api.github.com/repos/jacquev6/PyGithub/branches{/branch}","tags_url":"https://api.github.com/repos/jacquev6/PyGithub/tags","blobs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jacquev6/PyGithub/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/refs{/sha}","trees_url":"https://api.github.com/repos/jacquev6/PyGithub/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jacquev6/PyGithub/statuses/{sha}","languages_url":"https://api.github.com/repos/jacquev6/PyGithub/languages","stargazers_url":"https://api.github.com/repos/jacquev6/PyGithub/stargazers","contributors_url":"https://api.github.com/repos/jacquev6/PyGithub/contributors","subscribers_url":"https://api.github.com/repos/jacquev6/PyGithub/subscribers","subscription_url":"https://api.github.com/repos/jacquev6/PyGithub/subscription","commits_url":"https://api.github.com/repos/jacquev6/PyGithub/commits{/sha}","git_commits_url":"https://api.github.com/repos/jacquev6/PyGithub/git/commits{/sha}","comments_url":"https://api.github.com/repos/jacquev6/PyGithub/comments{/number}","issue_comment_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/comments/{number}","contents_url":"https://api.github.com/repos/jacquev6/PyGithub/contents/{+path}","compare_url":"https://api.github.com/repos/jacquev6/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jacquev6/PyGithub/merges","archive_url":"https://api.github.com/repos/jacquev6/PyGithub/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jacquev6/PyGithub/downloads","issues_url":"https://api.github.com/repos/jacquev6/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/jacquev6/PyGithub/pulls{/number}","milestones_url":"https://api.github.com/repos/jacquev6/PyGithub/milestones{/number}","notifications_url":"https://api.github.com/repos/jacquev6/PyGithub/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jacquev6/PyGithub/labels{/name}","created_at":"2012-02-25T12:53:47Z","updated_at":"2013-08-21T20:32:08Z","pushed_at":"2013-08-21T20:31:45Z","git_url":"git://github.com/jacquev6/PyGithub.git","ssh_url":"git@github.com:jacquev6/PyGithub.git","clone_url":"https://github.com/jacquev6/PyGithub.git","svn_url":"https://github.com/jacquev6/PyGithub","homepage":"http://jacquev6.github.com/PyGithub","size":7437,"watchers_count":248,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":70,"mirror_url":null,"open_issues_count":17,"forks":70,"open_issues":17,"watchers":248,"master_branch":"master","default_branch":"master"},"source":{"id":3544490,"name":"PyGithub","full_name":"jacquev6/PyGithub","owner":{"login":"jacquev6","id":327146,"avatar_url":"https://0.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https%3A%2F%2Fidenticons.github.com%2Ffadfb5f7088ef66579d198a3c9a4935e.png","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","url":"https://api.github.com/users/jacquev6","html_url":"https://github.com/jacquev6","followers_url":"https://api.github.com/users/jacquev6/followers","following_url":"https://api.github.com/users/jacquev6/following{/other_user}","gists_url":"https://api.github.com/users/jacquev6/gists{/gist_id}","starred_url":"https://api.github.com/users/jacquev6/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacquev6/subscriptions","organizations_url":"https://api.github.com/users/jacquev6/orgs","repos_url":"https://api.github.com/users/jacquev6/repos","events_url":"https://api.github.com/users/jacquev6/events{/privacy}","received_events_url":"https://api.github.com/users/jacquev6/received_events","type":"User"},"private":false,"html_url":"https://github.com/jacquev6/PyGithub","description":"Python library implementing the full Github API v3","fork":false,"url":"https://api.github.com/repos/jacquev6/PyGithub","forks_url":"https://api.github.com/repos/jacquev6/PyGithub/forks","keys_url":"https://api.github.com/repos/jacquev6/PyGithub/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jacquev6/PyGithub/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jacquev6/PyGithub/teams","hooks_url":"https://api.github.com/repos/jacquev6/PyGithub/hooks","issue_events_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/events{/number}","events_url":"https://api.github.com/repos/jacquev6/PyGithub/events","assignees_url":"https://api.github.com/repos/jacquev6/PyGithub/assignees{/user}","branches_url":"https://api.github.com/repos/jacquev6/PyGithub/branches{/branch}","tags_url":"https://api.github.com/repos/jacquev6/PyGithub/tags","blobs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jacquev6/PyGithub/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/refs{/sha}","trees_url":"https://api.github.com/repos/jacquev6/PyGithub/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jacquev6/PyGithub/statuses/{sha}","languages_url":"https://api.github.com/repos/jacquev6/PyGithub/languages","stargazers_url":"https://api.github.com/repos/jacquev6/PyGithub/stargazers","contributors_url":"https://api.github.com/repos/jacquev6/PyGithub/contributors","subscribers_url":"https://api.github.com/repos/jacquev6/PyGithub/subscribers","subscription_url":"https://api.github.com/repos/jacquev6/PyGithub/subscription","commits_url":"https://api.github.com/repos/jacquev6/PyGithub/commits{/sha}","git_commits_url":"https://api.github.com/repos/jacquev6/PyGithub/git/commits{/sha}","comments_url":"https://api.github.com/repos/jacquev6/PyGithub/comments{/number}","issue_comment_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/comments/{number}","contents_url":"https://api.github.com/repos/jacquev6/PyGithub/contents/{+path}","compare_url":"https://api.github.com/repos/jacquev6/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jacquev6/PyGithub/merges","archive_url":"https://api.github.com/repos/jacquev6/PyGithub/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jacquev6/PyGithub/downloads","issues_url":"https://api.github.com/repos/jacquev6/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/jacquev6/PyGithub/pulls{/number}","milestones_url":"https://api.github.com/repos/jacquev6/PyGithub/milestones{/number}","notifications_url":"https://api.github.com/repos/jacquev6/PyGithub/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jacquev6/PyGithub/labels{/name}","created_at":"2012-02-25T12:53:47Z","updated_at":"2013-08-21T20:32:08Z","pushed_at":"2013-08-21T20:31:45Z","git_url":"git://github.com/jacquev6/PyGithub.git","ssh_url":"git@github.com:jacquev6/PyGithub.git","clone_url":"https://github.com/jacquev6/PyGithub.git","svn_url":"https://github.com/jacquev6/PyGithub","homepage":"http://jacquev6.github.com/PyGithub","size":7437,"watchers_count":248,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":70,"mirror_url":null,"open_issues_count":17,"forks":70,"open_issues":17,"watchers":248,"master_branch":"master","default_branch":"master"}} + diff --git a/github/tests/ReplayData/Persistence.testLoadAndUpdate.txt b/github/tests/ReplayData/Persistence.testLoadAndUpdate.txt new file mode 100644 index 00000000..b6d8aeec --- /dev/null +++ b/github/tests/ReplayData/Persistence.testLoadAndUpdate.txt @@ -0,0 +1,11 @@ +https +GET +api.github.com +None +/repos/akfish/PyGithub +{'If-None-Match': '"8600bedcb7fed1d8065e1693e05529ce"', 'User-Agent': 'PyGithub/Python', 'Authorization': 'Basic login_and_password_removed', 'If-Modified-Since': 'Thu, 22 Aug 2013 02:09:11 GMT'} +null +200 +[('status', '200 OK'), ('x-ratelimit-remaining', '4987'), ('x-github-media-type', 'github.beta; format=json'), ('x-content-type-options', 'nosniff'), ('access-control-expose-headers', 'ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes'), ('access-control-allow-credentials', 'true'), ('vary', 'Accept, Authorization, Cookie, Accept-Encoding'), ('content-length', '13712'), ('server', 'GitHub.com'), ('last-modified', 'Thu, 22 Aug 2013 02:14:54 GMT'), ('x-ratelimit-limit', '5000'), ('etag', '"ef281ef0e821c18f80da36902727160b"'), ('cache-control', 'private, max-age=60, s-maxage=60'), ('date', 'Thu, 22 Aug 2013 02:15:01 GMT'), ('access-control-allow-origin', '*'), ('content-type', 'application/json; charset=utf-8'), ('x-ratelimit-reset', '1377140429')] +{"id":12156762,"name":"PyGithub","full_name":"akfish/PyGithub","owner":{"login":"akfish","id":922715,"avatar_url":"https://0.gravatar.com/avatar/12a1b44d4e5c19cee59618084602b112?d=https%3A%2F%2Fidenticons.github.com%2F6eb90fb68a77fb5a5a997c6264bedf35.png","gravatar_id":"12a1b44d4e5c19cee59618084602b112","url":"https://api.github.com/users/akfish","html_url":"https://github.com/akfish","followers_url":"https://api.github.com/users/akfish/followers","following_url":"https://api.github.com/users/akfish/following{/other_user}","gists_url":"https://api.github.com/users/akfish/gists{/gist_id}","starred_url":"https://api.github.com/users/akfish/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/akfish/subscriptions","organizations_url":"https://api.github.com/users/akfish/orgs","repos_url":"https://api.github.com/users/akfish/repos","events_url":"https://api.github.com/users/akfish/events{/privacy}","received_events_url":"https://api.github.com/users/akfish/received_events","type":"User"},"private":false,"html_url":"https://github.com/akfish/PyGithub","description":"Python library implementing the full Github API v3 - AKFish Fork","fork":true,"url":"https://api.github.com/repos/akfish/PyGithub","forks_url":"https://api.github.com/repos/akfish/PyGithub/forks","keys_url":"https://api.github.com/repos/akfish/PyGithub/keys{/key_id}","collaborators_url":"https://api.github.com/repos/akfish/PyGithub/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/akfish/PyGithub/teams","hooks_url":"https://api.github.com/repos/akfish/PyGithub/hooks","issue_events_url":"https://api.github.com/repos/akfish/PyGithub/issues/events{/number}","events_url":"https://api.github.com/repos/akfish/PyGithub/events","assignees_url":"https://api.github.com/repos/akfish/PyGithub/assignees{/user}","branches_url":"https://api.github.com/repos/akfish/PyGithub/branches{/branch}","tags_url":"https://api.github.com/repos/akfish/PyGithub/tags","blobs_url":"https://api.github.com/repos/akfish/PyGithub/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/akfish/PyGithub/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/akfish/PyGithub/git/refs{/sha}","trees_url":"https://api.github.com/repos/akfish/PyGithub/git/trees{/sha}","statuses_url":"https://api.github.com/repos/akfish/PyGithub/statuses/{sha}","languages_url":"https://api.github.com/repos/akfish/PyGithub/languages","stargazers_url":"https://api.github.com/repos/akfish/PyGithub/stargazers","contributors_url":"https://api.github.com/repos/akfish/PyGithub/contributors","subscribers_url":"https://api.github.com/repos/akfish/PyGithub/subscribers","subscription_url":"https://api.github.com/repos/akfish/PyGithub/subscription","commits_url":"https://api.github.com/repos/akfish/PyGithub/commits{/sha}","git_commits_url":"https://api.github.com/repos/akfish/PyGithub/git/commits{/sha}","comments_url":"https://api.github.com/repos/akfish/PyGithub/comments{/number}","issue_comment_url":"https://api.github.com/repos/akfish/PyGithub/issues/comments/{number}","contents_url":"https://api.github.com/repos/akfish/PyGithub/contents/{+path}","compare_url":"https://api.github.com/repos/akfish/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/akfish/PyGithub/merges","archive_url":"https://api.github.com/repos/akfish/PyGithub/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/akfish/PyGithub/downloads","issues_url":"https://api.github.com/repos/akfish/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/akfish/PyGithub/pulls{/number}","milestones_url":"https://api.github.com/repos/akfish/PyGithub/milestones{/number}","notifications_url":"https://api.github.com/repos/akfish/PyGithub/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/akfish/PyGithub/labels{/name}","created_at":"2013-08-16T10:56:11Z","updated_at":"2013-08-22T02:14:54Z","pushed_at":"2013-08-22T02:09:09Z","git_url":"git://github.com/akfish/PyGithub.git","ssh_url":"git@github.com:akfish/PyGithub.git","clone_url":"https://github.com/akfish/PyGithub.git","svn_url":"https://github.com/akfish/PyGithub","homepage":"http://jacquev6.github.com/PyGithub","size":6736,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"master_branch":"master","default_branch":"master","permissions":{"admin":true,"push":true,"pull":true},"network_count":70,"parent":{"id":3544490,"name":"PyGithub","full_name":"jacquev6/PyGithub","owner":{"login":"jacquev6","id":327146,"avatar_url":"https://0.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https%3A%2F%2Fidenticons.github.com%2Ffadfb5f7088ef66579d198a3c9a4935e.png","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","url":"https://api.github.com/users/jacquev6","html_url":"https://github.com/jacquev6","followers_url":"https://api.github.com/users/jacquev6/followers","following_url":"https://api.github.com/users/jacquev6/following{/other_user}","gists_url":"https://api.github.com/users/jacquev6/gists{/gist_id}","starred_url":"https://api.github.com/users/jacquev6/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacquev6/subscriptions","organizations_url":"https://api.github.com/users/jacquev6/orgs","repos_url":"https://api.github.com/users/jacquev6/repos","events_url":"https://api.github.com/users/jacquev6/events{/privacy}","received_events_url":"https://api.github.com/users/jacquev6/received_events","type":"User"},"private":false,"html_url":"https://github.com/jacquev6/PyGithub","description":"Python library implementing the full Github API v3","fork":false,"url":"https://api.github.com/repos/jacquev6/PyGithub","forks_url":"https://api.github.com/repos/jacquev6/PyGithub/forks","keys_url":"https://api.github.com/repos/jacquev6/PyGithub/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jacquev6/PyGithub/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jacquev6/PyGithub/teams","hooks_url":"https://api.github.com/repos/jacquev6/PyGithub/hooks","issue_events_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/events{/number}","events_url":"https://api.github.com/repos/jacquev6/PyGithub/events","assignees_url":"https://api.github.com/repos/jacquev6/PyGithub/assignees{/user}","branches_url":"https://api.github.com/repos/jacquev6/PyGithub/branches{/branch}","tags_url":"https://api.github.com/repos/jacquev6/PyGithub/tags","blobs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jacquev6/PyGithub/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/refs{/sha}","trees_url":"https://api.github.com/repos/jacquev6/PyGithub/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jacquev6/PyGithub/statuses/{sha}","languages_url":"https://api.github.com/repos/jacquev6/PyGithub/languages","stargazers_url":"https://api.github.com/repos/jacquev6/PyGithub/stargazers","contributors_url":"https://api.github.com/repos/jacquev6/PyGithub/contributors","subscribers_url":"https://api.github.com/repos/jacquev6/PyGithub/subscribers","subscription_url":"https://api.github.com/repos/jacquev6/PyGithub/subscription","commits_url":"https://api.github.com/repos/jacquev6/PyGithub/commits{/sha}","git_commits_url":"https://api.github.com/repos/jacquev6/PyGithub/git/commits{/sha}","comments_url":"https://api.github.com/repos/jacquev6/PyGithub/comments{/number}","issue_comment_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/comments/{number}","contents_url":"https://api.github.com/repos/jacquev6/PyGithub/contents/{+path}","compare_url":"https://api.github.com/repos/jacquev6/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jacquev6/PyGithub/merges","archive_url":"https://api.github.com/repos/jacquev6/PyGithub/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jacquev6/PyGithub/downloads","issues_url":"https://api.github.com/repos/jacquev6/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/jacquev6/PyGithub/pulls{/number}","milestones_url":"https://api.github.com/repos/jacquev6/PyGithub/milestones{/number}","notifications_url":"https://api.github.com/repos/jacquev6/PyGithub/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jacquev6/PyGithub/labels{/name}","created_at":"2012-02-25T12:53:47Z","updated_at":"2013-08-21T20:32:08Z","pushed_at":"2013-08-21T20:31:45Z","git_url":"git://github.com/jacquev6/PyGithub.git","ssh_url":"git@github.com:jacquev6/PyGithub.git","clone_url":"https://github.com/jacquev6/PyGithub.git","svn_url":"https://github.com/jacquev6/PyGithub","homepage":"http://jacquev6.github.com/PyGithub","size":7437,"watchers_count":248,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":70,"mirror_url":null,"open_issues_count":17,"forks":70,"open_issues":17,"watchers":248,"master_branch":"master","default_branch":"master"},"source":{"id":3544490,"name":"PyGithub","full_name":"jacquev6/PyGithub","owner":{"login":"jacquev6","id":327146,"avatar_url":"https://0.gravatar.com/avatar/b68de5ae38616c296fa345d2b9df2225?d=https%3A%2F%2Fidenticons.github.com%2Ffadfb5f7088ef66579d198a3c9a4935e.png","gravatar_id":"b68de5ae38616c296fa345d2b9df2225","url":"https://api.github.com/users/jacquev6","html_url":"https://github.com/jacquev6","followers_url":"https://api.github.com/users/jacquev6/followers","following_url":"https://api.github.com/users/jacquev6/following{/other_user}","gists_url":"https://api.github.com/users/jacquev6/gists{/gist_id}","starred_url":"https://api.github.com/users/jacquev6/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jacquev6/subscriptions","organizations_url":"https://api.github.com/users/jacquev6/orgs","repos_url":"https://api.github.com/users/jacquev6/repos","events_url":"https://api.github.com/users/jacquev6/events{/privacy}","received_events_url":"https://api.github.com/users/jacquev6/received_events","type":"User"},"private":false,"html_url":"https://github.com/jacquev6/PyGithub","description":"Python library implementing the full Github API v3","fork":false,"url":"https://api.github.com/repos/jacquev6/PyGithub","forks_url":"https://api.github.com/repos/jacquev6/PyGithub/forks","keys_url":"https://api.github.com/repos/jacquev6/PyGithub/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jacquev6/PyGithub/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jacquev6/PyGithub/teams","hooks_url":"https://api.github.com/repos/jacquev6/PyGithub/hooks","issue_events_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/events{/number}","events_url":"https://api.github.com/repos/jacquev6/PyGithub/events","assignees_url":"https://api.github.com/repos/jacquev6/PyGithub/assignees{/user}","branches_url":"https://api.github.com/repos/jacquev6/PyGithub/branches{/branch}","tags_url":"https://api.github.com/repos/jacquev6/PyGithub/tags","blobs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jacquev6/PyGithub/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jacquev6/PyGithub/git/refs{/sha}","trees_url":"https://api.github.com/repos/jacquev6/PyGithub/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jacquev6/PyGithub/statuses/{sha}","languages_url":"https://api.github.com/repos/jacquev6/PyGithub/languages","stargazers_url":"https://api.github.com/repos/jacquev6/PyGithub/stargazers","contributors_url":"https://api.github.com/repos/jacquev6/PyGithub/contributors","subscribers_url":"https://api.github.com/repos/jacquev6/PyGithub/subscribers","subscription_url":"https://api.github.com/repos/jacquev6/PyGithub/subscription","commits_url":"https://api.github.com/repos/jacquev6/PyGithub/commits{/sha}","git_commits_url":"https://api.github.com/repos/jacquev6/PyGithub/git/commits{/sha}","comments_url":"https://api.github.com/repos/jacquev6/PyGithub/comments{/number}","issue_comment_url":"https://api.github.com/repos/jacquev6/PyGithub/issues/comments/{number}","contents_url":"https://api.github.com/repos/jacquev6/PyGithub/contents/{+path}","compare_url":"https://api.github.com/repos/jacquev6/PyGithub/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jacquev6/PyGithub/merges","archive_url":"https://api.github.com/repos/jacquev6/PyGithub/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jacquev6/PyGithub/downloads","issues_url":"https://api.github.com/repos/jacquev6/PyGithub/issues{/number}","pulls_url":"https://api.github.com/repos/jacquev6/PyGithub/pulls{/number}","milestones_url":"https://api.github.com/repos/jacquev6/PyGithub/milestones{/number}","notifications_url":"https://api.github.com/repos/jacquev6/PyGithub/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jacquev6/PyGithub/labels{/name}","created_at":"2012-02-25T12:53:47Z","updated_at":"2013-08-21T20:32:08Z","pushed_at":"2013-08-21T20:31:45Z","git_url":"git://github.com/jacquev6/PyGithub.git","ssh_url":"git@github.com:jacquev6/PyGithub.git","clone_url":"https://github.com/jacquev6/PyGithub.git","svn_url":"https://github.com/jacquev6/PyGithub","homepage":"http://jacquev6.github.com/PyGithub","size":7437,"watchers_count":248,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":70,"mirror_url":null,"open_issues_count":17,"forks":70,"open_issues":17,"watchers":248,"master_branch":"master","default_branch":"master"}} +