From 6cf0a59c74c8d4531fc83c2d247f0a1ad6885b1c Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 26 Feb 2012 20:35:19 +0000 Subject: [PATCH 01/56] Typo --- ReferenceOfClasses.md | 5 ++++- github/GithubObjects.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ReferenceOfClasses.md b/ReferenceOfClasses.md index 06929fe7..d38498be 100644 --- a/ReferenceOfClasses.md +++ b/ReferenceOfClasses.md @@ -492,6 +492,9 @@ Attributes * `changed_files` * `head` * `base` +* `merged_by` +* `review_comments` +* `user`: `NamedUser` Modification ------------ @@ -625,7 +628,7 @@ Git refs Git commits ----------- * `get_git_commit( sha )`: `GitCommit` -* `create_git_commit( message, tree, parents, [author, commiter] )`: `GitCommit` +* `create_git_commit( message, tree, parents, [author, committer] )`: `GitCommit` Git trees --------- diff --git a/github/GithubObjects.py b/github/GithubObjects.py index ff4c7ab0..e95e0836 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -385,7 +385,7 @@ Repository._addAttributePolicy( SeveralAttributePolicies( [ ), ExternalListOfObjects( "git/commits", "git_commit", GitCommit, ElementGetable( [ "sha" ], [], __modifyAttributesForObjectsReferingRepo ), - ElementCreatable( [ "message", "tree", "parents" ], [ "author", "commiter" ], __modifyAttributesForObjectsReferingRepo ) + ElementCreatable( [ "message", "tree", "parents" ], [ "author", "committer" ], __modifyAttributesForObjectsReferingRepo ) ), ExternalListOfObjects( "git/trees", "git_tree", GitTree, ElementGetable( [ "sha" ], [], __modifyAttributesForObjectsReferingRepo ), From 10cca6b38ad89106706a3e3bd68c421065247a7a Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 23 Feb 2012 21:35:58 +0000 Subject: [PATCH 02/56] Todos for gists --- ReferenceOfApis.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index b9c152bf..4e32e71a 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -15,43 +15,43 @@ API `/events` API `/gists` ============ -* GET: (TODO) -* POST: (TODO) +* GET: (TODO SOON) +* POST: (TODO SOON) API `/gists/:gist_id/comments` ============================== -* GET: (TODO) -* POST: (TODO) +* GET: (TODO SOON) +* POST: (TODO SOON) API `/gists/:id` ================ -* GET: (TODO) -* PATCH: (TODO) -* DELETE: (TODO) +* GET: (TODO SOON) +* PATCH: (TODO SOON) +* DELETE: (TODO SOON) API `/gists/:id/fork` ===================== -* POST: (TODO) +* POST: (TODO SOON) API `/gists/:id/star` ===================== -* GET: (TODO) -* PUT: (TODO) -* DELETE: (TODO) +* GET: (TODO SOON) +* PUT: (TODO SOON) +* DELETE: (TODO SOON) API `/gists/comments/:id` ========================= -* GET: (TODO) -* PATCH: (TODO) -* DELETE: (TODO) +* GET: (TODO SOON) +* PATCH: (TODO SOON) +* DELETE: (TODO SOON) API `/gists/public` =================== -* GET: (TODO) +* GET: (TODO SOON) API `/gists/starred` ==================== -* GET: (TODO) +* GET: (TODO SOON) API `/issues` ============= @@ -471,7 +471,7 @@ API `/users/:user/following` API `/users/:user/gists` ======================== -* GET: (TODO) +* GET: (TODO SOON) API `/users/:user/orgs` ======================= From 832605afcb52cf5384e12b088f2e1d25c1c0a184 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Tue, 28 Feb 2012 20:24:00 +0000 Subject: [PATCH 03/56] Gists --- IntegrationTest.py | 16 ++++++- ReferenceOfApis.md | 40 +++++++++--------- ReferenceOfClasses.md | 74 +++++++++++++++++++++++++++++++++ github/Github.py | 3 ++ github/GithubObjects.py | 69 ++++++++++++++++++++++++++++++ github/ObjectCapacities/List.py | 32 ++++++++------ 6 files changed, 201 insertions(+), 33 deletions(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index e2800f04..953890f1 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -115,8 +115,8 @@ class IntegrationTest: exit( 1 ) def playScenario( self ): - self.doSomeReads() self.doSomeWrites() + self.doSomeReads() def doSomeReads( self ): self.dumpUser( self.g.get_user(), doPrivateThings = True ) @@ -129,6 +129,7 @@ class IntegrationTest: def doSomeWrites( self ): self.doSomeWritesToUser() self.doSomeWritesToRepository() + self.doSomeWritesToGist() def doSomeWritesToUser( self ): u = self.g.get_user() @@ -199,8 +200,21 @@ class IntegrationTest: self.dumpRepository( r ) + def doSomeWritesToGist( self ): + u = self.g.get_user() + g = u.create_gist( True, { "foobar.txt": { "content": "Gist created by PyGithub" } }, "Gist created by PyGithub" ) + g.edit( "Gist edited by PyGithub" ) + g.create_comment( "Gist comment created by PyGithub" ) + g.set_starred() + assert g.is_starred() + g.reset_starred() + assert not g.is_starred() + def dumpUser( self, u, doPrivateThings ): print u.login, "(", u.name, ")" + print " Gists:", ", ".join( g.description + "(" + ", ".join( c.body for c in g.get_comments() ) + ")" for g in u.get_gists() ) + if doPrivateThings: + print " Starred gists:", ", ".join( g.description for g in u.get_starred_gists() ) print " Repos:" for r in u.get_repos(): print " ", r.name, diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index 4e32e71a..5c071266 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -15,43 +15,43 @@ API `/events` API `/gists` ============ -* GET: (TODO SOON) -* POST: (TODO SOON) - -API `/gists/:gist_id/comments` -============================== -* GET: (TODO SOON) -* POST: (TODO SOON) +* GET: `AuthenticatedUser.get_gists` +* POST: `AuthenticatedUser.create_gist` API `/gists/:id` ================ -* GET: (TODO SOON) -* PATCH: (TODO SOON) -* DELETE: (TODO SOON) +* GET: `Github.get_gist` +* PATCH: `Gist.edit` +* DELETE: `Gist.delete` + +API `/gists/:id/comments` +============================== +* GET: `Gist.get_comments` +* POST: `Gist.create_comment` API `/gists/:id/fork` ===================== -* POST: (TODO SOON) +* POST: `Gist.create_fork` API `/gists/:id/star` ===================== -* GET: (TODO SOON) -* PUT: (TODO SOON) -* DELETE: (TODO SOON) +* GET: `Gist.is_starred` +* PUT: `Gist.set_starred` +* DELETE: `Gist.reset_starred` API `/gists/comments/:id` ========================= -* GET: (TODO SOON) -* PATCH: (TODO SOON) -* DELETE: (TODO SOON) +* GET: `Gist.get_comment` +* PATCH: `GistComment.edit` +* DELETE: `GistComment.delete` API `/gists/public` =================== -* GET: (TODO SOON) +* GET: (TODO) (Almost useless: huge fast-changing list, so I will have to re-re-implement pagination, with detection of duplicates caused by shifts, and a real iteration, not construction of the full list...) API `/gists/starred` ==================== -* GET: (TODO SOON) +* GET: `AuthenticatedUser.get_starred_gists` API `/issues` ============= @@ -471,7 +471,7 @@ API `/users/:user/following` API `/users/:user/gists` ======================== -* GET: (TODO SOON) +* GET: `NamedUser.get_gists` API `/users/:user/orgs` ======================= diff --git a/ReferenceOfClasses.md b/ReferenceOfClasses.md index d38498be..1b9079b9 100644 --- a/ReferenceOfClasses.md +++ b/ReferenceOfClasses.md @@ -96,6 +96,12 @@ Forking ------- * `create_fork( repo )`: `Repository` +Gists +----- +* `get_gists()`: list of `Gist` +* `create_gist( public, files, [description] )`: `Gist` +* `get_starred_gists()`: list of `Gist` + Class `Branch` ============== @@ -178,6 +184,70 @@ Deletion -------- * `delete()` +Class `Gist` +============ + +Attributes +---------- +* `url` +* `id` +* `description` +* `public` +* `files` +* `comments` +* `html_url` +* `git_pull_url` +* `git_push_url` +* `created_at` +* `forks` +* `history` +* `updated_at` +* `user`: `NamedUser` + +Modification +------------ +* `edit( [description, files] )` + +Deletion +-------- +* `delete()` + +Comments +-------- +* `get_comments()`: list of `GistComment` +* `get_comment( id )`: `GistComment` +* `create_comment( body )`: `GistComment` + +Starring +-------- +* `is_starred()`: bool +* `set_starred()` +* `reset_starred()` + +Forking +------- +* `create_fork()`: `Gist` + +Class `GistComment` +=================== + +Attributes +---------- +* `id` +* `url` +* `body` +* `created_at` +* `updated_at` +* `user`: `NamedUser` + +Modification +------------ +* `edit( body )` + +Deletion +-------- +* `delete()` + Class `GitBlob` =============== @@ -398,6 +468,10 @@ Watched ------- * `get_watched()`: list of `Repository` +Gists +----- +* `get_gists()`: list of `Gist` + Class `Organization` ==================== diff --git a/github/Github.py b/github/Github.py index 9446f6ba..03781a5d 100644 --- a/github/Github.py +++ b/github/Github.py @@ -19,3 +19,6 @@ class Github: def get_organization( self, login ): return Organization( self, { "login": login }, lazy = False ) + + def get_gist( self, id ): + return Gist( self, { "id": id }, lazy = False ) diff --git a/github/GithubObjects.py b/github/GithubObjects.py index e95e0836..f8d1e603 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -521,3 +521,72 @@ Repository._addAttributePolicy( ListGetable( [], [] ) ) ) + +GistComment = GithubObject( + "GistComment", + BaseUrl( lambda obj: "/gists/comments/" + str( obj.id ) ), + InternalSimpleAttributes( + "id", "url", "body", "created_at", + "updated_at", + ), + InternalObjectAttribute( "user", NamedUser ), + Editable( [ "body" ], [] ), + Deletable(), +) + +def __isStarred( gist ): + return gist._github._statusRequest( "GET", gist._baseUrl + "/star", None, None ) == 204 +def __setStarred( gist ): + gist._github._statusRequest( "PUT", gist._baseUrl + "/star", None, None ) +def __resetStarred( gist ): + gist._github._statusRequest( "DELETE", gist._baseUrl + "/star", None, None ) +Gist = GithubObject( + "Gist", + BaseUrl( lambda obj: "/gists/" + str( obj.id ) ), + InternalSimpleAttributes( + "url", "id", "description", "public", "files", "comments", "html_url", + "git_pull_url", "git_push_url", "created_at", "forks", "history", + "updated_at", + ), + InternalObjectAttribute( "user", NamedUser ), + Editable( [], [ "description", "files" ] ), + Deletable(), + ExternalListOfObjects( "comments", "comment", GistComment, + ListGetable( [], [] ), + ElementGetable( [ "id" ], [] ), + ElementCreatable( [ "body" ], [] ), + ), + SeveralAttributePolicies( [ + MethodFromCallable( "is_starred", [], [], __isStarred, SimpleTypePolicy( "bool" ) ), + MethodFromCallable( "set_starred", [], [], __setStarred, SimpleTypePolicy( None ) ), + MethodFromCallable( "reset_starred", [], [], __resetStarred, SimpleTypePolicy( None ) ), + ], "Starring" ), +) +def __createFork( gist ): + return Gist( gitst._github, gist._github._dataRequest( "POST", gist._baseUrl + "/fork", None, None ), lazy = True ) +Gist._addAttributePolicy( SeveralAttributePolicies( [ + MethodFromCallable( "create_fork", [], [], __createFork, ObjectTypePolicy( Gist ) ), + ], "Forking" ), +) + +NamedUser._addAttributePolicy( + ExternalListOfObjects( "gists", "gist", Gist, + ListGetable( [], [] ), + ) +) + +AuthenticatedUser._addAttributePolicy( + ExternalListOfObjects( "gists", "gist", Gist, + ListGetable( [], [] ), + ElementCreatable( [ "public", "files", ], [ "description" ] ), + url = "/gists", + ) +) +def __getStaredGists( user ): + return [ + Gist( user._github, attributes, lazy = True ) + for attributes in user._github._dataRequest( "GET", "/gists/starred", None, None ) + ] +AuthenticatedUser._addAttributePolicy( + MethodFromCallable( "get_starred_gists", [], [], __getStaredGists, SimpleTypePolicy( "list of `Gist`" ) ), +) diff --git a/github/ObjectCapacities/List.py b/github/ObjectCapacities/List.py index 24014fa8..76547bd7 100644 --- a/github/ObjectCapacities/List.py +++ b/github/ObjectCapacities/List.py @@ -5,12 +5,19 @@ from TypePolicies import * from ArgumentsChecker import * class ListCapacity: - def setList( self, attributeName, singularName, typePolicy ): + def setList( self, attributeName, singularName, typePolicy, url = None ): self.attributeName = attributeName self.singularName = singularName self.safeAttributeName = attributeName.replace( "/", "_" ) self.safeSingularName = singularName.replace( "/", "_" ) self.typePolicy = typePolicy + self.__url = url + + def baseUrl( self, obj ): + if self.__url is None: + return obj._baseUrl + "/" + self.attributeName + else: + return self.__url class ElementAddable( ListCapacity ): def apply( self, cls ): @@ -19,7 +26,7 @@ class ElementAddable( ListCapacity ): def __execute( self, obj, toBeAdded ): obj._github._statusRequest( "PUT", - obj._baseUrl + "/" + self.attributeName + "/" + self.typePolicy.getIdentity( toBeAdded ), + self.baseUrl( obj ) + "/" + self.typePolicy.getIdentity( toBeAdded ), None, None ) @@ -34,7 +41,7 @@ class ElementRemovable( ListCapacity ): def __execute( self, obj, toBeDeleted ): obj._github._statusRequest( "DELETE", - obj._baseUrl + "/" + self.attributeName + "/" + self.typePolicy.getIdentity( toBeDeleted ), + self.baseUrl( obj ) + "/" + self.typePolicy.getIdentity( toBeDeleted ), None, None ) @@ -49,12 +56,13 @@ class ElementHasable( ListCapacity ): def __execute( self, obj, toBeQueried ): return obj._github._statusRequest( "GET", - obj._baseUrl + "/" + self.attributeName + "/" + self.typePolicy.getIdentity( toBeQueried ), + self.baseUrl( obj ) + "/" + self.typePolicy.getIdentity( toBeQueried ), None, None ) == 204 def autoDocument( self ): + ### @todo `bool` -> bool return "* `has_in_" + self.safeAttributeName + "( " + self.singularName + " )`: `bool`\n * `" + self.singularName + "`: " + self.typePolicy.documentTypeName() + "\n" class ElementCreatable( ListCapacity ): @@ -72,7 +80,7 @@ class ElementCreatable( ListCapacity ): obj, obj._github._dataRequest( "POST", - obj._baseUrl + "/" + self.attributeName, + self.baseUrl( obj ), None, self.__argumentsChecker.check( args, kwds ) ) @@ -119,7 +127,7 @@ class SeveralElementsAddable( ListCapacity ): def __execute( self, obj, *toBeAddeds ): obj._github._statusRequest( "POST", - obj._baseUrl + "/" + self.attributeName, + self.baseUrl( obj ), None, [ self.typePolicy.getIdentity( toBeAdded ) @@ -137,7 +145,7 @@ class SeveralElementsRemovable( ListCapacity ): def __execute( self, obj, *toBeDeleteds ): obj._github._statusRequest( "DELETE", - obj._baseUrl + "/" + self.attributeName, + self.baseUrl( obj ), None, [ self.typePolicy.getIdentity( toBeDeleted ) @@ -165,7 +173,7 @@ class ListGetable( ListCapacity ): ) for attributes in obj._github._dataRequest( "GET", - obj._baseUrl + "/" + self.attributeName, + self.baseUrl( obj ), params, None ) @@ -186,7 +194,7 @@ class ListSetable( ListCapacity ): def __execute( self, obj, *toBeSets ): obj._github._statusRequest( "PUT", - obj._baseUrl + "/" + self.attributeName, + self.baseUrl( obj ), None, [ self.typePolicy.getIdentity( toBeSet ) @@ -204,7 +212,7 @@ class ListDeletable( ListCapacity ): def __execute( self, obj ): obj._github._statusRequest( "DELETE", - obj._baseUrl + "/" + self.attributeName, + self.baseUrl( obj ), None, None ) @@ -212,9 +220,9 @@ class ListDeletable( ListCapacity ): def autoDocument( self ): return "* `delete_" + self.safeAttributeName + "()`\n" -def ExternalListOfObjects( attributeName, singularName, type, *capacities ): +def ExternalListOfObjects( attributeName, singularName, type, *capacities, **kwds ): for capacity in capacities: - capacity.setList( attributeName, singularName, ObjectTypePolicy( type ) ) + capacity.setList( attributeName, singularName, ObjectTypePolicy( type ), **kwds ) return SeveralAttributePolicies( capacities, attributeName.capitalize().replace( "_", " " ).replace( "/", " " ) ) def ExternalListOfSimpleTypes( attributeName, singularName, type, *capacities ): From 3b523190a0495c9ea25d589c8ff01d5a92a62751 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 23 Feb 2012 21:38:43 +0000 Subject: [PATCH 04/56] Todos for authorizations and keys --- ReferenceOfApis.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index 5c071266..8454c441 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -1,13 +1,13 @@ API `/authorizations` ===================== -* GET: (TODO) -* POST: (TODO) +* GET: (TODO SOON) +* POST: (TODO SOON) API `/authorizations/:id` ========================= -* GET: (TODO) -* PATCH: (TODO) -* DELETE: (TODO) +* GET: (TODO SOON) +* PATCH: (TODO SOON) +* DELETE: (TODO SOON) API `/events` ============= @@ -279,14 +279,14 @@ API `/repos/:user/:repo/issues/events/:id` API `/repos/:user/:repo/keys` ============================= -* GET: (TODO) -* POST: (TODO) +* GET: (TODO SOON) +* POST: (TODO SOON) API `/repos/:user/:repo/keys/:id` ================================= -* GET: (TODO) -* PATCH: (TODO) -* DELETE: (TODO) +* GET: (TODO SOON) +* PATCH: (TODO SOON) +* DELETE: (TODO SOON) API `/repos/:user/:repo/labels` =============================== @@ -417,14 +417,14 @@ API `/user/following/:user` API `/user/keys` ================ -* GET: (TODO) -* POST: (TODO) +* GET: (TODO SOON) +* POST: (TODO SOON) API `/user/keys/:id` ==================== -* GET: (TODO) -* PATCH: (TODO) -* DELETE: (TODO) +* GET: (TODO SOON) +* PATCH: (TODO SOON) +* DELETE: (TODO SOON) API `/user/orgs` ================ From b53f96bafae6c6502ffcfd029338df2f02ac0faa Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 07:50:15 +0100 Subject: [PATCH 05/56] Authorizations: step 1 --- ReferenceOfApis.md | 10 +++++----- ReferenceOfClasses.md | 20 ++++++++++++++++++++ github/GithubObjects.py | 16 ++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index 8454c441..8d350016 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -1,13 +1,13 @@ API `/authorizations` ===================== -* GET: (TODO SOON) -* POST: (TODO SOON) +* GET: `AuthenticatedUser.get_authorizations` +* POST: `AuthenticatedUser.create_authorization` API `/authorizations/:id` ========================= -* GET: (TODO SOON) -* PATCH: (TODO SOON) -* DELETE: (TODO SOON) +* GET: `AuthenticatedUser.get_authorization` +* PATCH: `Authorization.edit` +* DELETE: `Authorization.delete` API `/events` ============= diff --git a/ReferenceOfClasses.md b/ReferenceOfClasses.md index 1b9079b9..11deaffe 100644 --- a/ReferenceOfClasses.md +++ b/ReferenceOfClasses.md @@ -58,6 +58,12 @@ Emails * `remove_from_emails( email, ... )` * `email`: string +Authorizations +-------------- +* `get_authorizations()`: list of `Authorization` +* `get_authorization( id )`: `Authorization` +* `create_authorization()`: `Authorization` + Followers --------- * `get_followers()`: list of `NamedUser` @@ -102,6 +108,20 @@ Gists * `create_gist( public, files, [description] )`: `Gist` * `get_starred_gists()`: list of `Gist` +Class `Authorization` +===================== + +Attributes +---------- + +Modification +------------ +* `edit()` + +Deletion +-------- +* `delete()` + Class `Branch` ============== diff --git a/github/GithubObjects.py b/github/GithubObjects.py index f8d1e603..5b935e06 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -3,6 +3,16 @@ import urllib from GithubObject import * +Authorization = GithubObject( + "Authorization", + BaseUrl( lambda obj: "/authorizations/" + str( obj.id ) ), + InternalSimpleAttributes( + ### @todo + ), + Editable( [], [] ), ### @todo + Deletable(), +) + AuthenticatedUser = GithubObject( "AuthenticatedUser", BaseUrl( lambda obj: "/user" ), @@ -20,6 +30,12 @@ AuthenticatedUser = GithubObject( SeveralElementsAddable(), SeveralElementsRemovable() ), + ExternalListOfObjects( "authorizations", "authorization", Authorization, + ListGetable( [], [] ), + ElementGetable( [ "id" ], [] ), + ElementCreatable( [], [] ), ### @todo + ### url = "/authorizations", ### @todo + ), ) NamedUser = GithubObject( From f02c938974b0faa620934059cb677ea2558a5d67 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 07:53:32 +0100 Subject: [PATCH 06/56] UserKey: step 1 --- ReferenceOfApis.md | 10 +++++----- ReferenceOfClasses.md | 20 ++++++++++++++++++++ github/GithubObjects.py | 17 ++++++++++++++++- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index 8d350016..cfc219b6 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -417,14 +417,14 @@ API `/user/following/:user` API `/user/keys` ================ -* GET: (TODO SOON) -* POST: (TODO SOON) +* GET: `AuthenticatedUser.get_keys` +* POST: `AuthenticatedUser.create_key` API `/user/keys/:id` ==================== -* GET: (TODO SOON) -* PATCH: (TODO SOON) -* DELETE: (TODO SOON) +* GET: `AuthenticatedUser.get_key` +* PATCH: `UserKey.edit` +* DELETE: `UserKey.delete` API `/user/orgs` ================ diff --git a/ReferenceOfClasses.md b/ReferenceOfClasses.md index 11deaffe..d86ab9e4 100644 --- a/ReferenceOfClasses.md +++ b/ReferenceOfClasses.md @@ -64,6 +64,12 @@ Authorizations * `get_authorization( id )`: `Authorization` * `create_authorization()`: `Authorization` +Keys +---- +* `get_keys()`: list of `UserKey` +* `get_key( id )`: `UserKey` +* `create_key()`: `UserKey` + Followers --------- * `get_followers()`: list of `NamedUser` @@ -841,4 +847,18 @@ Repos * `has_in_repos( repo )`: `bool` * `repo`: `Repository` +Class `UserKey` +=============== + +Attributes +---------- + +Modification +------------ +* `edit()` + +Deletion +-------- +* `delete()` + diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 5b935e06..a412e588 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -5,7 +5,17 @@ from GithubObject import * Authorization = GithubObject( "Authorization", - BaseUrl( lambda obj: "/authorizations/" + str( obj.id ) ), + BaseUrl( lambda obj: "/authorizations/" + str( obj.id ) ), ### @todo make the lambda return a tuple, and BaseUrl convert elements to strings and join them with "/" + InternalSimpleAttributes( + ### @todo + ), + Editable( [], [] ), ### @todo + Deletable(), +) + +UserKey = GithubObject( + "UserKey", + BaseUrl( lambda obj: "/user/keys/" + str( obj.id ) ), InternalSimpleAttributes( ### @todo ), @@ -36,6 +46,11 @@ AuthenticatedUser = GithubObject( ElementCreatable( [], [] ), ### @todo ### url = "/authorizations", ### @todo ), + ExternalListOfObjects( "keys", "key", UserKey, + ListGetable( [], [] ), + ElementGetable( [ "id" ], [] ), + ElementCreatable( [], [] ), ### @todo + ), ) NamedUser = GithubObject( From 2ea7ce772342479c90ca646f837ba92d6a02a8f5 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 07:59:02 +0100 Subject: [PATCH 07/56] RepositoryKey: first step --- ReferenceOfApis.md | 10 +++++----- ReferenceOfClasses.md | 20 ++++++++++++++++++++ github/GithubObjects.py | 16 ++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index cfc219b6..fa94f5e2 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -279,14 +279,14 @@ API `/repos/:user/:repo/issues/events/:id` API `/repos/:user/:repo/keys` ============================= -* GET: (TODO SOON) -* POST: (TODO SOON) +* GET: `Repository.get_keys` +* POST: `Repository.create_key` API `/repos/:user/:repo/keys/:id` ================================= -* GET: (TODO SOON) -* PATCH: (TODO SOON) -* DELETE: (TODO SOON) +* GET: `Repository.get_key` +* PATCH: `RepositoryKey.edit` +* DELETE: `RepositoryKey.delete` API `/repos/:user/:repo/labels` =============================== diff --git a/ReferenceOfClasses.md b/ReferenceOfClasses.md index d86ab9e4..b8a059e8 100644 --- a/ReferenceOfClasses.md +++ b/ReferenceOfClasses.md @@ -701,6 +701,12 @@ Languages --------- * `get_languages()`: dictionary of strings to integers +Keys +---- +* `get_keys()`: list of `RepositoryKey` +* `get_key( id )`: `RepositoryKey` +* `create_key()`: `RepositoryKey` + Collaborators ------------- * `get_collaborators()`: list of `NamedUser` @@ -797,6 +803,20 @@ Teams ----- * `get_teams()`: list of `Team` +Class `RepositoryKey` +===================== + +Attributes +---------- + +Modification +------------ +* `edit()` + +Deletion +-------- +* `delete()` + Class `Tag` =========== diff --git a/github/GithubObjects.py b/github/GithubObjects.py index a412e588..2ae7a165 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -368,6 +368,17 @@ PullRequest = GithubObject( ), ) +RepositoryKey = GithubObject( + "RepositoryKey", + BaseUrl( lambda obj: obj._repo._baseUrl + "/keys/" + str( obj.id ) ), + InternalSimpleAttributes( + ### @todo + "_repo", ### Ugly hack + ), + Editable( [], [] ), ### @todo + Deletable() +) + Repository = GithubObject( "Repository", BaseUrl( lambda obj: "/repos/" + obj.owner.login + "/" + obj.name ), @@ -397,6 +408,11 @@ Repository._addAttributePolicy( SeveralAttributePolicies( [ ExternalSimpleAttribute( "languages", "dictionary of strings to integers" ) ], "Languages" ) ) Repository._addAttributePolicy( SeveralAttributePolicies( [ + ExternalListOfObjects( "keys", "key", RepositoryKey, + ListGetable( [], [] ), + ElementGetable( [ "id" ], [], __modifyAttributesForObjectsReferingRepo ), + ElementCreatable( [], [] ), ### @todo + ), ExternalListOfObjects( "collaborators", "collaborator", NamedUser, ListGetable( [], [] ), ElementAddable(), From 3bf073954ca1cf7cf35393fcddd8424c35d92d7c Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 17:53:53 +0000 Subject: [PATCH 08/56] Authorizations: step 2 --- ReferenceOfClasses.md | 13 +++++++++++-- github/GithubObjects.py | 9 +++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/ReferenceOfClasses.md b/ReferenceOfClasses.md index b8a059e8..687e4a28 100644 --- a/ReferenceOfClasses.md +++ b/ReferenceOfClasses.md @@ -62,7 +62,7 @@ Authorizations -------------- * `get_authorizations()`: list of `Authorization` * `get_authorization( id )`: `Authorization` -* `create_authorization()`: `Authorization` +* `create_authorization( [scopes, note, note_url] )`: `Authorization` Keys ---- @@ -119,10 +119,19 @@ Class `Authorization` Attributes ---------- +* `id` +* `url` +* `scopes` +* `token` +* `app` +* `note` +* `note_url` +* `updated_at` +* `created_at` Modification ------------ -* `edit()` +* `edit( [scopes, add_scopes, remove_scopes, note, note_url] )` Deletion -------- diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 2ae7a165..051800cb 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -7,9 +7,10 @@ Authorization = GithubObject( "Authorization", BaseUrl( lambda obj: "/authorizations/" + str( obj.id ) ), ### @todo make the lambda return a tuple, and BaseUrl convert elements to strings and join them with "/" InternalSimpleAttributes( - ### @todo + "id", "url", "scopes", "token", "app", "note", "note_url", "updated_at", + "created_at", ), - Editable( [], [] ), ### @todo + Editable( [], [ "scopes", "add_scopes", "remove_scopes", "note", "note_url" ] ), Deletable(), ) @@ -43,8 +44,8 @@ AuthenticatedUser = GithubObject( ExternalListOfObjects( "authorizations", "authorization", Authorization, ListGetable( [], [] ), ElementGetable( [ "id" ], [] ), - ElementCreatable( [], [] ), ### @todo - ### url = "/authorizations", ### @todo + ElementCreatable( [], [ "scopes", "note", "note_url" ] ), + url = "/authorizations", ), ExternalListOfObjects( "keys", "key", UserKey, ListGetable( [], [] ), From df1143107cb3f59b53428c7fd1786def06ed50d6 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 17:56:50 +0000 Subject: [PATCH 09/56] Keys: step 2 --- ReferenceOfClasses.md | 16 ++++++++++++---- github/GithubObjects.py | 12 ++++++------ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/ReferenceOfClasses.md b/ReferenceOfClasses.md index 687e4a28..d26aed04 100644 --- a/ReferenceOfClasses.md +++ b/ReferenceOfClasses.md @@ -68,7 +68,7 @@ Keys ---- * `get_keys()`: list of `UserKey` * `get_key( id )`: `UserKey` -* `create_key()`: `UserKey` +* `create_key( title, key )`: `UserKey` Followers --------- @@ -714,7 +714,7 @@ Keys ---- * `get_keys()`: list of `RepositoryKey` * `get_key( id )`: `RepositoryKey` -* `create_key()`: `RepositoryKey` +* `create_key( title, key )`: `RepositoryKey` Collaborators ------------- @@ -817,10 +817,14 @@ Class `RepositoryKey` Attributes ---------- +* `url` +* `id` +* `title` +* `key` Modification ------------ -* `edit()` +* `edit( title, key )` Deletion -------- @@ -881,10 +885,14 @@ Class `UserKey` Attributes ---------- +* `url` +* `id` +* `title` +* `key` Modification ------------ -* `edit()` +* `edit( title, key )` Deletion -------- diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 051800cb..b0dca1b0 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -18,9 +18,9 @@ UserKey = GithubObject( "UserKey", BaseUrl( lambda obj: "/user/keys/" + str( obj.id ) ), InternalSimpleAttributes( - ### @todo + "url", "id", "title", "key", ), - Editable( [], [] ), ### @todo + Editable( [ "title", "key" ], [] ), Deletable(), ) @@ -50,7 +50,7 @@ AuthenticatedUser = GithubObject( ExternalListOfObjects( "keys", "key", UserKey, ListGetable( [], [] ), ElementGetable( [ "id" ], [] ), - ElementCreatable( [], [] ), ### @todo + ElementCreatable( [ "title", "key" ], [] ), ), ) @@ -373,10 +373,10 @@ RepositoryKey = GithubObject( "RepositoryKey", BaseUrl( lambda obj: obj._repo._baseUrl + "/keys/" + str( obj.id ) ), InternalSimpleAttributes( - ### @todo + "url", "id", "title", "key", "_repo", ### Ugly hack ), - Editable( [], [] ), ### @todo + Editable( [ "title", "key" ], [] ), Deletable() ) @@ -412,7 +412,7 @@ Repository._addAttributePolicy( SeveralAttributePolicies( [ ExternalListOfObjects( "keys", "key", RepositoryKey, ListGetable( [], [] ), ElementGetable( [ "id" ], [], __modifyAttributesForObjectsReferingRepo ), - ElementCreatable( [], [] ), ### @todo + ElementCreatable( [ "title", "key" ], [] ), ), ExternalListOfObjects( "collaborators", "collaborator", NamedUser, ListGetable( [], [] ), From a7acdb6078455a8824f780deb00ef43292fa769b Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 18:45:24 +0000 Subject: [PATCH 10/56] On the way to modular integration test --- .gitignore | 2 +- NewIntegrationTest.py | 147 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 NewIntegrationTest.py diff --git a/.gitignore b/.gitignore index 2afca92c..fcca9d01 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ GithubCredentials.py .coverage /dist /MANIFEST -ReplayDataForIntegrationTest.txt +ReplayDataForIntegrationTest*.txt diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py new file mode 100644 index 00000000..a26ae7f2 --- /dev/null +++ b/NewIntegrationTest.py @@ -0,0 +1,147 @@ +#!/bin/env python + +import time +import sys +import httplib +import base64 + +from github import Github + +class RecordingHttpsConnection: + class HttpResponse( object ): + def __init__( self, file, res ): + self.status = res.status + self.__headers = res.getheaders() + self.__output = res.read() + file.write( str( self.status ) + "\n" ) + file.write( str( self.__headers ) + "\n" ) + file.write( str( self.__output ) + "\n" ) + + def getheaders( self ): + return self.__headers + + def read( self ): + return self.__output + + __realHttpsConnection = httplib.HTTPSConnection + + def __init__( self, file, *args, **kwds ): + self.__file = file + self.__cnx = self.__realHttpsConnection( *args, **kwds ) + + def request( self, verb, url, input, headers ): + self.__cnx.request( verb, url, input, headers ) + del headers[ "Authorization" ] # Do not let sensitive info in git :-p + self.__file.write( verb + " " + url + " " + str( headers ) + " " + input + "\n" ) + + def getresponse( self ): + return RecordingHttpsConnection.HttpResponse( self.__file, self.__cnx.getresponse() ) + + def close( self ): + self.__file.write( "\n" ) + return self.__cnx.close() + +class ReplayingHttpsConnection: + class HttpResponse( object ): + def __init__( self, file ): + self.status = int( file.readline().strip() ) + self.__headers = eval( file.readline().strip() ) + self.__output = file.readline().strip() + + def getheaders( self ): + return self.__headers + + def read( self ): + return self.__output + + def __init__( self, file ): + self.__file = file + + def request( self, verb, url, input, headers ): + del headers[ "Authorization" ] + assert self.__file.readline().strip() == verb + " " + url + " " + str( headers ) + " " + input + + def getresponse( self ): + return ReplayingHttpsConnection.HttpResponse( self.__file ) + + def close( self ): + self.__file.readline() + +class IntegrationTest: + cobayeNamedUserLogin = "cjuniet" + + def main( self, argv ): + if len( argv ) >= 1: + if argv[ 0 ] == "--record": + print "Record mode: this script is really going to do requests to github.com" + argv = argv[ 1: ] + record = True + elif argv[ 0 ] == "--list": + print "List of available tests:" + print "\n".join( self.listTests() ) + return + else: + print "Replay mode: this script will used requests to and replies from github.com recorded in previous runs in record mode" + record = False + + if len( argv ) == 0: + tests = self.listTests() + else: + tests = argv + self.runTests( tests, record ) + + def prepareRecord( self, test ): + self.avoidError500FromGithub = lambda: time.sleep( 1 ) + try: + import GithubCredentials + self.g = Github( GithubCredentials.login, GithubCredentials.password ) + file = open( self.__fileName( test ), "w" ) + httplib.HTTPSConnection = lambda *args, **kwds: RecordingHttpsConnection( file, *args, **kwds ) + except ImportError: + print "Please create a 'GithubCredentials.py' file containing:" + print "login = ''" + print "password = ''" + exit( 1 ) + + def prepareReplay( self, test ): + self.avoidError500FromGithub = lambda: 0 + try: + file = open( self.__fileName( test ) ) + httplib.HTTPSConnection = lambda *args, **kwds: ReplayingHttpsConnection( file ) + self.g = Github( "login", "password" ) + except IOError: + print "Please re-run this script with argument '--record' to be able to replay the integration tests based on recorded first execution" + exit( 1 ) + + def __fileName( self, test ): + return "ReplayDataForIntegrationTest." + test + ".txt" + + def listTests( self ): + return [ f[ 4: ] for f in dir( self ) if f.startswith( "test" ) ] + + def runTests( self, tests, record ): + for test in tests: + print + print test + if record: + self.prepareRecord( test ) + else: + self.prepareReplay( test ) + getattr( self, "test" + test )() + + def testAuthenticatedUserEdition( self ): + print "Changing your user name (and reseting it)" + u = self.g.get_user() + originalName = u.name + tmpName = u.name + " (edited by PyGithub)" + print self.g.get_user().name, "->", + u.edit( name = tmpName ) + print self.g.get_user().name, "->", + u.edit( name = originalName ) + print self.g.get_user().name + + def testNamedUserDetails( self ): + u = self.g.get_user( self.cobayeNamedUserLogin ) + print u.login, "(" + u.name + ") is from", u.location + +IntegrationTest().main( sys.argv[ 1: ] ) From bd377941b954ae767112028e0d99098ec05c02b3 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 18:53:23 +0000 Subject: [PATCH 11/56] Do not break the integration test if some test was never recorded --- NewIntegrationTest.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index a26ae7f2..a5cb2665 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -67,6 +67,9 @@ class ReplayingHttpsConnection: def close( self ): self.__file.readline() +class RecordReplayException( Exception ): + pass + class IntegrationTest: cobayeNamedUserLogin = "cjuniet" @@ -98,10 +101,10 @@ class IntegrationTest: file = open( self.__fileName( test ), "w" ) httplib.HTTPSConnection = lambda *args, **kwds: RecordingHttpsConnection( file, *args, **kwds ) except ImportError: - print "Please create a 'GithubCredentials.py' file containing:" - print "login = ''" - print "password = ''" - exit( 1 ) + raise RecordReplayException( textwrap.dedent( """\ + Please create a 'GithubCredentials.py' file containing:" + login = ''" + password = ''""" ) ) def prepareReplay( self, test ): self.avoidError500FromGithub = lambda: 0 @@ -110,8 +113,7 @@ class IntegrationTest: httplib.HTTPSConnection = lambda *args, **kwds: ReplayingHttpsConnection( file ) self.g = Github( "login", "password" ) except IOError: - print "Please re-run this script with argument '--record' to be able to replay the integration tests based on recorded first execution" - exit( 1 ) + raise RecordReplayException( "Please re-run this script with argument '--record' to be able to replay the integration tests based on recorded first execution" ) def __fileName( self, test ): return "ReplayDataForIntegrationTest." + test + ".txt" @@ -123,11 +125,16 @@ class IntegrationTest: for test in tests: print print test - if record: - self.prepareRecord( test ) - else: - self.prepareReplay( test ) - getattr( self, "test" + test )() + try: + if record: + self.prepareRecord( test ) + else: + self.prepareReplay( test ) + getattr( self, "test" + test )() + except RecordReplayException, e: + print "*" * len( str( e ) ) + print e + print "*" * len( str( e ) ) def testAuthenticatedUserEdition( self ): print "Changing your user name (and reseting it)" @@ -144,4 +151,8 @@ class IntegrationTest: u = self.g.get_user( self.cobayeNamedUserLogin ) print u.login, "(" + u.name + ") is from", u.location + def testOrganizationDetails( self ): + o = self.g.get_organization( "github" ) + print o.login, "(" + o.name + ") is in", o.location + IntegrationTest().main( sys.argv[ 1: ] ) From 415dc856e6ec5f62710ed03d0c9ceebfc484ae67 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 19:09:06 +0000 Subject: [PATCH 12/56] More integration test --- NewIntegrationTest.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index a5cb2665..69b3ff30 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -141,18 +141,25 @@ class IntegrationTest: u = self.g.get_user() originalName = u.name tmpName = u.name + " (edited by PyGithub)" - print self.g.get_user().name, "->", + print u.name, "->", u.edit( name = tmpName ) - print self.g.get_user().name, "->", + print u.name, "->", u.edit( name = originalName ) - print self.g.get_user().name + print u.name def testNamedUserDetails( self ): u = self.g.get_user( self.cobayeNamedUserLogin ) print u.login, "(" + u.name + ") is from", u.location + self.printList( "Repos", u.get_repos(), lambda r: r.name ) def testOrganizationDetails( self ): o = self.g.get_organization( "github" ) print o.login, "(" + o.name + ") is in", o.location + self.printList( "Public members", o.get_public_members(), lambda m: m.login ) + self.printList( "Members", o.get_members(), lambda m: m.login ) + self.printList( "Repos", o.get_repos(), lambda r: r.name ) + + def printList( self, title, iterable, f = lambda x: x ): + print title + ":", ", ".join( f( x ) for x in iterable[ :10 ] ), "..." if len( iterable ) > 10 else "" IntegrationTest().main( sys.argv[ 1: ] ) From e7feab272ef530f0fcb72f9762d9d5a72edcf14e Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 19:37:44 +0000 Subject: [PATCH 13/56] More integration test --- NewIntegrationTest.py | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index 69b3ff30..70428579 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -7,6 +7,11 @@ import base64 from github import Github +### @todo From ReplayDataForIntegrationTest.*.txt files and ReferenceOfApis.md, build a coverage of the API by the integration test + +class RecordReplayException( Exception ): + pass + class RecordingHttpsConnection: class HttpResponse( object ): def __init__( self, file, res ): @@ -59,7 +64,8 @@ class ReplayingHttpsConnection: def request( self, verb, url, input, headers ): del headers[ "Authorization" ] - assert self.__file.readline().strip() == verb + " " + url + " " + str( headers ) + " " + input + if( self.__file.readline().strip() != verb + " " + url + " " + str( headers ) + " " + input ): + raise RecordReplayException( "This test has been changed since last record. Please re-run this script with argument '--record'" ) def getresponse( self ): return ReplayingHttpsConnection.HttpResponse( self.__file ) @@ -67,11 +73,9 @@ class ReplayingHttpsConnection: def close( self ): self.__file.readline() -class RecordReplayException( Exception ): - pass - class IntegrationTest: - cobayeNamedUserLogin = "cjuniet" + cobayeUser = "Lyloa" + cobayeOrganization = "BeaverSoftware" def main( self, argv ): if len( argv ) >= 1: @@ -113,7 +117,7 @@ class IntegrationTest: httplib.HTTPSConnection = lambda *args, **kwds: ReplayingHttpsConnection( file ) self.g = Github( "login", "password" ) except IOError: - raise RecordReplayException( "Please re-run this script with argument '--record' to be able to replay the integration tests based on recorded first execution" ) + raise RecordReplayException( "This test has never been recorded. Please re-run this script with argument '--record'" ) def __fileName( self, test ): return "ReplayDataForIntegrationTest." + test + ".txt" @@ -136,7 +140,7 @@ class IntegrationTest: print e print "*" * len( str( e ) ) - def testAuthenticatedUserEdition( self ): + def testEditAuthenticatedUser( self ): print "Changing your user name (and reseting it)" u = self.g.get_user() originalName = u.name @@ -148,7 +152,7 @@ class IntegrationTest: print u.name def testNamedUserDetails( self ): - u = self.g.get_user( self.cobayeNamedUserLogin ) + u = self.g.get_user( self.cobayeUser ) print u.login, "(" + u.name + ") is from", u.location self.printList( "Repos", u.get_repos(), lambda r: r.name ) @@ -159,6 +163,24 @@ class IntegrationTest: self.printList( "Members", o.get_members(), lambda m: m.login ) self.printList( "Repos", o.get_repos(), lambda r: r.name ) + def testEditOrganization( self ): + o = self.g.get_organization( self.cobayeOrganization ) + r = o.create_repo( "TestPyGithub" ) + t = o.create_team( "PyGithubTesters", permission = "push" ) + self.printList( "Teams", o.get_teams(), lambda t: t.name ) + u = self.g.get_user( self.cobayeUser ) + print t.name, t.has_in_repos( r ), t.has_in_members( u ) + t.add_to_members( u ) + t.add_to_repos( r ) + print t.name, t.has_in_repos( r ), t.has_in_members( u ) + self.printList( "Team members", t.get_members(), lambda m: m.login ) + self.printList( "Team repos", t.get_repos(), lambda r: r.name ) + t.remove_from_members( u ) + t.remove_from_repos( r ) + print t.name, t.has_in_repos( r ), t.has_in_members( u ) + t.delete() + self.printList( "Teams", o.get_teams(), lambda t: t.name ) + def printList( self, title, iterable, f = lambda x: x ): print title + ":", ", ".join( f( x ) for x in iterable[ :10 ] ), "..." if len( iterable ) > 10 else "" From fe6154911d50db18fecfa1c9b11e884e8ce4f60e Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 20:24:01 +0000 Subject: [PATCH 14/56] Analyse integration test coverage. Improve coverage of Organization --- NewIntegrationTest.py | 73 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 4 deletions(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index 70428579..d03655b5 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -1,5 +1,6 @@ #!/bin/env python +import re import time import sys import httplib @@ -35,6 +36,7 @@ class RecordingHttpsConnection: self.__cnx = self.__realHttpsConnection( *args, **kwds ) def request( self, verb, url, input, headers ): + print verb, url self.__cnx.request( verb, url, input, headers ) del headers[ "Authorization" ] # Do not let sensitive info in git :-p self.__file.write( verb + " " + url + " " + str( headers ) + " " + input + "\n" ) @@ -97,6 +99,8 @@ class IntegrationTest: tests = argv self.runTests( tests, record ) + self.analyseCoverage() + def prepareRecord( self, test ): self.avoidError500FromGithub = lambda: time.sleep( 1 ) try: @@ -140,6 +144,38 @@ class IntegrationTest: print e print "*" * len( str( e ) ) + def analyseCoverage( self ): + coveredUrls = dict() + for test in self.listTests(): + with open( self.__fileName( test ) ) as file: + requests = [ line.strip() for line in file.readlines() ][ 0 : : 5 ] + for request in requests: + verb, url = request.split( " " )[ 0 : 2 ] + if url not in coveredUrls: + coveredUrls[ url ] = set() + coveredUrls[ url ].add( verb ) + + uncoveredMethods = set() + with open( "ReferenceOfApis.md" ) as file: + for line in file.readlines(): + line = line.strip() + if line.startswith( "API" ): + currentApi = line[ 5 : -1 ] + apiRegex = re.sub( ":\w+", "\w+", currentApi ) + if line.startswith( "* " ) and line.endswith( "`" ): + verb = line[ 2 : line.find( ":" ) ] + for url, verbs in coveredUrls.iteritems(): + if re.match( apiRegex, url ) and verb in verbs: + break + else: + uncoveredMethods.add( line[ line.find( "`" ) + 1 : -1 ] ) + + if len( uncoveredMethods ) != 0: + print + print "Not covered:" + print "\n".join( sorted( uncoveredMethods ) ) + #print "\n".join( sorted( m for m in uncoveredMethods if m.startswith( "Org" ) ) ) + def testEditAuthenticatedUser( self ): print "Changing your user name (and reseting it)" u = self.g.get_user() @@ -163,21 +199,50 @@ class IntegrationTest: self.printList( "Members", o.get_members(), lambda m: m.login ) self.printList( "Repos", o.get_repos(), lambda r: r.name ) - def testEditOrganization( self ): + def testEditOrganizationTeamAndMembers( self ): o = self.g.get_organization( self.cobayeOrganization ) r = o.create_repo( "TestPyGithub" ) + + self.printList( "Teams", o.get_teams(), lambda t: t.name ) t = o.create_team( "PyGithubTesters", permission = "push" ) self.printList( "Teams", o.get_teams(), lambda t: t.name ) + u = self.g.get_user( self.cobayeUser ) - print t.name, t.has_in_repos( r ), t.has_in_members( u ) + + self.printList( "Team members", t.get_members(), lambda m: m.login ) + self.printList( "Team repos", t.get_repos(), lambda r: r.name ) + assert not t.has_in_repos( r ) + assert not t.has_in_members( u ) t.add_to_members( u ) t.add_to_repos( r ) - print t.name, t.has_in_repos( r ), t.has_in_members( u ) + assert t.has_in_repos( r ) + assert t.has_in_members( u ) + self.printList( "Team members", t.get_members(), lambda m: m.login ) + self.printList( "Team repos", t.get_repos(), lambda r: r.name ) + + self.printList( "Public members", o.get_public_members(), lambda m: m.login ) + o.add_to_public_members( u ) + assert o.has_in_public_members( u ) + self.printList( "Public members", o.get_public_members(), lambda m: m.login ) + o.remove_from_public_members( u ) + assert not o.has_in_public_members( u ) + self.printList( "Public members", o.get_public_members(), lambda m: m.login ) + + self.printList( "Members", o.get_members(), lambda m: m.login ) + assert o.has_in_members( u ) + o.remove_from_members( u ) + assert not o.has_in_members( u ) + self.printList( "Members", o.get_members(), lambda m: m.login ) + self.printList( "Team members", t.get_members(), lambda m: m.login ) self.printList( "Team repos", t.get_repos(), lambda r: r.name ) t.remove_from_members( u ) t.remove_from_repos( r ) - print t.name, t.has_in_repos( r ), t.has_in_members( u ) + assert not t.has_in_repos( r ) + assert not t.has_in_members( u ) + self.printList( "Team members", t.get_members(), lambda m: m.login ) + self.printList( "Team repos", t.get_repos(), lambda r: r.name ) + t.delete() self.printList( "Teams", o.get_teams(), lambda t: t.name ) From 0a102985d22f0591d479af44f6285bb2b941f09e Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 20:31:16 +0000 Subject: [PATCH 15/56] Organization.edit --- NewIntegrationTest.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index d03655b5..375f60e1 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -174,16 +174,13 @@ class IntegrationTest: print print "Not covered:" print "\n".join( sorted( uncoveredMethods ) ) - #print "\n".join( sorted( m for m in uncoveredMethods if m.startswith( "Org" ) ) ) def testEditAuthenticatedUser( self ): - print "Changing your user name (and reseting it)" u = self.g.get_user() originalName = u.name - tmpName = u.name + " (edited by PyGithub)" - print u.name, "->", - u.edit( name = tmpName ) - print u.name, "->", + print u.name + u.edit( name = u.name + " (edited by PyGithub)" ) + print u.name u.edit( name = originalName ) print u.name @@ -199,6 +196,15 @@ class IntegrationTest: self.printList( "Members", o.get_members(), lambda m: m.login ) self.printList( "Repos", o.get_repos(), lambda r: r.name ) + def testEditOrganization( self ): + o = self.g.get_organization( self.cobayeOrganization ) + originalName = o.name + print o.name + o.edit( name = str( o.name ) + " (edited by PyGithub)" ) + print o.name + o.edit( name = originalName ) + print o.name + def testEditOrganizationTeamAndMembers( self ): o = self.g.get_organization( self.cobayeOrganization ) r = o.create_repo( "TestPyGithub" ) From 26fe6d8b2f50e7e7c3874883699901e2fe0100b6 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 20:39:52 +0000 Subject: [PATCH 16/56] Watching and Following --- NewIntegrationTest.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index 375f60e1..a4a38e5f 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -80,18 +80,20 @@ class IntegrationTest: cobayeOrganization = "BeaverSoftware" def main( self, argv ): + record = False if len( argv ) >= 1: if argv[ 0 ] == "--record": - print "Record mode: this script is really going to do requests to github.com" argv = argv[ 1: ] record = True elif argv[ 0 ] == "--list": print "List of available tests:" print "\n".join( self.listTests() ) return + + if record: + print "Record mode: this script is really going to do requests to github.com" else: print "Replay mode: this script will used requests to and replies from github.com recorded in previous runs in record mode" - record = False if len( argv ) == 0: tests = self.listTests() @@ -184,6 +186,25 @@ class IntegrationTest: u.edit( name = originalName ) print u.name + def testFollow( self ): + cobaye = self.g.get_user( self.cobayeUser ) + u = self.g.get_user() + u.remove_from_following( cobaye ) + assert not u.has_in_following( cobaye ) + u.add_to_following( cobaye ) + assert u.has_in_following( cobaye ) + self.printList( "Following", u.get_following(), lambda f: f.login ) + self.printList( "Followers", u.get_followers(), lambda f: f.login ) + + def testWatch( self ): + r = self.g.get_user( "jacquev6" ).get_repo( "PyGithub" ) + u = self.g.get_user() + u.remove_from_watched( r ) + assert not u.has_in_watched( r ) + u.add_to_watched( r ) + assert u.has_in_watched( r ) + self.printList( "Watched", u.get_watched(), lambda r: r.name ) + def testNamedUserDetails( self ): u = self.g.get_user( self.cobayeUser ) print u.login, "(" + u.name + ") is from", u.location From d796d289eb32f9bd228fd530bf37f6f354d357c7 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 20:51:24 +0000 Subject: [PATCH 17/56] Test UserKey --- NewIntegrationTest.py | 11 +++++++++++ github/GithubObjects.py | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index a4a38e5f..3773cbc7 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -273,6 +273,17 @@ class IntegrationTest: t.delete() self.printList( "Teams", o.get_teams(), lambda t: t.name ) + def testKeys( self ): + u = self.g.get_user() + self.printList( "Keys", u.get_keys(), lambda k: k.title ) + k = u.create_key( "vincent@PyGithub", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvborozfBBn2a+JETqPekTWZ1tmYjpfH9wTKFPLjIXQmxXjNye6HVgvi+iMI436RdoLsPEFDe3cjrQ6CJa7KzhRJKNTPh5EZbKI13CXfMGr7V1i3tOokXBFSRQKnDx2dj2hnswqxGUk2jXpgC/KA1q71yqnL45CBlWr50eDpwUIEPnmqSrPpRV/0ZGwIlh4o7+6HwPUF9aBhWj945WSkjZubR4UFWlDZl7ROafpkJHs2cQzaxtmBOZnu6dzmfyro0zJsvhZKD2K6d9eKgpDeKaw5rWr6FeOZPd4xyDaV1gctG0YEui8uuSPKhpcykgREUAFf+vmOKt+yXnOoq8P4vIQ==" ) + self.printList( "Keys", u.get_keys(), lambda k: k.title ) + k.edit( title = "vincent@PyGithub2" ) + k = u.get_key( k.id ) + self.printList( "Keys", u.get_keys(), lambda k: k.title ) + k.delete() + self.printList( "Keys", u.get_keys(), lambda k: k.title ) + def printList( self, title, iterable, f = lambda x: x ): print title + ":", ", ".join( f( x ) for x in iterable[ :10 ] ), "..." if len( iterable ) > 10 else "" diff --git a/github/GithubObjects.py b/github/GithubObjects.py index b0dca1b0..d74e500e 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -20,7 +20,7 @@ UserKey = GithubObject( InternalSimpleAttributes( "url", "id", "title", "key", ), - Editable( [ "title", "key" ], [] ), + Editable( [], [ "title", "key" ] ), Deletable(), ) From 600ca2390a61d1a23118842e657a23bd1e41a846 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 21:01:36 +0000 Subject: [PATCH 18/56] Integration test --- NewIntegrationTest.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index 3773cbc7..eacedbf6 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -135,6 +135,7 @@ class IntegrationTest: for test in tests: print print test + print "=" * len( test ) try: if record: self.prepareRecord( test ) @@ -174,7 +175,7 @@ class IntegrationTest: if len( uncoveredMethods ) != 0: print - print "Not covered:" + print "Not covered (" + str( len( uncoveredMethods ) ) + "):" print "\n".join( sorted( uncoveredMethods ) ) def testEditAuthenticatedUser( self ): @@ -276,9 +277,9 @@ class IntegrationTest: def testKeys( self ): u = self.g.get_user() self.printList( "Keys", u.get_keys(), lambda k: k.title ) - k = u.create_key( "vincent@PyGithub", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvborozfBBn2a+JETqPekTWZ1tmYjpfH9wTKFPLjIXQmxXjNye6HVgvi+iMI436RdoLsPEFDe3cjrQ6CJa7KzhRJKNTPh5EZbKI13CXfMGr7V1i3tOokXBFSRQKnDx2dj2hnswqxGUk2jXpgC/KA1q71yqnL45CBlWr50eDpwUIEPnmqSrPpRV/0ZGwIlh4o7+6HwPUF9aBhWj945WSkjZubR4UFWlDZl7ROafpkJHs2cQzaxtmBOZnu6dzmfyro0zJsvhZKD2K6d9eKgpDeKaw5rWr6FeOZPd4xyDaV1gctG0YEui8uuSPKhpcykgREUAFf+vmOKt+yXnOoq8P4vIQ==" ) + k = u.create_key( u.login + "@PyGithub", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvborozfBBn2a+JETqPekTWZ1tmYjpfH9wTKFPLjIXQmxXjNye6HVgvi+iMI436RdoLsPEFDe3cjrQ6CJa7KzhRJKNTPh5EZbKI13CXfMGr7V1i3tOokXBFSRQKnDx2dj2hnswqxGUk2jXpgC/KA1q71yqnL45CBlWr50eDpwUIEPnmqSrPpRV/0ZGwIlh4o7+6HwPUF9aBhWj945WSkjZubR4UFWlDZl7ROafpkJHs2cQzaxtmBOZnu6dzmfyro0zJsvhZKD2K6d9eKgpDeKaw5rWr6FeOZPd4xyDaV1gctG0YEui8uuSPKhpcykgREUAFf+vmOKt+yXnOoq8P4vIQ==" ) self.printList( "Keys", u.get_keys(), lambda k: k.title ) - k.edit( title = "vincent@PyGithub2" ) + k.edit( title = u.login + "@PyGithub2" ) k = u.get_key( k.id ) self.printList( "Keys", u.get_keys(), lambda k: k.title ) k.delete() From cbd7e2be6539848856eee00eb3a9e9587985e261 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 07:55:37 +0000 Subject: [PATCH 19/56] CreateForkForOrganization --- NewIntegrationTest.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index eacedbf6..9d0d2cb9 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -227,9 +227,15 @@ class IntegrationTest: o.edit( name = originalName ) print o.name + def testCreateForkForOrganization( self ): + o = self.g.get_organization( self.cobayeOrganization ) + r = self.g.get_user().get_repo( "TestPyGithub" ) + rf = o.create_fork( r ) + print r.owner.login + "/" + r.name, "->", rf.owner.login + "/" + rf.name + def testEditOrganizationTeamAndMembers( self ): o = self.g.get_organization( self.cobayeOrganization ) - r = o.create_repo( "TestPyGithub" ) + r = o.get_repo( "TestPyGithub" ) self.printList( "Teams", o.get_teams(), lambda t: t.name ) t = o.create_team( "PyGithubTesters", permission = "push" ) From 98c7953681a95bc3ead726d1ff79924a1a9543a0 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 08:58:15 +0000 Subject: [PATCH 20/56] Git objects --- NewIntegrationTest.py | 23 +++++++++++++++++++++++ github/GithubObjects.py | 25 ++++++++++++------------- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index 9d0d2cb9..eb70d889 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -291,6 +291,29 @@ class IntegrationTest: k.delete() self.printList( "Keys", u.get_keys(), lambda k: k.title ) + def testGitObjects( self ): + o = self.g.get_organization( self.cobayeOrganization ) + r = o.get_repo( "TestPyGithub" ) + + masterRef = r.get_git_ref( "refs/heads/master" ) + masterCommit = r.get_git_commit( masterRef.object[ "sha" ] ) + masterTree = r.get_git_tree( masterCommit.tree.sha ) + readmeBlob = None + for element in masterTree.tree: + if element[ "path" ] == "ReadMe.md": + readmeBlob = r.get_git_blob( element[ "sha" ] ) + break + + blob = r.create_git_blob( "This blob was created by PyGithub", encoding = "latin1" ) + tree = r.create_git_tree( [ { "path": "foo.bar", "mode": "100644", "type": "blob", "sha": blob.sha }, { "path": "ReadMe.md", "mode": "100644", "type": "blob", "sha": readmeBlob.sha } ] ) + commit = r.create_git_commit( "This commit was created by PyGithub", tree.sha, [ masterCommit.sha ] ) + r.create_git_ref( "refs/heads/previous_master", masterRef.object[ "sha" ] ) + masterRef.edit( commit.sha ) + + tag = r.create_git_tag( "tagCreatedByPyGithub", "This tag was created by PyGithub", commit.sha, "commit" ) + r.create_git_ref( "refs/tags/tagCreatedByPyGithub", tag.sha ) + reTag = r.get_git_tag( tag.sha ) + def printList( self, title, iterable, f = lambda x: x ): print title + ":", ", ".join( f( x ) for x in iterable[ :10 ] ), "..." if len( iterable ) > 10 else "" diff --git a/github/GithubObjects.py b/github/GithubObjects.py index d74e500e..2eac6927 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -144,19 +144,6 @@ GitRef = GithubObject( Editable( [ "sha" ], [ "force" ] ), ) -GitCommit = GithubObject( - "GitCommit", - BaseUrl( lambda obj: obj._repo._baseUrl + "/git/commits/" + obj.sha ), - InternalSimpleAttributes( - "sha", "url", "message", - "author", ### @todo Structure - "committer", ### @todo Structure - "tree", ### @todo Structure - "parents", ### @todo Structure - "_repo", ### Ugly hack - ), -) - GitTree = GithubObject( "GitTree", BaseUrl( lambda obj: obj._repo._baseUrl + "/git/trees/" + obj.sha ), @@ -167,6 +154,18 @@ GitTree = GithubObject( ), ) +GitCommit = GithubObject( + "GitCommit", + BaseUrl( lambda obj: obj._repo._baseUrl + "/git/commits/" + obj.sha ), + InternalSimpleAttributes( + "sha", "url", "message", + "parents", ### @todo Structure + "author", "committer", + "_repo", ### Ugly hack + ), + InternalObjectAttribute( "tree", GitTree ), +) + GitBlob = GithubObject( "GitBlob", BaseUrl( lambda obj: obj._repo._baseUrl + "/git/blobs/" + obj.sha ), From e10aa3eb07c6b4b2b8c3872cdd3cfd91fd15fc97 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 10:13:37 +0000 Subject: [PATCH 21/56] Emails --- NewIntegrationTest.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index eb70d889..03c02770 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -314,6 +314,14 @@ class IntegrationTest: r.create_git_ref( "refs/tags/tagCreatedByPyGithub", tag.sha ) reTag = r.get_git_tag( tag.sha ) + def testEmails( self ): + u = self.g.get_user() + self.printList( "Emails", u.get_emails() ) + u.add_to_emails( "ab@xxx.com", "cd@xxx.com" ) + self.printList( "Emails", u.get_emails() ) + u.remove_from_emails( "ab@xxx.com", "cd@xxx.com" ) + self.printList( "Emails", u.get_emails() ) + def printList( self, title, iterable, f = lambda x: x ): print title + ":", ", ".join( f( x ) for x in iterable[ :10 ] ), "..." if len( iterable ) > 10 else "" From b4dbc8cd86d6ee31a7c28c21a019e586ff708110 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 10:16:19 +0000 Subject: [PATCH 22/56] Reorder integration test --- NewIntegrationTest.py | 92 +++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index 03c02770..640623b0 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -178,6 +178,12 @@ class IntegrationTest: print "Not covered (" + str( len( uncoveredMethods ) ) + "):" print "\n".join( sorted( uncoveredMethods ) ) + def testCreateForkForOrganization( self ): + o = self.g.get_organization( self.cobayeOrganization ) + r = self.g.get_user().get_repo( "TestPyGithub" ) + rf = o.create_fork( r ) + print r.owner.login + "/" + r.name, "->", rf.owner.login + "/" + rf.name + def testEditAuthenticatedUser( self ): u = self.g.get_user() originalName = u.name @@ -187,37 +193,6 @@ class IntegrationTest: u.edit( name = originalName ) print u.name - def testFollow( self ): - cobaye = self.g.get_user( self.cobayeUser ) - u = self.g.get_user() - u.remove_from_following( cobaye ) - assert not u.has_in_following( cobaye ) - u.add_to_following( cobaye ) - assert u.has_in_following( cobaye ) - self.printList( "Following", u.get_following(), lambda f: f.login ) - self.printList( "Followers", u.get_followers(), lambda f: f.login ) - - def testWatch( self ): - r = self.g.get_user( "jacquev6" ).get_repo( "PyGithub" ) - u = self.g.get_user() - u.remove_from_watched( r ) - assert not u.has_in_watched( r ) - u.add_to_watched( r ) - assert u.has_in_watched( r ) - self.printList( "Watched", u.get_watched(), lambda r: r.name ) - - def testNamedUserDetails( self ): - u = self.g.get_user( self.cobayeUser ) - print u.login, "(" + u.name + ") is from", u.location - self.printList( "Repos", u.get_repos(), lambda r: r.name ) - - def testOrganizationDetails( self ): - o = self.g.get_organization( "github" ) - print o.login, "(" + o.name + ") is in", o.location - self.printList( "Public members", o.get_public_members(), lambda m: m.login ) - self.printList( "Members", o.get_members(), lambda m: m.login ) - self.printList( "Repos", o.get_repos(), lambda r: r.name ) - def testEditOrganization( self ): o = self.g.get_organization( self.cobayeOrganization ) originalName = o.name @@ -227,12 +202,6 @@ class IntegrationTest: o.edit( name = originalName ) print o.name - def testCreateForkForOrganization( self ): - o = self.g.get_organization( self.cobayeOrganization ) - r = self.g.get_user().get_repo( "TestPyGithub" ) - rf = o.create_fork( r ) - print r.owner.login + "/" + r.name, "->", rf.owner.login + "/" + rf.name - def testEditOrganizationTeamAndMembers( self ): o = self.g.get_organization( self.cobayeOrganization ) r = o.get_repo( "TestPyGithub" ) @@ -280,16 +249,15 @@ class IntegrationTest: t.delete() self.printList( "Teams", o.get_teams(), lambda t: t.name ) - def testKeys( self ): + def testFollow( self ): + cobaye = self.g.get_user( self.cobayeUser ) u = self.g.get_user() - self.printList( "Keys", u.get_keys(), lambda k: k.title ) - k = u.create_key( u.login + "@PyGithub", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvborozfBBn2a+JETqPekTWZ1tmYjpfH9wTKFPLjIXQmxXjNye6HVgvi+iMI436RdoLsPEFDe3cjrQ6CJa7KzhRJKNTPh5EZbKI13CXfMGr7V1i3tOokXBFSRQKnDx2dj2hnswqxGUk2jXpgC/KA1q71yqnL45CBlWr50eDpwUIEPnmqSrPpRV/0ZGwIlh4o7+6HwPUF9aBhWj945WSkjZubR4UFWlDZl7ROafpkJHs2cQzaxtmBOZnu6dzmfyro0zJsvhZKD2K6d9eKgpDeKaw5rWr6FeOZPd4xyDaV1gctG0YEui8uuSPKhpcykgREUAFf+vmOKt+yXnOoq8P4vIQ==" ) - self.printList( "Keys", u.get_keys(), lambda k: k.title ) - k.edit( title = u.login + "@PyGithub2" ) - k = u.get_key( k.id ) - self.printList( "Keys", u.get_keys(), lambda k: k.title ) - k.delete() - self.printList( "Keys", u.get_keys(), lambda k: k.title ) + u.remove_from_following( cobaye ) + assert not u.has_in_following( cobaye ) + u.add_to_following( cobaye ) + assert u.has_in_following( cobaye ) + self.printList( "Following", u.get_following(), lambda f: f.login ) + self.printList( "Followers", u.get_followers(), lambda f: f.login ) def testGitObjects( self ): o = self.g.get_organization( self.cobayeOrganization ) @@ -314,6 +282,38 @@ class IntegrationTest: r.create_git_ref( "refs/tags/tagCreatedByPyGithub", tag.sha ) reTag = r.get_git_tag( tag.sha ) + def testKeys( self ): + u = self.g.get_user() + self.printList( "Keys", u.get_keys(), lambda k: k.title ) + k = u.create_key( u.login + "@PyGithub", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvborozfBBn2a+JETqPekTWZ1tmYjpfH9wTKFPLjIXQmxXjNye6HVgvi+iMI436RdoLsPEFDe3cjrQ6CJa7KzhRJKNTPh5EZbKI13CXfMGr7V1i3tOokXBFSRQKnDx2dj2hnswqxGUk2jXpgC/KA1q71yqnL45CBlWr50eDpwUIEPnmqSrPpRV/0ZGwIlh4o7+6HwPUF9aBhWj945WSkjZubR4UFWlDZl7ROafpkJHs2cQzaxtmBOZnu6dzmfyro0zJsvhZKD2K6d9eKgpDeKaw5rWr6FeOZPd4xyDaV1gctG0YEui8uuSPKhpcykgREUAFf+vmOKt+yXnOoq8P4vIQ==" ) + self.printList( "Keys", u.get_keys(), lambda k: k.title ) + k.edit( title = u.login + "@PyGithub2" ) + k = u.get_key( k.id ) + self.printList( "Keys", u.get_keys(), lambda k: k.title ) + k.delete() + self.printList( "Keys", u.get_keys(), lambda k: k.title ) + + def testNamedUserDetails( self ): + u = self.g.get_user( self.cobayeUser ) + print u.login, "(" + u.name + ") is from", u.location + self.printList( "Repos", u.get_repos(), lambda r: r.name ) + + def testOrganizationDetails( self ): + o = self.g.get_organization( "github" ) + print o.login, "(" + o.name + ") is in", o.location + self.printList( "Public members", o.get_public_members(), lambda m: m.login ) + self.printList( "Members", o.get_members(), lambda m: m.login ) + self.printList( "Repos", o.get_repos(), lambda r: r.name ) + + def testWatch( self ): + r = self.g.get_user( "jacquev6" ).get_repo( "PyGithub" ) + u = self.g.get_user() + u.remove_from_watched( r ) + assert not u.has_in_watched( r ) + u.add_to_watched( r ) + assert u.has_in_watched( r ) + self.printList( "Watched", u.get_watched(), lambda r: r.name ) + def testEmails( self ): u = self.g.get_user() self.printList( "Emails", u.get_emails() ) From c7dc02e529b87d81eb45233d9103f197e608442f Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 10:28:10 +0000 Subject: [PATCH 23/56] More NamedUser coverage --- NewIntegrationTest.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index 640623b0..1fc3d429 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -294,9 +294,14 @@ class IntegrationTest: self.printList( "Keys", u.get_keys(), lambda k: k.title ) def testNamedUserDetails( self ): - u = self.g.get_user( self.cobayeUser ) + u = self.g.get_user( "jacquev6" ) print u.login, "(" + u.name + ") is from", u.location self.printList( "Repos", u.get_repos(), lambda r: r.name ) + self.printList( "Followers", u.get_followers(), lambda m: m.login ) + self.printList( "Following", u.get_following(), lambda m: m.login ) + self.printList( "Watched", u.get_watched(), lambda r: r.owner.login + "/" + r.name ) + self.printList( "Organizations", u.get_orgs(), lambda o: o.login ) + self.printList( "Gists", u.get_gists(), lambda g: g.description ) def testOrganizationDetails( self ): o = self.g.get_organization( "github" ) From dfe9ded1e481ef6aea0d3df0c4d12df1cb1f1a4d Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 10:30:38 +0000 Subject: [PATCH 24/56] Coverage --- NewIntegrationTest.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index 1fc3d429..3f803db0 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -8,8 +8,6 @@ import base64 from github import Github -### @todo From ReplayDataForIntegrationTest.*.txt files and ReferenceOfApis.md, build a coverage of the API by the integration test - class RecordReplayException( Exception ): pass @@ -101,7 +99,8 @@ class IntegrationTest: tests = argv self.runTests( tests, record ) - self.analyseCoverage() + if not record: + self.analyseCoverage() def prepareRecord( self, test ): self.avoidError500FromGithub = lambda: time.sleep( 1 ) From ae81345d06311446375c8c614fa23a7e20e52f56 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 11:10:12 +0000 Subject: [PATCH 25/56] testIssuesAndMilestones --- NewIntegrationTest.py | 56 +++++++++++++++++++++++++++++++++ github/GithubObject.UnitTest.py | 4 +++ github/GithubObjects.py | 2 +- 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index 3f803db0..1070a038 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -281,6 +281,62 @@ class IntegrationTest: r.create_git_ref( "refs/tags/tagCreatedByPyGithub", tag.sha ) reTag = r.get_git_tag( tag.sha ) + def testIssuesAndMilestones( self ): + u = self.g.get_user() + r = u.get_repo( "TestPyGithub" ) + + self.printList( "Issues", r.get_issues(), lambda i: i.title ) + i = r.create_issue( "Issue created by PyGithub" ) + self.printList( "Issues", r.get_issues(), lambda i: i.title ) + i.edit( body = "Issue edited by PyGithub" ) + + self.printList( "Comments on issue", i.get_comments(), lambda c: c.body ) + c = i.create_comment( "Comment created by PyGithub" ) + self.printList( "Comments on issue", i.get_comments(), lambda c: c.body ) + c.edit( "Comment edited by PyGithub" ) + sameComment = i.get_comment( c.id ) + self.printList( "Comments on issue", i.get_comments(), lambda c: c.body ) + c.delete() + self.printList( "Comments on issue", i.get_comments(), lambda c: c.body ) + + self.printList( "Milestones", r.get_milestones(), lambda m: m.title ) + m = r.create_milestone( "Milestone created by PyGithub" ) + self.printList( "Milestones", r.get_milestones(), lambda m: m.title ) + m.edit( title = "Milestone edited by PyGithub" ) + self.printList( "Milestones", r.get_milestones(), lambda m: m.title ) + + self.printList( "Issues of milestone", r.get_issues( milestone = m.number ), lambda i: i.title ) + i.edit( milestone = m.number ) + self.printList( "Issues of milestone", r.get_issues( milestone = m.number ), lambda i: i.title ) + + self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) + labelD = r.create_label( "D", "FF0000" ) + self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) + ### @todo Uncomment after fixing bug about BaseUrl depending on editable attribute + # labelD.edit( "Dada", "00FF00" ) + # self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) + labelD.delete() + self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) + + labelA = r.get_label( "bug" ) + labelB = r.get_label( "duplicate" ) + labelC = r.get_label( "invalid" ) + + self.printList( "Labels", i.get_labels(), lambda l: l.name ) + i.set_labels( labelA, labelB ) + self.printList( "Labels", i.get_labels(), lambda l: l.name ) + i.remove_from_labels( labelB ) + self.printList( "Labels", i.get_labels(), lambda l: l.name ) + i.delete_labels() + self.printList( "Labels", i.get_labels(), lambda l: l.name ) + i.add_to_labels( labelB, labelC ) + self.printList( "Labels", i.get_labels(), lambda l: l.name ) + + self.printList( "Milestone labels", r.get_milestone( m.number ).get_labels(), lambda l: l.name ) + + m.delete() + self.printList( "Milestones", r.get_milestones(), lambda m: m.title ) + def testKeys( self ): u = self.g.get_user() self.printList( "Keys", u.get_keys(), lambda k: k.title ) diff --git a/github/GithubObject.UnitTest.py b/github/GithubObject.UnitTest.py index d4f90921..e1848b89 100644 --- a/github/GithubObject.UnitTest.py +++ b/github/GithubObject.UnitTest.py @@ -3,6 +3,10 @@ import MockMockMock from GithubObject import * +### @todo add a test where BaseUrl depends on some editable attribute. +### Show that BaseUrl is faithfull to the edited attribute +### (currently not the case for Label, whish has a BaseUrl depending on its name) + class GithubObjectTestCase( unittest.TestCase ): def testDuplicatedAttributeInOnePolicy( self ): with self.assertRaises( BadGithubObjectException ): diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 2eac6927..10332435 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -220,7 +220,7 @@ Milestone = GithubObject( IssueComment = GithubObject( "IssueComment", - BaseUrl( lambda obj: obj._repo._baseUrl + "/issues/comment" + str( obj.id ) ), + BaseUrl( lambda obj: obj._repo._baseUrl + "/issues/comments/" + str( obj.id ) ), InternalSimpleAttributes( "url", "body", "created_at", "updated_at", "id", "_repo", ### Ugly hack From b24d995b4c8b2072d0d3aadafa350e960485d93f Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 11:23:29 +0000 Subject: [PATCH 26/56] CreateRepo --- NewIntegrationTest.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index 1070a038..67f537a1 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -183,6 +183,14 @@ class IntegrationTest: rf = o.create_fork( r ) print r.owner.login + "/" + r.name, "->", rf.owner.login + "/" + rf.name + def testCreateRepoForOrganization( self ): + o = self.g.get_organization( self.cobayeOrganization ) + r = o.create_repo( "CreatedByPyGithub", has_wiki = False ) + + def testCreateRepoForUser( self ): + u = self.g.get_user() + r = u.create_repo( "CreatedByPyGithub", has_wiki = False ) + def testEditAuthenticatedUser( self ): u = self.g.get_user() originalName = u.name From db4b8a1512e48ff786548c43b8fac17b978396c2 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 11:53:37 +0000 Subject: [PATCH 27/56] Gists --- NewIntegrationTest.py | 32 ++++++++++++++++++++++++++++++++ github/GithubObjects.py | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py index 67f537a1..b3e03ad2 100644 --- a/NewIntegrationTest.py +++ b/NewIntegrationTest.py @@ -266,6 +266,38 @@ class IntegrationTest: self.printList( "Following", u.get_following(), lambda f: f.login ) self.printList( "Followers", u.get_followers(), lambda f: f.login ) + def testGists( self ): + u = self.g.get_user() + self.printList( "Gists", u.get_gists(), lambda g: g.description ) + g = u.create_gist( public = True, description = "Gist created by PyGithub", files = { "foo.bar": { "content": "This gist was created by PyGithub" } } ) + self.printList( "Gists", u.get_gists(), lambda g: g.description ) + g.edit( description = "Gist edited by PyGithub" ) + self.printList( "Gists", u.get_gists(), lambda g: g.description ) + + self.printList( "Starred gists", u.get_starred_gists(), lambda g: g.description ) + g.set_starred() + assert g.is_starred() + self.printList( "Starred gists", u.get_starred_gists(), lambda g: g.description ) + g.reset_starred() + self.printList( "Starred gists", u.get_starred_gists(), lambda g: g.description ) + + self.printList( "Gist comments", g.get_comments(), lambda c: c.body ) + c = g.create_comment( "Comment created by PyGithub" ) + self.printList( "Gist comments", g.get_comments(), lambda c: c.body ) + c.edit( "Comment edited by PyGithub" ) + self.printList( "Gist comments", g.get_comments(), lambda c: c.body ) + sameComment = g.get_comment( c.id ) + c.delete() + self.printList( "Gist comments", g.get_comments(), lambda c: c.body ) + + otherGist = self.g.get_gist( 1965703 ).create_fork() # Origin gist picked up randomly + self.printList( "Gists", u.get_gists(), lambda g: g.description or "None" ) + otherGist.delete() + self.printList( "Gists", u.get_gists(), lambda g: g.description ) + + g.delete() + self.printList( "Gists", u.get_gists(), lambda g: g.description ) + def testGitObjects( self ): o = self.g.get_organization( self.cobayeOrganization ) r = o.get_repo( "TestPyGithub" ) diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 10332435..723ded55 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -610,7 +610,7 @@ Gist = GithubObject( ], "Starring" ), ) def __createFork( gist ): - return Gist( gitst._github, gist._github._dataRequest( "POST", gist._baseUrl + "/fork", None, None ), lazy = True ) + return Gist( gist._github, gist._github._dataRequest( "POST", gist._baseUrl + "/fork", None, None ), lazy = True ) Gist._addAttributePolicy( SeveralAttributePolicies( [ MethodFromCallable( "create_fork", [], [], __createFork, ObjectTypePolicy( Gist ) ), ], "Forking" ), From 77d38c0be6192e184b3120c31be5eb84c1832aaa Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 11:58:08 +0000 Subject: [PATCH 28/56] NewIntegrationTest -> IntegrationTest --- IntegrationTest.py | 553 ++++++++++++++++++++++++++---------------- NewIntegrationTest.py | 428 -------------------------------- 2 files changed, 350 insertions(+), 631 deletions(-) delete mode 100644 NewIntegrationTest.py diff --git a/IntegrationTest.py b/IntegrationTest.py index 953890f1..b3e03ad2 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -1,5 +1,6 @@ #!/bin/env python +import re import time import sys import httplib @@ -7,22 +8,25 @@ import base64 from github import Github -class RecordingHttpResponse( object ): - def __init__( self, file, res ): - self.status = res.status - self.__headers = res.getheaders() - self.__output = res.read() - file.write( str( self.status ) + "\n" ) - file.write( str( self.__headers ) + "\n" ) - file.write( str( self.__output ) + "\n" ) - - def getheaders( self ): - return self.__headers - - def read( self ): - return self.__output +class RecordReplayException( Exception ): + pass class RecordingHttpsConnection: + class HttpResponse( object ): + def __init__( self, file, res ): + self.status = res.status + self.__headers = res.getheaders() + self.__output = res.read() + file.write( str( self.status ) + "\n" ) + file.write( str( self.__headers ) + "\n" ) + file.write( str( self.__output ) + "\n" ) + + def getheaders( self ): + return self.__headers + + def read( self ): + return self.__output + __realHttpsConnection = httplib.HTTPSConnection def __init__( self, file, *args, **kwds ): @@ -30,252 +34,395 @@ class RecordingHttpsConnection: self.__cnx = self.__realHttpsConnection( *args, **kwds ) def request( self, verb, url, input, headers ): + print verb, url self.__cnx.request( verb, url, input, headers ) del headers[ "Authorization" ] # Do not let sensitive info in git :-p self.__file.write( verb + " " + url + " " + str( headers ) + " " + input + "\n" ) def getresponse( self ): - return RecordingHttpResponse( self.__file, self.__cnx.getresponse() ) + return RecordingHttpsConnection.HttpResponse( self.__file, self.__cnx.getresponse() ) def close( self ): self.__file.write( "\n" ) return self.__cnx.close() -class ReplayingHttpResponse( object ): - def __init__( self, file ): - self.status = int( file.readline().strip() ) - self.__headers = eval( file.readline().strip() ) - self.__output = file.readline().strip() - - def getheaders( self ): - return self.__headers - - def read( self ): - return self.__output - class ReplayingHttpsConnection: + class HttpResponse( object ): + def __init__( self, file ): + self.status = int( file.readline().strip() ) + self.__headers = eval( file.readline().strip() ) + self.__output = file.readline().strip() + + def getheaders( self ): + return self.__headers + + def read( self ): + return self.__output + def __init__( self, file ): self.__file = file def request( self, verb, url, input, headers ): del headers[ "Authorization" ] - assert self.__file.readline().strip() == verb + " " + url + " " + str( headers ) + " " + input + if( self.__file.readline().strip() != verb + " " + url + " " + str( headers ) + " " + input ): + raise RecordReplayException( "This test has been changed since last record. Please re-run this script with argument '--record'" ) def getresponse( self ): - return ReplayingHttpResponse( self.__file ) + return ReplayingHttpsConnection.HttpResponse( self.__file ) def close( self ): self.__file.readline() class IntegrationTest: - __fileName = "ReplayDataForIntegrationTest.txt" + cobayeUser = "Lyloa" + cobayeOrganization = "BeaverSoftware" - def main( self ): - if len( sys.argv ) == 2 and sys.argv[ 1 ] == "--record": - print "Record mode: I'm really going to do requests to github.com. Please type 'yes' and return" - sys.stdout.flush() - confirm = sys.stdin.readline().strip() - if confirm != "yes": - exit( 1 ) - self.record() + def main( self, argv ): + record = False + if len( argv ) >= 1: + if argv[ 0 ] == "--record": + argv = argv[ 1: ] + record = True + elif argv[ 0 ] == "--list": + print "List of available tests:" + print "\n".join( self.listTests() ) + return + + if record: + print "Record mode: this script is really going to do requests to github.com" else: - self.replay() + print "Replay mode: this script will used requests to and replies from github.com recorded in previous runs in record mode" - exit() + if len( argv ) == 0: + tests = self.listTests() + else: + tests = argv + self.runTests( tests, record ) - def record( self ): - self.prepareRecord() - self.playScenario() + if not record: + self.analyseCoverage() - def replay( self ): - self.prepareReplay() - self.playScenario() - - def prepareRecord( self ): + def prepareRecord( self, test ): self.avoidError500FromGithub = lambda: time.sleep( 1 ) try: import GithubCredentials self.g = Github( GithubCredentials.login, GithubCredentials.password ) - file = open( self.__fileName, "w" ) + file = open( self.__fileName( test ), "w" ) httplib.HTTPSConnection = lambda *args, **kwds: RecordingHttpsConnection( file, *args, **kwds ) except ImportError: - print "Please create a 'GithubCredentials.py' file containing:" - print "login = ''" - print "password = ''" - exit( 1 ) + raise RecordReplayException( textwrap.dedent( """\ + Please create a 'GithubCredentials.py' file containing:" + login = ''" + password = ''""" ) ) - def prepareReplay( self ): + def prepareReplay( self, test ): self.avoidError500FromGithub = lambda: 0 try: - file = open( self.__fileName ) + file = open( self.__fileName( test ) ) httplib.HTTPSConnection = lambda *args, **kwds: ReplayingHttpsConnection( file ) self.g = Github( "login", "password" ) except IOError: - print "Please re-run this script with argument '--record' to be able to replay the integration tests based on recorded first execution" - exit( 1 ) + raise RecordReplayException( "This test has never been recorded. Please re-run this script with argument '--record'" ) - def playScenario( self ): - self.doSomeWrites() - self.doSomeReads() + def __fileName( self, test ): + return "ReplayDataForIntegrationTest." + test + ".txt" - def doSomeReads( self ): - self.dumpUser( self.g.get_user(), doPrivateThings = True ) - jacquev6 = self.g.get_user( "jacquev6" ) - self.dumpUser( jacquev6, doPrivateThings = False ) - self.dumpOrganization( self.g.get_organization( "github" ), doTeams = False ) - self.dumpOrganization( self.g.get_organization( "BeaverSoftware" ), doTeams = True ) - self.dumpRepository( jacquev6.get_repo( "PyGithub" ) ) + def listTests( self ): + return [ f[ 4: ] for f in dir( self ) if f.startswith( "test" ) ] - def doSomeWrites( self ): - self.doSomeWritesToUser() - self.doSomeWritesToRepository() - self.doSomeWritesToGist() + def runTests( self, tests, record ): + for test in tests: + print + print test + print "=" * len( test ) + try: + if record: + self.prepareRecord( test ) + else: + self.prepareReplay( test ) + getattr( self, "test" + test )() + except RecordReplayException, e: + print "*" * len( str( e ) ) + print e + print "*" * len( str( e ) ) - def doSomeWritesToUser( self ): - u = self.g.get_user() - oldBio = u.bio - u.edit( bio = oldBio + " (Edited by PyGithub)" ) - u.edit( bio = oldBio ) - jacquev6 = self.g.get_user( "jacquev6" ) - u.remove_from_following( jacquev6 ) - u.add_to_following( jacquev6 ) - PyGithub = jacquev6.get_repo( "PyGithub" ) - u.remove_from_watched( PyGithub ) - u.add_to_watched( PyGithub ) + def analyseCoverage( self ): + coveredUrls = dict() + for test in self.listTests(): + with open( self.__fileName( test ) ) as file: + requests = [ line.strip() for line in file.readlines() ][ 0 : : 5 ] + for request in requests: + verb, url = request.split( " " )[ 0 : 2 ] + if url not in coveredUrls: + coveredUrls[ url ] = set() + coveredUrls[ url ].add( verb ) - def doSomeWritesToRepository( self ): - u = self.g.get_user() - r = u.create_repo( name = "TestPyGithub", description = "Created by PyGithub", has_wiki = False ) - self.avoidError500FromGithub() + uncoveredMethods = set() + with open( "ReferenceOfApis.md" ) as file: + for line in file.readlines(): + line = line.strip() + if line.startswith( "API" ): + currentApi = line[ 5 : -1 ] + apiRegex = re.sub( ":\w+", "\w+", currentApi ) + if line.startswith( "* " ) and line.endswith( "`" ): + verb = line[ 2 : line.find( ":" ) ] + for url, verbs in coveredUrls.iteritems(): + if re.match( apiRegex, url ) and verb in verbs: + break + else: + uncoveredMethods.add( line[ line.find( "`" ) + 1 : -1 ] ) - # Git objects - b1 = r.create_git_blob( "This blob was created by PyGithub", encoding = "latin1" ) - t1 = r.create_git_tree( [ { "path": "foo.bar", "mode": "100644", "type": "blob", "sha": b1.sha } ] ) - c1 = r.create_git_commit( "This commit was created by PyGithub", t1.sha, [] ) - master = r.create_git_ref( "refs/heads/master", c1.sha ) - b2 = r.create_git_blob( "This blob was also created by PyGithub", encoding = "latin1" ) - t2 = r.create_git_tree( [ { "path": "foo.bar", "mode": "100644", "type": "blob", "sha": b2.sha }, { "path": "old", "mode": "040000", "type": "tree", "sha": t1.sha } ] ) - c2 = r.create_git_commit( "This commit was also created by PyGithub", t2.sha, [ c1.sha ] ) - master.edit( c2.sha ) - tag = r.create_git_tag( "a_tag", "This tag was created by PyGithub", c2.sha, "commit" ) - r.create_git_ref( "refs/tags/a_tag", tag.sha ) - - c = r.get_commit( c2.sha ) - c.create_comment( "Commented with PyGithub", c.sha, 1, "foo.bar", 1 ) - - # Issues and milestones - l = r.create_label( "Label created by PyGithub", "00FF00" ) - l.edit( "Label created and modified by PyGithub", "FFFF00" ) - m = r.create_milestone( title = "This milestone was created by PyGithub" ) - m.edit( title = m.title, description = "And the description was modified by PyGithub as well" ) - m = r.create_milestone( title = "This milestone was also created by PyGithub" ) - m.delete() - i = r.create_issue( "Issue created by PyGithub" ) - i.edit( body = "Body edited by PyGithub" ) - - la = r.create_label( "a", "00FF00" ) - lb = r.create_label( "b", "00FF00" ) - lc = r.create_label( "c", "00FF00" ) - i.set_labels( la, lb ) - i.remove_from_labels( lb ) - i.delete_labels() - i.add_to_labels( lc ) - - i.create_comment( "Commented from PyGithub" ) - - # Downloads - r.create_download( "MyDownloadCreatedByPyGithub", 1000 ) - - # Forking, commiting and requesting merge - o = self.g.get_organization( "BeaverSoftware" ) + if len( uncoveredMethods ) != 0: + print + print "Not covered (" + str( len( uncoveredMethods ) ) + "):" + print "\n".join( sorted( uncoveredMethods ) ) + def testCreateForkForOrganization( self ): + o = self.g.get_organization( self.cobayeOrganization ) + r = self.g.get_user().get_repo( "TestPyGithub" ) rf = o.create_fork( r ) - self.avoidError500FromGithub() - b3 = rf.create_git_blob( "This blob was ter created by PyGithub", encoding = "latin1" ) - t3 = rf.create_git_tree( [ { "path": "foo.bar", "mode": "100644", "type": "blob", "sha": b3.sha } ] ) - c3 = rf.create_git_commit( "This commit was ter created by PyGithub", t3.sha, [ c2.sha ] ) - rf.get_git_ref( "refs/heads/master" ).edit( c3.sha ) + print r.owner.login + "/" + r.name, "->", rf.owner.login + "/" + rf.name - p = r.create_pull( "Pull request created by PyGithub", "", "jacquev6:master", "BeaverSoftware:master" ) + def testCreateRepoForOrganization( self ): + o = self.g.get_organization( self.cobayeOrganization ) + r = o.create_repo( "CreatedByPyGithub", has_wiki = False ) - self.dumpRepository( r ) - - def doSomeWritesToGist( self ): + def testCreateRepoForUser( self ): u = self.g.get_user() - g = u.create_gist( True, { "foobar.txt": { "content": "Gist created by PyGithub" } }, "Gist created by PyGithub" ) - g.edit( "Gist edited by PyGithub" ) - g.create_comment( "Gist comment created by PyGithub" ) + r = u.create_repo( "CreatedByPyGithub", has_wiki = False ) + + def testEditAuthenticatedUser( self ): + u = self.g.get_user() + originalName = u.name + print u.name + u.edit( name = u.name + " (edited by PyGithub)" ) + print u.name + u.edit( name = originalName ) + print u.name + + def testEditOrganization( self ): + o = self.g.get_organization( self.cobayeOrganization ) + originalName = o.name + print o.name + o.edit( name = str( o.name ) + " (edited by PyGithub)" ) + print o.name + o.edit( name = originalName ) + print o.name + + def testEditOrganizationTeamAndMembers( self ): + o = self.g.get_organization( self.cobayeOrganization ) + r = o.get_repo( "TestPyGithub" ) + + self.printList( "Teams", o.get_teams(), lambda t: t.name ) + t = o.create_team( "PyGithubTesters", permission = "push" ) + self.printList( "Teams", o.get_teams(), lambda t: t.name ) + + u = self.g.get_user( self.cobayeUser ) + + self.printList( "Team members", t.get_members(), lambda m: m.login ) + self.printList( "Team repos", t.get_repos(), lambda r: r.name ) + assert not t.has_in_repos( r ) + assert not t.has_in_members( u ) + t.add_to_members( u ) + t.add_to_repos( r ) + assert t.has_in_repos( r ) + assert t.has_in_members( u ) + self.printList( "Team members", t.get_members(), lambda m: m.login ) + self.printList( "Team repos", t.get_repos(), lambda r: r.name ) + + self.printList( "Public members", o.get_public_members(), lambda m: m.login ) + o.add_to_public_members( u ) + assert o.has_in_public_members( u ) + self.printList( "Public members", o.get_public_members(), lambda m: m.login ) + o.remove_from_public_members( u ) + assert not o.has_in_public_members( u ) + self.printList( "Public members", o.get_public_members(), lambda m: m.login ) + + self.printList( "Members", o.get_members(), lambda m: m.login ) + assert o.has_in_members( u ) + o.remove_from_members( u ) + assert not o.has_in_members( u ) + self.printList( "Members", o.get_members(), lambda m: m.login ) + + self.printList( "Team members", t.get_members(), lambda m: m.login ) + self.printList( "Team repos", t.get_repos(), lambda r: r.name ) + t.remove_from_members( u ) + t.remove_from_repos( r ) + assert not t.has_in_repos( r ) + assert not t.has_in_members( u ) + self.printList( "Team members", t.get_members(), lambda m: m.login ) + self.printList( "Team repos", t.get_repos(), lambda r: r.name ) + + t.delete() + self.printList( "Teams", o.get_teams(), lambda t: t.name ) + + def testFollow( self ): + cobaye = self.g.get_user( self.cobayeUser ) + u = self.g.get_user() + u.remove_from_following( cobaye ) + assert not u.has_in_following( cobaye ) + u.add_to_following( cobaye ) + assert u.has_in_following( cobaye ) + self.printList( "Following", u.get_following(), lambda f: f.login ) + self.printList( "Followers", u.get_followers(), lambda f: f.login ) + + def testGists( self ): + u = self.g.get_user() + self.printList( "Gists", u.get_gists(), lambda g: g.description ) + g = u.create_gist( public = True, description = "Gist created by PyGithub", files = { "foo.bar": { "content": "This gist was created by PyGithub" } } ) + self.printList( "Gists", u.get_gists(), lambda g: g.description ) + g.edit( description = "Gist edited by PyGithub" ) + self.printList( "Gists", u.get_gists(), lambda g: g.description ) + + self.printList( "Starred gists", u.get_starred_gists(), lambda g: g.description ) g.set_starred() assert g.is_starred() + self.printList( "Starred gists", u.get_starred_gists(), lambda g: g.description ) g.reset_starred() - assert not g.is_starred() + self.printList( "Starred gists", u.get_starred_gists(), lambda g: g.description ) - def dumpUser( self, u, doPrivateThings ): - print u.login, "(", u.name, ")" - print " Gists:", ", ".join( g.description + "(" + ", ".join( c.body for c in g.get_comments() ) + ")" for g in u.get_gists() ) - if doPrivateThings: - print " Starred gists:", ", ".join( g.description for g in u.get_starred_gists() ) - print " Repos:" - for r in u.get_repos(): - print " ", r.name, - if r.fork: - print "<-", r.parent.owner.login + "/" + r.parent.name, - print "<-", r.source.owner.login + "/" + r.source.name, - print - if doPrivateThings: - print " Emails:", ", ".join( u.get_emails() ) - print " Watched:", ", ".join( r.name for r in u.get_watched() ) - print " Organizations:", ", ".join( o.login for o in u.get_orgs() ) - print " Following:", ", ".join( f.login for f in u.get_following() ) - if doPrivateThings: - print " Is following jacquev6:", u.has_in_following( self.g.get_user( "jacquev6" ) ) - print " Followers:", ", ".join( f.login for f in u.get_followers() ) - print - sys.stdout.flush() + self.printList( "Gist comments", g.get_comments(), lambda c: c.body ) + c = g.create_comment( "Comment created by PyGithub" ) + self.printList( "Gist comments", g.get_comments(), lambda c: c.body ) + c.edit( "Comment edited by PyGithub" ) + self.printList( "Gist comments", g.get_comments(), lambda c: c.body ) + sameComment = g.get_comment( c.id ) + c.delete() + self.printList( "Gist comments", g.get_comments(), lambda c: c.body ) - def dumpOrganization( self, o, doTeams ): - print o.login, "(", o.name, ")" - print " Members:", ", ".join( u.login for u in o.get_members() ) - print " Repos:", ", ".join( r.name for r in o.get_repos() ) - if doTeams: - print " Teams:" - for team in o.get_teams(): - print " ", team.name, "(" + team.permission + "):", ", ".join( u.login for u in team.get_members() ), "->", ", ".join( r.name for r in team.get_repos() ) - print - sys.stdout.flush() + otherGist = self.g.get_gist( 1965703 ).create_fork() # Origin gist picked up randomly + self.printList( "Gists", u.get_gists(), lambda g: g.description or "None" ) + otherGist.delete() + self.printList( "Gists", u.get_gists(), lambda g: g.description ) - def dumpRepository( self, r ): - print r.owner.login + "/" + r.name - print " Collaborators:", ", ".join( u.login for u in r.get_collaborators() ) - print " Contributors:", ", ".join( u.login for u in r.get_contributors() ) - print " Watchers:", ", ".join( u.login for u in r.get_watchers() ) - print " Forks:", ", ".join( f.owner.login + "/" + f.name for f in r.get_forks() ) - print " Languages:", r.get_languages() - print " Downloads:", ", ".join( d.name for d in r.get_downloads() ) - print " Tags:", ", ".join( t.name + " (" + t.commit.sha + ")" for t in r.get_tags() ) - print " Branches:", ", ".join( b.name + " (" + b.commit.sha + ")" for b in r.get_branches() ) - print " Commits:", ", ".join( c.commit.message + " (" + str( c.stats ) + " ".join( comment.body for comment in c.get_comments() ) + ")" for c in r.get_commits()[ : 10 ] ) - print " Git references:", ", ".join( ref.ref + " (" + ref.object[ "sha" ][ :7 ] + ")" for ref in r.get_git_refs() ) - masterCommitSha = r.get_git_ref( "refs/heads/master" ).object[ "sha" ] - masterCommit = r.get_git_commit( masterCommitSha ) - masterTreeSha = masterCommit.tree[ "sha" ] - masterTree = r.get_git_tree( masterTreeSha ) + g.delete() + self.printList( "Gists", u.get_gists(), lambda g: g.description ) + + def testGitObjects( self ): + o = self.g.get_organization( self.cobayeOrganization ) + r = o.get_repo( "TestPyGithub" ) + + masterRef = r.get_git_ref( "refs/heads/master" ) + masterCommit = r.get_git_commit( masterRef.object[ "sha" ] ) + masterTree = r.get_git_tree( masterCommit.tree.sha ) + readmeBlob = None for element in masterTree.tree: - if element[ "type" ] == "blob": - blobSha = element[ "sha" ] + if element[ "path" ] == "ReadMe.md": + readmeBlob = r.get_git_blob( element[ "sha" ] ) break - blob = r.get_git_blob( blobSha ) - print " Master:", masterCommitSha, masterCommit.message, ", ".join( element[ "path" ] + " (" + element[ "type" ] + ")" for element in masterTree.tree ) - print " blob:", blob.content, blob.encoding, - if blob.encoding == "base64": - print base64.b64decode( blob.content ), - print - print " Labels:", ", ".join( l.name + " (" + l.color + ")" for l in r.get_labels() ) - print " Issues:", ", ".join( i.title + " (" + ", ".join( l.name for l in i.get_labels() ) + ") (" + ", ".join( c.body for c in i.get_comments() ) + ")" for i in r.get_issues() ) - print " Milestones:", ", ".join( m.title + " (created by " + m.creator.login + ", " + ", ".join( l.name for l in m.get_labels() ) + ")" for m in r.get_milestones() ) - print " Closed milestones:", ", ".join( m.title for m in r.get_milestones( state = "closed" ) ) - print " Merge requests:", ", ".join( p.title + "(" + ", ".join( f.filename for f in p.get_files() ) + ")" for p in r.get_pulls() ) - print - sys.stdout.flush() -IntegrationTest().main() + blob = r.create_git_blob( "This blob was created by PyGithub", encoding = "latin1" ) + tree = r.create_git_tree( [ { "path": "foo.bar", "mode": "100644", "type": "blob", "sha": blob.sha }, { "path": "ReadMe.md", "mode": "100644", "type": "blob", "sha": readmeBlob.sha } ] ) + commit = r.create_git_commit( "This commit was created by PyGithub", tree.sha, [ masterCommit.sha ] ) + r.create_git_ref( "refs/heads/previous_master", masterRef.object[ "sha" ] ) + masterRef.edit( commit.sha ) + + tag = r.create_git_tag( "tagCreatedByPyGithub", "This tag was created by PyGithub", commit.sha, "commit" ) + r.create_git_ref( "refs/tags/tagCreatedByPyGithub", tag.sha ) + reTag = r.get_git_tag( tag.sha ) + + def testIssuesAndMilestones( self ): + u = self.g.get_user() + r = u.get_repo( "TestPyGithub" ) + + self.printList( "Issues", r.get_issues(), lambda i: i.title ) + i = r.create_issue( "Issue created by PyGithub" ) + self.printList( "Issues", r.get_issues(), lambda i: i.title ) + i.edit( body = "Issue edited by PyGithub" ) + + self.printList( "Comments on issue", i.get_comments(), lambda c: c.body ) + c = i.create_comment( "Comment created by PyGithub" ) + self.printList( "Comments on issue", i.get_comments(), lambda c: c.body ) + c.edit( "Comment edited by PyGithub" ) + sameComment = i.get_comment( c.id ) + self.printList( "Comments on issue", i.get_comments(), lambda c: c.body ) + c.delete() + self.printList( "Comments on issue", i.get_comments(), lambda c: c.body ) + + self.printList( "Milestones", r.get_milestones(), lambda m: m.title ) + m = r.create_milestone( "Milestone created by PyGithub" ) + self.printList( "Milestones", r.get_milestones(), lambda m: m.title ) + m.edit( title = "Milestone edited by PyGithub" ) + self.printList( "Milestones", r.get_milestones(), lambda m: m.title ) + + self.printList( "Issues of milestone", r.get_issues( milestone = m.number ), lambda i: i.title ) + i.edit( milestone = m.number ) + self.printList( "Issues of milestone", r.get_issues( milestone = m.number ), lambda i: i.title ) + + self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) + labelD = r.create_label( "D", "FF0000" ) + self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) + ### @todo Uncomment after fixing bug about BaseUrl depending on editable attribute + # labelD.edit( "Dada", "00FF00" ) + # self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) + labelD.delete() + self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) + + labelA = r.get_label( "bug" ) + labelB = r.get_label( "duplicate" ) + labelC = r.get_label( "invalid" ) + + self.printList( "Labels", i.get_labels(), lambda l: l.name ) + i.set_labels( labelA, labelB ) + self.printList( "Labels", i.get_labels(), lambda l: l.name ) + i.remove_from_labels( labelB ) + self.printList( "Labels", i.get_labels(), lambda l: l.name ) + i.delete_labels() + self.printList( "Labels", i.get_labels(), lambda l: l.name ) + i.add_to_labels( labelB, labelC ) + self.printList( "Labels", i.get_labels(), lambda l: l.name ) + + self.printList( "Milestone labels", r.get_milestone( m.number ).get_labels(), lambda l: l.name ) + + m.delete() + self.printList( "Milestones", r.get_milestones(), lambda m: m.title ) + + def testKeys( self ): + u = self.g.get_user() + self.printList( "Keys", u.get_keys(), lambda k: k.title ) + k = u.create_key( u.login + "@PyGithub", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvborozfBBn2a+JETqPekTWZ1tmYjpfH9wTKFPLjIXQmxXjNye6HVgvi+iMI436RdoLsPEFDe3cjrQ6CJa7KzhRJKNTPh5EZbKI13CXfMGr7V1i3tOokXBFSRQKnDx2dj2hnswqxGUk2jXpgC/KA1q71yqnL45CBlWr50eDpwUIEPnmqSrPpRV/0ZGwIlh4o7+6HwPUF9aBhWj945WSkjZubR4UFWlDZl7ROafpkJHs2cQzaxtmBOZnu6dzmfyro0zJsvhZKD2K6d9eKgpDeKaw5rWr6FeOZPd4xyDaV1gctG0YEui8uuSPKhpcykgREUAFf+vmOKt+yXnOoq8P4vIQ==" ) + self.printList( "Keys", u.get_keys(), lambda k: k.title ) + k.edit( title = u.login + "@PyGithub2" ) + k = u.get_key( k.id ) + self.printList( "Keys", u.get_keys(), lambda k: k.title ) + k.delete() + self.printList( "Keys", u.get_keys(), lambda k: k.title ) + + def testNamedUserDetails( self ): + u = self.g.get_user( "jacquev6" ) + print u.login, "(" + u.name + ") is from", u.location + self.printList( "Repos", u.get_repos(), lambda r: r.name ) + self.printList( "Followers", u.get_followers(), lambda m: m.login ) + self.printList( "Following", u.get_following(), lambda m: m.login ) + self.printList( "Watched", u.get_watched(), lambda r: r.owner.login + "/" + r.name ) + self.printList( "Organizations", u.get_orgs(), lambda o: o.login ) + self.printList( "Gists", u.get_gists(), lambda g: g.description ) + + def testOrganizationDetails( self ): + o = self.g.get_organization( "github" ) + print o.login, "(" + o.name + ") is in", o.location + self.printList( "Public members", o.get_public_members(), lambda m: m.login ) + self.printList( "Members", o.get_members(), lambda m: m.login ) + self.printList( "Repos", o.get_repos(), lambda r: r.name ) + + def testWatch( self ): + r = self.g.get_user( "jacquev6" ).get_repo( "PyGithub" ) + u = self.g.get_user() + u.remove_from_watched( r ) + assert not u.has_in_watched( r ) + u.add_to_watched( r ) + assert u.has_in_watched( r ) + self.printList( "Watched", u.get_watched(), lambda r: r.name ) + + def testEmails( self ): + u = self.g.get_user() + self.printList( "Emails", u.get_emails() ) + u.add_to_emails( "ab@xxx.com", "cd@xxx.com" ) + self.printList( "Emails", u.get_emails() ) + u.remove_from_emails( "ab@xxx.com", "cd@xxx.com" ) + self.printList( "Emails", u.get_emails() ) + + def printList( self, title, iterable, f = lambda x: x ): + print title + ":", ", ".join( f( x ) for x in iterable[ :10 ] ), "..." if len( iterable ) > 10 else "" + +IntegrationTest().main( sys.argv[ 1: ] ) diff --git a/NewIntegrationTest.py b/NewIntegrationTest.py deleted file mode 100644 index b3e03ad2..00000000 --- a/NewIntegrationTest.py +++ /dev/null @@ -1,428 +0,0 @@ -#!/bin/env python - -import re -import time -import sys -import httplib -import base64 - -from github import Github - -class RecordReplayException( Exception ): - pass - -class RecordingHttpsConnection: - class HttpResponse( object ): - def __init__( self, file, res ): - self.status = res.status - self.__headers = res.getheaders() - self.__output = res.read() - file.write( str( self.status ) + "\n" ) - file.write( str( self.__headers ) + "\n" ) - file.write( str( self.__output ) + "\n" ) - - def getheaders( self ): - return self.__headers - - def read( self ): - return self.__output - - __realHttpsConnection = httplib.HTTPSConnection - - def __init__( self, file, *args, **kwds ): - self.__file = file - self.__cnx = self.__realHttpsConnection( *args, **kwds ) - - def request( self, verb, url, input, headers ): - print verb, url - self.__cnx.request( verb, url, input, headers ) - del headers[ "Authorization" ] # Do not let sensitive info in git :-p - self.__file.write( verb + " " + url + " " + str( headers ) + " " + input + "\n" ) - - def getresponse( self ): - return RecordingHttpsConnection.HttpResponse( self.__file, self.__cnx.getresponse() ) - - def close( self ): - self.__file.write( "\n" ) - return self.__cnx.close() - -class ReplayingHttpsConnection: - class HttpResponse( object ): - def __init__( self, file ): - self.status = int( file.readline().strip() ) - self.__headers = eval( file.readline().strip() ) - self.__output = file.readline().strip() - - def getheaders( self ): - return self.__headers - - def read( self ): - return self.__output - - def __init__( self, file ): - self.__file = file - - def request( self, verb, url, input, headers ): - del headers[ "Authorization" ] - if( self.__file.readline().strip() != verb + " " + url + " " + str( headers ) + " " + input ): - raise RecordReplayException( "This test has been changed since last record. Please re-run this script with argument '--record'" ) - - def getresponse( self ): - return ReplayingHttpsConnection.HttpResponse( self.__file ) - - def close( self ): - self.__file.readline() - -class IntegrationTest: - cobayeUser = "Lyloa" - cobayeOrganization = "BeaverSoftware" - - def main( self, argv ): - record = False - if len( argv ) >= 1: - if argv[ 0 ] == "--record": - argv = argv[ 1: ] - record = True - elif argv[ 0 ] == "--list": - print "List of available tests:" - print "\n".join( self.listTests() ) - return - - if record: - print "Record mode: this script is really going to do requests to github.com" - else: - print "Replay mode: this script will used requests to and replies from github.com recorded in previous runs in record mode" - - if len( argv ) == 0: - tests = self.listTests() - else: - tests = argv - self.runTests( tests, record ) - - if not record: - self.analyseCoverage() - - def prepareRecord( self, test ): - self.avoidError500FromGithub = lambda: time.sleep( 1 ) - try: - import GithubCredentials - self.g = Github( GithubCredentials.login, GithubCredentials.password ) - file = open( self.__fileName( test ), "w" ) - httplib.HTTPSConnection = lambda *args, **kwds: RecordingHttpsConnection( file, *args, **kwds ) - except ImportError: - raise RecordReplayException( textwrap.dedent( """\ - Please create a 'GithubCredentials.py' file containing:" - login = ''" - password = ''""" ) ) - - def prepareReplay( self, test ): - self.avoidError500FromGithub = lambda: 0 - try: - file = open( self.__fileName( test ) ) - httplib.HTTPSConnection = lambda *args, **kwds: ReplayingHttpsConnection( file ) - self.g = Github( "login", "password" ) - except IOError: - raise RecordReplayException( "This test has never been recorded. Please re-run this script with argument '--record'" ) - - def __fileName( self, test ): - return "ReplayDataForIntegrationTest." + test + ".txt" - - def listTests( self ): - return [ f[ 4: ] for f in dir( self ) if f.startswith( "test" ) ] - - def runTests( self, tests, record ): - for test in tests: - print - print test - print "=" * len( test ) - try: - if record: - self.prepareRecord( test ) - else: - self.prepareReplay( test ) - getattr( self, "test" + test )() - except RecordReplayException, e: - print "*" * len( str( e ) ) - print e - print "*" * len( str( e ) ) - - def analyseCoverage( self ): - coveredUrls = dict() - for test in self.listTests(): - with open( self.__fileName( test ) ) as file: - requests = [ line.strip() for line in file.readlines() ][ 0 : : 5 ] - for request in requests: - verb, url = request.split( " " )[ 0 : 2 ] - if url not in coveredUrls: - coveredUrls[ url ] = set() - coveredUrls[ url ].add( verb ) - - uncoveredMethods = set() - with open( "ReferenceOfApis.md" ) as file: - for line in file.readlines(): - line = line.strip() - if line.startswith( "API" ): - currentApi = line[ 5 : -1 ] - apiRegex = re.sub( ":\w+", "\w+", currentApi ) - if line.startswith( "* " ) and line.endswith( "`" ): - verb = line[ 2 : line.find( ":" ) ] - for url, verbs in coveredUrls.iteritems(): - if re.match( apiRegex, url ) and verb in verbs: - break - else: - uncoveredMethods.add( line[ line.find( "`" ) + 1 : -1 ] ) - - if len( uncoveredMethods ) != 0: - print - print "Not covered (" + str( len( uncoveredMethods ) ) + "):" - print "\n".join( sorted( uncoveredMethods ) ) - - def testCreateForkForOrganization( self ): - o = self.g.get_organization( self.cobayeOrganization ) - r = self.g.get_user().get_repo( "TestPyGithub" ) - rf = o.create_fork( r ) - print r.owner.login + "/" + r.name, "->", rf.owner.login + "/" + rf.name - - def testCreateRepoForOrganization( self ): - o = self.g.get_organization( self.cobayeOrganization ) - r = o.create_repo( "CreatedByPyGithub", has_wiki = False ) - - def testCreateRepoForUser( self ): - u = self.g.get_user() - r = u.create_repo( "CreatedByPyGithub", has_wiki = False ) - - def testEditAuthenticatedUser( self ): - u = self.g.get_user() - originalName = u.name - print u.name - u.edit( name = u.name + " (edited by PyGithub)" ) - print u.name - u.edit( name = originalName ) - print u.name - - def testEditOrganization( self ): - o = self.g.get_organization( self.cobayeOrganization ) - originalName = o.name - print o.name - o.edit( name = str( o.name ) + " (edited by PyGithub)" ) - print o.name - o.edit( name = originalName ) - print o.name - - def testEditOrganizationTeamAndMembers( self ): - o = self.g.get_organization( self.cobayeOrganization ) - r = o.get_repo( "TestPyGithub" ) - - self.printList( "Teams", o.get_teams(), lambda t: t.name ) - t = o.create_team( "PyGithubTesters", permission = "push" ) - self.printList( "Teams", o.get_teams(), lambda t: t.name ) - - u = self.g.get_user( self.cobayeUser ) - - self.printList( "Team members", t.get_members(), lambda m: m.login ) - self.printList( "Team repos", t.get_repos(), lambda r: r.name ) - assert not t.has_in_repos( r ) - assert not t.has_in_members( u ) - t.add_to_members( u ) - t.add_to_repos( r ) - assert t.has_in_repos( r ) - assert t.has_in_members( u ) - self.printList( "Team members", t.get_members(), lambda m: m.login ) - self.printList( "Team repos", t.get_repos(), lambda r: r.name ) - - self.printList( "Public members", o.get_public_members(), lambda m: m.login ) - o.add_to_public_members( u ) - assert o.has_in_public_members( u ) - self.printList( "Public members", o.get_public_members(), lambda m: m.login ) - o.remove_from_public_members( u ) - assert not o.has_in_public_members( u ) - self.printList( "Public members", o.get_public_members(), lambda m: m.login ) - - self.printList( "Members", o.get_members(), lambda m: m.login ) - assert o.has_in_members( u ) - o.remove_from_members( u ) - assert not o.has_in_members( u ) - self.printList( "Members", o.get_members(), lambda m: m.login ) - - self.printList( "Team members", t.get_members(), lambda m: m.login ) - self.printList( "Team repos", t.get_repos(), lambda r: r.name ) - t.remove_from_members( u ) - t.remove_from_repos( r ) - assert not t.has_in_repos( r ) - assert not t.has_in_members( u ) - self.printList( "Team members", t.get_members(), lambda m: m.login ) - self.printList( "Team repos", t.get_repos(), lambda r: r.name ) - - t.delete() - self.printList( "Teams", o.get_teams(), lambda t: t.name ) - - def testFollow( self ): - cobaye = self.g.get_user( self.cobayeUser ) - u = self.g.get_user() - u.remove_from_following( cobaye ) - assert not u.has_in_following( cobaye ) - u.add_to_following( cobaye ) - assert u.has_in_following( cobaye ) - self.printList( "Following", u.get_following(), lambda f: f.login ) - self.printList( "Followers", u.get_followers(), lambda f: f.login ) - - def testGists( self ): - u = self.g.get_user() - self.printList( "Gists", u.get_gists(), lambda g: g.description ) - g = u.create_gist( public = True, description = "Gist created by PyGithub", files = { "foo.bar": { "content": "This gist was created by PyGithub" } } ) - self.printList( "Gists", u.get_gists(), lambda g: g.description ) - g.edit( description = "Gist edited by PyGithub" ) - self.printList( "Gists", u.get_gists(), lambda g: g.description ) - - self.printList( "Starred gists", u.get_starred_gists(), lambda g: g.description ) - g.set_starred() - assert g.is_starred() - self.printList( "Starred gists", u.get_starred_gists(), lambda g: g.description ) - g.reset_starred() - self.printList( "Starred gists", u.get_starred_gists(), lambda g: g.description ) - - self.printList( "Gist comments", g.get_comments(), lambda c: c.body ) - c = g.create_comment( "Comment created by PyGithub" ) - self.printList( "Gist comments", g.get_comments(), lambda c: c.body ) - c.edit( "Comment edited by PyGithub" ) - self.printList( "Gist comments", g.get_comments(), lambda c: c.body ) - sameComment = g.get_comment( c.id ) - c.delete() - self.printList( "Gist comments", g.get_comments(), lambda c: c.body ) - - otherGist = self.g.get_gist( 1965703 ).create_fork() # Origin gist picked up randomly - self.printList( "Gists", u.get_gists(), lambda g: g.description or "None" ) - otherGist.delete() - self.printList( "Gists", u.get_gists(), lambda g: g.description ) - - g.delete() - self.printList( "Gists", u.get_gists(), lambda g: g.description ) - - def testGitObjects( self ): - o = self.g.get_organization( self.cobayeOrganization ) - r = o.get_repo( "TestPyGithub" ) - - masterRef = r.get_git_ref( "refs/heads/master" ) - masterCommit = r.get_git_commit( masterRef.object[ "sha" ] ) - masterTree = r.get_git_tree( masterCommit.tree.sha ) - readmeBlob = None - for element in masterTree.tree: - if element[ "path" ] == "ReadMe.md": - readmeBlob = r.get_git_blob( element[ "sha" ] ) - break - - blob = r.create_git_blob( "This blob was created by PyGithub", encoding = "latin1" ) - tree = r.create_git_tree( [ { "path": "foo.bar", "mode": "100644", "type": "blob", "sha": blob.sha }, { "path": "ReadMe.md", "mode": "100644", "type": "blob", "sha": readmeBlob.sha } ] ) - commit = r.create_git_commit( "This commit was created by PyGithub", tree.sha, [ masterCommit.sha ] ) - r.create_git_ref( "refs/heads/previous_master", masterRef.object[ "sha" ] ) - masterRef.edit( commit.sha ) - - tag = r.create_git_tag( "tagCreatedByPyGithub", "This tag was created by PyGithub", commit.sha, "commit" ) - r.create_git_ref( "refs/tags/tagCreatedByPyGithub", tag.sha ) - reTag = r.get_git_tag( tag.sha ) - - def testIssuesAndMilestones( self ): - u = self.g.get_user() - r = u.get_repo( "TestPyGithub" ) - - self.printList( "Issues", r.get_issues(), lambda i: i.title ) - i = r.create_issue( "Issue created by PyGithub" ) - self.printList( "Issues", r.get_issues(), lambda i: i.title ) - i.edit( body = "Issue edited by PyGithub" ) - - self.printList( "Comments on issue", i.get_comments(), lambda c: c.body ) - c = i.create_comment( "Comment created by PyGithub" ) - self.printList( "Comments on issue", i.get_comments(), lambda c: c.body ) - c.edit( "Comment edited by PyGithub" ) - sameComment = i.get_comment( c.id ) - self.printList( "Comments on issue", i.get_comments(), lambda c: c.body ) - c.delete() - self.printList( "Comments on issue", i.get_comments(), lambda c: c.body ) - - self.printList( "Milestones", r.get_milestones(), lambda m: m.title ) - m = r.create_milestone( "Milestone created by PyGithub" ) - self.printList( "Milestones", r.get_milestones(), lambda m: m.title ) - m.edit( title = "Milestone edited by PyGithub" ) - self.printList( "Milestones", r.get_milestones(), lambda m: m.title ) - - self.printList( "Issues of milestone", r.get_issues( milestone = m.number ), lambda i: i.title ) - i.edit( milestone = m.number ) - self.printList( "Issues of milestone", r.get_issues( milestone = m.number ), lambda i: i.title ) - - self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) - labelD = r.create_label( "D", "FF0000" ) - self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) - ### @todo Uncomment after fixing bug about BaseUrl depending on editable attribute - # labelD.edit( "Dada", "00FF00" ) - # self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) - labelD.delete() - self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) - - labelA = r.get_label( "bug" ) - labelB = r.get_label( "duplicate" ) - labelC = r.get_label( "invalid" ) - - self.printList( "Labels", i.get_labels(), lambda l: l.name ) - i.set_labels( labelA, labelB ) - self.printList( "Labels", i.get_labels(), lambda l: l.name ) - i.remove_from_labels( labelB ) - self.printList( "Labels", i.get_labels(), lambda l: l.name ) - i.delete_labels() - self.printList( "Labels", i.get_labels(), lambda l: l.name ) - i.add_to_labels( labelB, labelC ) - self.printList( "Labels", i.get_labels(), lambda l: l.name ) - - self.printList( "Milestone labels", r.get_milestone( m.number ).get_labels(), lambda l: l.name ) - - m.delete() - self.printList( "Milestones", r.get_milestones(), lambda m: m.title ) - - def testKeys( self ): - u = self.g.get_user() - self.printList( "Keys", u.get_keys(), lambda k: k.title ) - k = u.create_key( u.login + "@PyGithub", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvborozfBBn2a+JETqPekTWZ1tmYjpfH9wTKFPLjIXQmxXjNye6HVgvi+iMI436RdoLsPEFDe3cjrQ6CJa7KzhRJKNTPh5EZbKI13CXfMGr7V1i3tOokXBFSRQKnDx2dj2hnswqxGUk2jXpgC/KA1q71yqnL45CBlWr50eDpwUIEPnmqSrPpRV/0ZGwIlh4o7+6HwPUF9aBhWj945WSkjZubR4UFWlDZl7ROafpkJHs2cQzaxtmBOZnu6dzmfyro0zJsvhZKD2K6d9eKgpDeKaw5rWr6FeOZPd4xyDaV1gctG0YEui8uuSPKhpcykgREUAFf+vmOKt+yXnOoq8P4vIQ==" ) - self.printList( "Keys", u.get_keys(), lambda k: k.title ) - k.edit( title = u.login + "@PyGithub2" ) - k = u.get_key( k.id ) - self.printList( "Keys", u.get_keys(), lambda k: k.title ) - k.delete() - self.printList( "Keys", u.get_keys(), lambda k: k.title ) - - def testNamedUserDetails( self ): - u = self.g.get_user( "jacquev6" ) - print u.login, "(" + u.name + ") is from", u.location - self.printList( "Repos", u.get_repos(), lambda r: r.name ) - self.printList( "Followers", u.get_followers(), lambda m: m.login ) - self.printList( "Following", u.get_following(), lambda m: m.login ) - self.printList( "Watched", u.get_watched(), lambda r: r.owner.login + "/" + r.name ) - self.printList( "Organizations", u.get_orgs(), lambda o: o.login ) - self.printList( "Gists", u.get_gists(), lambda g: g.description ) - - def testOrganizationDetails( self ): - o = self.g.get_organization( "github" ) - print o.login, "(" + o.name + ") is in", o.location - self.printList( "Public members", o.get_public_members(), lambda m: m.login ) - self.printList( "Members", o.get_members(), lambda m: m.login ) - self.printList( "Repos", o.get_repos(), lambda r: r.name ) - - def testWatch( self ): - r = self.g.get_user( "jacquev6" ).get_repo( "PyGithub" ) - u = self.g.get_user() - u.remove_from_watched( r ) - assert not u.has_in_watched( r ) - u.add_to_watched( r ) - assert u.has_in_watched( r ) - self.printList( "Watched", u.get_watched(), lambda r: r.name ) - - def testEmails( self ): - u = self.g.get_user() - self.printList( "Emails", u.get_emails() ) - u.add_to_emails( "ab@xxx.com", "cd@xxx.com" ) - self.printList( "Emails", u.get_emails() ) - u.remove_from_emails( "ab@xxx.com", "cd@xxx.com" ) - self.printList( "Emails", u.get_emails() ) - - def printList( self, title, iterable, f = lambda x: x ): - print title + ":", ", ".join( f( x ) for x in iterable[ :10 ] ), "..." if len( iterable ) > 10 else "" - -IntegrationTest().main( sys.argv[ 1: ] ) From 427b17cc27d1fdcb4160fe82be2aebe317697832 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 15:17:44 +0000 Subject: [PATCH 29/56] Restore test coverage --- github/Github.UnitTest.py | 23 ++++++++++ github/GithubObject.UnitTest.py | 57 +++++++++++++++++++++++++ github/ObjectCapacities/Basic.py | 1 - github/ObjectCapacities/List.py | 44 +++++++++---------- github/ObjectCapacities/TypePolicies.py | 5 +-- 5 files changed, 100 insertions(+), 30 deletions(-) diff --git a/github/Github.UnitTest.py b/github/Github.UnitTest.py index e3ddfb09..c1719c96 100644 --- a/github/Github.UnitTest.py +++ b/github/Github.UnitTest.py @@ -37,4 +37,27 @@ class TestCase( unittest.TestCase ): self.assertFalse( self.g.get_user().has_in_following( self.g.get_user( "xxx" ) ) ) self.assertTrue( self.g.get_user().has_in_following( self.g.get_user( "yyy" ) ) ) + def testGist( self ): + self.requester.expect.dataRequest( "GET", "/gists/123456", None, None ).andReturn( { "description": "xxx" } ) + g = self.g.get_gist( 123456 ) + self.assertEqual( g.description, "xxx" ) + self.requester.expect.statusRequest( "GET", "/gists/123456/star", None, None ).andReturn( 404 ) + self.assertFalse( g.is_starred() ) + self.requester.expect.statusRequest( "PUT", "/gists/123456/star", None, None ).andReturn( 204 ) + g.set_starred() + self.requester.expect.statusRequest( "DELETE", "/gists/123456/star", None, None ).andReturn( 204 ) + g.reset_starred() + self.requester.expect.dataRequest( "POST", "/gists/123456/fork", None, None ).andReturn( { "description": "yyy" } ) + self.assertEqual( g.create_fork().description, "yyy" ) + self.requester.expect.dataRequest( "GET", "/gists/starred", None, None ).andReturn( [ { "description": "xxx" }, { "description": "yyy" } ] ) + self.assertEqual( len( self.g.get_user().get_starred_gists() ), 2 ) + + def testRepositoryReference( self ): + self.requester.expect.dataRequest( "GET", "/user", None, None ).andReturn( { "login": "xxx" } ) + self.requester.expect.dataRequest( "GET", "/repos/xxx/yyy", None, None ).andReturn( { "name": "yyy", "owner": { "login": "xxx" } } ) + r = self.g.get_user().get_repo( "yyy" ) + self.requester.expect.dataRequest( "GET", "/repos/xxx/yyy/milestones/1", None, None ).andReturn( { "number": 1 } ) + self.requester.expect.dataRequest( "GET", "/repos/xxx/yyy/milestones/1/labels", {}, None ).andReturn( [ { "name": "a" } ] ) + self.assertIs( r.get_milestone( 1 ).get_labels()[ 0 ]._repo, r ) + unittest.main() diff --git a/github/GithubObject.UnitTest.py b/github/GithubObject.UnitTest.py index e1848b89..aeaf4cbf 100644 --- a/github/GithubObject.UnitTest.py +++ b/github/GithubObject.UnitTest.py @@ -21,6 +21,7 @@ class TestCaseWithGithubTestObject( unittest.TestCase ): unittest.TestCase.setUp( self ) self.g = MockMockMock.Mock( "github" ) self.o = self.GithubTestObject( self.g.object, { "a1": 1, "a2": 2 }, lazy = True ) + self.GithubTestObject._autoDocument() # Only for coverage def tearDown( self ): self.g.tearDown() @@ -47,6 +48,17 @@ class TestCaseWithGithubTestObject( unittest.TestCase ): def expectStatusDelete( self, url, data = None ): return self.g.expect._statusRequest( "DELETE", url, None, data ) +class GithubObjectWithDocumentationCoveringSpecialCases( TestCaseWithGithubTestObject ): + GithubTestObject = GithubObject( + "GithubTestObject", + BaseUrl( lambda obj: "/test" ), + InternalSimpleAttributes( "a1", "a2", "_a3" ), + MethodFromCallable( "myMethod", [ "mock", "arg" ], [], lambda obj: 42, ObjectTypePolicy( GithubObject ) ) + ) + + def testNothing( self ): + pass + class GithubObjectWithOnlyInternalSimpleAttributes( TestCaseWithGithubTestObject ): GithubTestObject = GithubObject( "GithubTestObject", @@ -232,6 +244,51 @@ class GithubObjectWithListGetableExternalListOfObjects( TestCaseWithGithubTestOb a3s = self.o.get_a3s( "foobar" ) self.assertEqual( len( a3s ), 3 ) +class GithubObjectWithListGetableExternalListOfObjectsWithOtherUrl( TestCaseWithGithubTestObject ): + ContainedObject = GithubObject( + "ContainedObject", + BaseUrl( lambda obj: "/other/" + obj.id ), + InternalSimpleAttributes( "id", "name" ) + ) + + GithubTestObject = GithubObject( + "GithubTestObject", + BaseUrl( lambda obj: "/test" ), + InternalSimpleAttributes( "a1", "a2" ), + ExternalListOfObjects( "a3s", "a3", ContainedObject, ListGetable( [], [ "type" ] ), url = "/other" ) + ) + + def testGetList( self ): + self.expectDataGet( "/other", {} ).andReturn( [ { "id": "id1" }, { "id": "id2" }, { "id": "id3" } ] ) + a3s = self.o.get_a3s() + self.assertEqual( len( a3s ), 3 ) + self.assertEqual( a3s[ 0 ].id, "id1" ) + self.expectDataGet( "/other/id1" ).andReturn( { "name": "name1" } ) + self.assertEqual( a3s[ 0 ].name, "name1" ) + +class GithubObjectWithListGetableExternalListOfObjectsWithAttributeModifier( TestCaseWithGithubTestObject ): + ContainedObject = GithubObject( + "ContainedObject", + BaseUrl( lambda obj: "/test/a3s/" + obj.id ), + InternalSimpleAttributes( "id", "name", "_a" ) + ) + + GithubTestObject = GithubObject( + "GithubTestObject", + BaseUrl( lambda obj: "/test" ), + InternalSimpleAttributes( "a1", "a2" ), + ExternalListOfObjects( "a3s", "a3", ContainedObject, ListGetable( [], [ "type" ], { "_a": lambda obj: 42 } ) ) + ) + + def testGetList( self ): + self.expectDataGet( "/test/a3s", {} ).andReturn( [ { "id": "id1" }, { "id": "id2" }, { "id": "id3" } ] ) + a3s = self.o.get_a3s() + self.assertEqual( len( a3s ), 3 ) + self.assertEqual( a3s[ 0 ].id, "id1" ) + self.assertEqual( a3s[ 0 ]._a, 42 ) + self.expectDataGet( "/test/a3s/id1" ).andReturn( { "name": "name1" } ) + self.assertEqual( a3s[ 0 ].name, "name1" ) + class GithubObjectWithElementAddableExternalListOfObjects( TestCaseWithGithubTestObject ): ContainedObject = GithubObject( "ContainedObject", diff --git a/github/ObjectCapacities/Basic.py b/github/ObjectCapacities/Basic.py index 30842fcc..cdf8fcf7 100644 --- a/github/ObjectCapacities/Basic.py +++ b/github/ObjectCapacities/Basic.py @@ -24,7 +24,6 @@ class AttributeFromCallable: def autoDocument( self ): return "" - return "* `" + self.__name + "`\n" ### @todo include the ArgumentsChecker class MethodFromCallable: diff --git a/github/ObjectCapacities/List.py b/github/ObjectCapacities/List.py index 76547bd7..0148c3f8 100644 --- a/github/ObjectCapacities/List.py +++ b/github/ObjectCapacities/List.py @@ -65,18 +65,27 @@ class ElementHasable( ListCapacity ): ### @todo `bool` -> bool return "* `has_in_" + self.safeAttributeName + "( " + self.singularName + " )`: `bool`\n * `" + self.singularName + "`: " + self.typePolicy.documentTypeName() + "\n" -class ElementCreatable( ListCapacity ): - def __init__( self, mandatoryParameters, optionalParameters, attributeModifiers = {} ): - self.__argumentsChecker = ArgumentsChecker( mandatoryParameters, optionalParameters ) +class ListCapacityWithModifier( ListCapacity ): + def __init__( self, attributeModifiers ): self.__attributeModifiers = attributeModifiers + def _modifyAttributes( self, obj, attributes ): + for attributeName, attributeModifier in self.__attributeModifiers.iteritems(): + attributes[ attributeName ] = attributeModifier( obj ) + return attributes + +class ElementCreatable( ListCapacityWithModifier ): + def __init__( self, mandatoryParameters, optionalParameters, attributeModifiers = {} ): + ListCapacityWithModifier.__init__( self, attributeModifiers ) + self.__argumentsChecker = ArgumentsChecker( mandatoryParameters, optionalParameters ) + def apply( self, cls ): cls._addMethod( "create_" + self.singularName, self.__execute ) def __execute( self, obj, *args, **kwds ): return self.typePolicy.createLazy( obj, - self.__modifyAttributes( + self._modifyAttributes( obj, obj._github._dataRequest( "POST", @@ -87,18 +96,13 @@ class ElementCreatable( ListCapacity ): ) ) - def __modifyAttributes( self, obj, attributes ): - for attributeName, attributeModifier in self.__attributeModifiers.iteritems(): - attributes[ attributeName ] = attributeModifier( obj ) - return attributes - def autoDocument( self ): return "* `create_" + self.singularName + "(" + self.__argumentsChecker.documentParameters() + ")`: " + self.typePolicy.documentTypeName() + "\n" -class ElementGetable( ListCapacity ): +class ElementGetable( ListCapacityWithModifier ): def __init__( self, mandatoryParameters, optionalParameters, attributeModifiers = {} ): + ListCapacityWithModifier.__init__( self, attributeModifiers ) self.__argumentsChecker = ArgumentsChecker( mandatoryParameters, optionalParameters ) - self.__attributeModifiers = attributeModifiers def apply( self, cls ): cls._addMethod( "get_" + self.singularName, self.__execute ) @@ -106,17 +110,12 @@ class ElementGetable( ListCapacity ): def __execute( self, obj, *args, **kwds ): return self.typePolicy.createNonLazy( obj, - self.__modifyAttributes( + self._modifyAttributes( obj, self.__argumentsChecker.check( args, kwds ) ) ) - def __modifyAttributes( self, obj, attributes ): - for attributeName, attributeModifier in self.__attributeModifiers.iteritems(): - attributes[ attributeName ] = attributeModifier( obj ) - return attributes - def autoDocument( self ): return "* `get_" + self.singularName + "(" + self.__argumentsChecker.documentParameters() + ")`: " + self.typePolicy.documentTypeName() + "\n" @@ -156,10 +155,10 @@ class SeveralElementsRemovable( ListCapacity ): def autoDocument( self ): return "* `remove_from_" + self.safeAttributeName + "( " + self.singularName + ", ... )`\n * `" + self.singularName + "`: " + self.typePolicy.documentTypeName() + "\n" -class ListGetable( ListCapacity ): +class ListGetable( ListCapacityWithModifier ): def __init__( self, mandatoryParameters, optionalParameters, attributeModifiers = {} ): + ListCapacityWithModifier.__init__( self, attributeModifiers ) self.__argumentsChecker = ArgumentsChecker( mandatoryParameters, optionalParameters ) - self.__attributeModifiers = attributeModifiers def apply( self, cls ): cls._addMethod( "get_" + self.safeAttributeName, self.__execute ) @@ -169,7 +168,7 @@ class ListGetable( ListCapacity ): return [ self.typePolicy.createLazy( obj, - self.__modifyAttributes( obj, attributes ) + self._modifyAttributes( obj, attributes ) ) for attributes in obj._github._dataRequest( "GET", @@ -182,11 +181,6 @@ class ListGetable( ListCapacity ): def autoDocument( self ): return "* `get_" + self.safeAttributeName + "(" + self.__argumentsChecker.documentParameters() + ")`: list of " + self.typePolicy.documentTypeName() + "\n" - def __modifyAttributes( self, obj, attributes ): - for attributeName, attributeModifier in self.__attributeModifiers.iteritems(): - attributes[ attributeName ] = attributeModifier( obj ) - return attributes - class ListSetable( ListCapacity ): def apply( self, cls ): cls._addMethod( "set_" + self.safeAttributeName, self.__execute ) diff --git a/github/ObjectCapacities/TypePolicies.py b/github/ObjectCapacities/TypePolicies.py index 81fb8832..a7aeb737 100644 --- a/github/ObjectCapacities/TypePolicies.py +++ b/github/ObjectCapacities/TypePolicies.py @@ -19,10 +19,7 @@ class ObjectTypePolicy: self.__type = type def createLazy( self, obj, attributes ): - if isinstance( attributes, self.__type ): - return attributes - else: - return self.__type( obj._github, attributes, lazy = True ) + return self.__type( obj._github, attributes, lazy = True ) def createNonLazy( self, obj, attributes ): return self.__type( obj._github, attributes, lazy = False ) From 408801e6b58487b1072ba132be28a9f09b5c993d Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 4 Mar 2012 08:22:25 +0000 Subject: [PATCH 30/56] Improve integration test --- IntegrationTest.py | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index b3e03ad2..b8f5098b 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -99,7 +99,7 @@ class IntegrationTest: tests = argv self.runTests( tests, record ) - if not record: + if self.succeeded: self.analyseCoverage() def prepareRecord( self, test ): @@ -107,8 +107,8 @@ class IntegrationTest: try: import GithubCredentials self.g = Github( GithubCredentials.login, GithubCredentials.password ) - file = open( self.__fileName( test ), "w" ) - httplib.HTTPSConnection = lambda *args, **kwds: RecordingHttpsConnection( file, *args, **kwds ) + self.__file = open( self.__fileName( test ), "w" ) + httplib.HTTPSConnection = lambda *args, **kwds: RecordingHttpsConnection( self.__file, *args, **kwds ) except ImportError: raise RecordReplayException( textwrap.dedent( """\ Please create a 'GithubCredentials.py' file containing:" @@ -118,8 +118,9 @@ class IntegrationTest: def prepareReplay( self, test ): self.avoidError500FromGithub = lambda: 0 try: - file = open( self.__fileName( test ) ) - httplib.HTTPSConnection = lambda *args, **kwds: ReplayingHttpsConnection( file ) + self.__file = None + self.__file = open( self.__fileName( test ) ) + httplib.HTTPSConnection = lambda *args, **kwds: ReplayingHttpsConnection( self.__file ) self.g = Github( "login", "password" ) except IOError: raise RecordReplayException( "This test has never been recorded. Please re-run this script with argument '--record'" ) @@ -131,6 +132,7 @@ class IntegrationTest: return [ f[ 4: ] for f in dir( self ) if f.startswith( "test" ) ] def runTests( self, tests, record ): + self.succeeded = True for test in tests: print print test @@ -141,10 +143,17 @@ class IntegrationTest: else: self.prepareReplay( test ) getattr( self, "test" + test )() + if not record: + if self.__file.readline(): + raise RecordReplayException( "This test has been changed since last record. Please re-run this script with argument '--record'" ) except RecordReplayException, e: print "*" * len( str( e ) ) print e print "*" * len( str( e ) ) + self.succeeded = False + finally: + if self.__file is not None: + self.__file.close() def analyseCoverage( self ): coveredUrls = dict() @@ -177,6 +186,17 @@ class IntegrationTest: print "Not covered (" + str( len( uncoveredMethods ) ) + "):" print "\n".join( sorted( uncoveredMethods ) ) + def testColaborators( self ): + r = self.g.get_user().get_repo( "TestPyGithub" ) + cobaye = self.g.get_user( self.cobayeUser ) + self.printList( "Collaborators", r.get_collaborators(), lambda m: m.login ) + r.add_to_collaborators( cobaye ) + assert r.has_in_collaborators( cobaye ) + self.printList( "Collaborators", r.get_collaborators(), lambda m: m.login ) + r.remove_from_collaborators( cobaye ) + assert not r.has_in_collaborators( cobaye ) + self.printList( "Collaborators", r.get_collaborators(), lambda m: m.login ) + def testCreateForkForOrganization( self ): o = self.g.get_organization( self.cobayeOrganization ) r = self.g.get_user().get_repo( "TestPyGithub" ) @@ -185,11 +205,15 @@ class IntegrationTest: def testCreateRepoForOrganization( self ): o = self.g.get_organization( self.cobayeOrganization ) + self.printList( "Repos", o.get_repos(), lambda r: r.name ) r = o.create_repo( "CreatedByPyGithub", has_wiki = False ) + self.printList( "Repos", o.get_repos(), lambda r: r.name ) def testCreateRepoForUser( self ): u = self.g.get_user() + self.printList( "Repos", u.get_repos(), lambda r: r.name ) r = u.create_repo( "CreatedByPyGithub", has_wiki = False ) + self.printList( "Repos", u.get_repos(), lambda r: r.name ) def testEditAuthenticatedUser( self ): u = self.g.get_user() @@ -401,9 +425,6 @@ class IntegrationTest: def testOrganizationDetails( self ): o = self.g.get_organization( "github" ) print o.login, "(" + o.name + ") is in", o.location - self.printList( "Public members", o.get_public_members(), lambda m: m.login ) - self.printList( "Members", o.get_members(), lambda m: m.login ) - self.printList( "Repos", o.get_repos(), lambda r: r.name ) def testWatch( self ): r = self.g.get_user( "jacquev6" ).get_repo( "PyGithub" ) From 7cc3b44c69b3b8b70143aeb912b4835a8d08b32b Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 4 Mar 2012 08:36:38 +0000 Subject: [PATCH 31/56] Commit comments --- IntegrationTest.py | 12 ++++++++++++ github/GithubObjects.py | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index b8f5098b..60ee418e 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -197,6 +197,18 @@ class IntegrationTest: assert not r.has_in_collaborators( cobaye ) self.printList( "Collaborators", r.get_collaborators(), lambda m: m.login ) + def testCommentCommit( self ): + r = self.g.get_user().get_repo( "TestPyGithub" ) + c = r.get_commits()[ 0 ] + self.printList( "Comments", c.get_comments(), lambda c: c.body ) + com1 = c.create_comment( "Comment created by PyGithub" ) + self.printList( "Comments", c.get_comments(), lambda c: c.body ) + com2 = c.create_comment( "Comment also created by PyGithub", path = "ReadMe.md", line = 1 ) + self.printList( "Comments", c.get_comments(), lambda c: c.body ) + com2.delete() + com1.edit( body = "Comment edited by PyGithub" ) + self.printList( "Comments", c.get_comments(), lambda c: c.body ) + def testCreateForkForOrganization( self ): o = self.g.get_organization( self.cobayeOrganization ) r = self.g.get_user().get_repo( "TestPyGithub" ) diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 723ded55..e3c9806f 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -297,8 +297,8 @@ Commit = GithubObject( InternalObjectAttribute( "author", NamedUser ), InternalObjectAttribute( "committer", NamedUser ), ExternalListOfObjects( "comments", "comment", CommitComment, - ListGetable( [], [] ), - ElementCreatable( [ "body", "commit_id", "line", "path", "position" ], [] ), + ListGetable( [], [], __modifyAttributesForObjectsReferingReferedRepo ), + ElementCreatable( [ "body" ], [ "commit_id", "line", "path", "position" ], __modifyAttributesForObjectsReferingReferedRepo ), ), ) From 629668beae870ecf5f3c693ffc9ee27d3e580ae6 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 4 Mar 2012 09:12:39 +0000 Subject: [PATCH 32/56] PullRequests --- IntegrationTest.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/IntegrationTest.py b/IntegrationTest.py index 60ee418e..a4635df7 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -438,6 +438,28 @@ class IntegrationTest: o = self.g.get_organization( "github" ) print o.login, "(" + o.name + ") is in", o.location + def testPullRequest( self ): + r = self.g.get_user().get_repo( "TestPyGithub" ) + self.printList( "Pull requests", r.get_pulls(), lambda p: p.title ) + p1 = r.create_pull( "Pull request created by PyGithub", "", "master", "BeaverSoftware:master" ) + self.printList( "Pull requests", r.get_pulls(), lambda p: p.title ) + p1.edit( state = "closed" ) + self.printList( "Pull requests", r.get_pulls(), lambda p: p.title ) + p2 = r.create_pull( "Pull request also created by PyGithub", "", "master", "BeaverSoftware:master" ) + self.printList( "Pull requests", r.get_pulls(), lambda p: p.title ) + self.printList( "Files", p2.get_files(), lambda f: f.filename ) + self.printList( "Commits", p2.get_commits(), lambda c: c.commit.message ) + self.printList( "Comments", p2.get_comments(), lambda c: c.body ) + com = p2.create_comment( "Comment created by PyGithub", "e4e84560cb5e87f3c0e9f710dae1ddab0eef487b", "foo.bar", 1 ) + self.printList( "Comments", p2.get_comments(), lambda c: c.body ) + com.edit( body = "Comment edited by PyGithub" ) + self.printList( "Comments", p2.get_comments(), lambda c: c.body ) + sameCom = p2.get_comment( com.id ) + sameCom.delete() + self.printList( "Comments", p2.get_comments(), lambda c: c.body ) + p2.edit( state = "closed" ) + self.printList( "Pull requests", r.get_pulls(), lambda p: p.title ) + def testWatch( self ): r = self.g.get_user( "jacquev6" ).get_repo( "PyGithub" ) u = self.g.get_user() From 827dc06d104c47421fd3ff470ddd842c923c2e84 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 4 Mar 2012 09:12:57 +0000 Subject: [PATCH 33/56] RepositoryKeys --- IntegrationTest.py | 11 +++++++++++ github/GithubObjects.py | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index a4635df7..b18490e1 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -460,6 +460,17 @@ class IntegrationTest: p2.edit( state = "closed" ) self.printList( "Pull requests", r.get_pulls(), lambda p: p.title ) + def testRepositoryKeys( self ): + r = self.g.get_user().get_repo( "TestPyGithub" ) + self.printList( "Keys", r.get_keys(), lambda k: k.title ) + k = r.create_key( "Key created by PyGithub", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvborozfBBn2a+JETqPekTWZ1tmYjpfH9wTKFPLjIXQmxXjNye6HVgvi+iMI436RdoLsPEFDe3cjrQ6CJa7KzhRJKNTPh5EZbKI13CXfMGr7V1i3tOokXBFSRQKnDx2dj2hnswqxGUk2jXpgC/KA1q71yqnL45CBlWr50eDpwUIEPnmqSrPpRV/0ZGwIlh4o7+6HwPUF9aBhWj945WSkjZubR4UFWlDZl7ROafpkJHs2cQzaxtmBOZnu6dzmfyro0zJsvhZKD2K6d9eKgpDeKaw5rWr6FeOZPd4xyDaV1gctG0YEui8uuSPKhpcykgREUAFf+vmOKt+yXnOoq8P4vIQ==" ) + self.printList( "Keys", r.get_keys(), lambda k: k.title ) + k.edit( "Key edited by PyGithub", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvborozfBBn2a+JETqPekTWZ1tmYjpfH9wTKFPLjIXQmxXjNye6HVgvi+iMI436RdoLsPEFDe3cjrQ6CJa7KzhRJKNTPh5EZbKI13CXfMGr7V1i3tOokXBFSRQKnDx2dj2hnswqxGUk2jXpgC/KA1q71yqnL45CBlWr50eDpwUIEPnmqSrPpRV/0ZGwIlh4o7+6HwPUF9aBhWj945WSkjZubR4UFWlDZl7ROafpkJHs2cQzaxtmBOZnu6dzmfyro0zJsvhZKD2K6d9eKgpDeKaw5rWr6FeOZPd4xyDaV1gctG0YEui8uuSPKhpcykgREUAFf+vmOKt+yXnOoq8P4vIQ==" ) + self.printList( "Keys", r.get_keys(), lambda k: k.title ) + sameKey = r.get_key( k.id ) + sameKey.delete() + self.printList( "Keys", r.get_keys(), lambda k: k.title ) + def testWatch( self ): r = self.g.get_user( "jacquev6" ).get_repo( "PyGithub" ) u = self.g.get_user() diff --git a/github/GithubObjects.py b/github/GithubObjects.py index e3c9806f..7d925d51 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -409,9 +409,9 @@ Repository._addAttributePolicy( ) Repository._addAttributePolicy( SeveralAttributePolicies( [ ExternalListOfObjects( "keys", "key", RepositoryKey, - ListGetable( [], [] ), + ListGetable( [], [], __modifyAttributesForObjectsReferingRepo ), ElementGetable( [ "id" ], [], __modifyAttributesForObjectsReferingRepo ), - ElementCreatable( [ "title", "key" ], [] ), + ElementCreatable( [ "title", "key" ], [], __modifyAttributesForObjectsReferingRepo ), ), ExternalListOfObjects( "collaborators", "collaborator", NamedUser, ListGetable( [], [] ), From 231ae0778e0bebaac3dc87fa8f602c1560b8164f Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 4 Mar 2012 09:18:40 +0000 Subject: [PATCH 34/56] Team.edit --- IntegrationTest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index b18490e1..a5fa537a 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -250,7 +250,8 @@ class IntegrationTest: r = o.get_repo( "TestPyGithub" ) self.printList( "Teams", o.get_teams(), lambda t: t.name ) - t = o.create_team( "PyGithubTesters", permission = "push" ) + t = o.create_team( "PyGithubTesters" ) + t.edit( "PyGithubTesters", permission = "push" ) self.printList( "Teams", o.get_teams(), lambda t: t.name ) u = self.g.get_user( self.cobayeUser ) From 6b89c02872cbcb179d79cb4ceb2436fee02425d0 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 4 Mar 2012 09:21:59 +0000 Subject: [PATCH 35/56] Downloads --- IntegrationTest.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/IntegrationTest.py b/IntegrationTest.py index a5fa537a..f5f1b899 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -227,6 +227,15 @@ class IntegrationTest: r = u.create_repo( "CreatedByPyGithub", has_wiki = False ) self.printList( "Repos", u.get_repos(), lambda r: r.name ) + def testDownloads( self ): + r = self.g.get_user().get_repo( "TestPyGithub" ) + self.printList( "Downloads", r.get_downloads(), lambda d: d.name ) + d = r.create_download( "DownloadCreatedByPyGithub.txt", 1024 ) + self.printList( "Downloads", r.get_downloads(), lambda d: d.name ) + sameDownload = r.get_download( d.id ) + sameDownload.delete() + self.printList( "Downloads", r.get_downloads(), lambda d: d.name ) + def testEditAuthenticatedUser( self ): u = self.g.get_user() originalName = u.name From e0c04877a9a00766d099251512a8bb512a1d37c2 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 4 Mar 2012 09:34:02 +0000 Subject: [PATCH 36/56] AuthenticatedUserDetails --- IntegrationTest.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/IntegrationTest.py b/IntegrationTest.py index f5f1b899..a4cc5030 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -186,6 +186,10 @@ class IntegrationTest: print "Not covered (" + str( len( uncoveredMethods ) ) + "):" print "\n".join( sorted( uncoveredMethods ) ) + def testAuthenticatedUserDetails( self ): + u = self.g.get_user() + self.printList( "Organizations", u.get_orgs(), lambda o: o.login ) + def testColaborators( self ): r = self.g.get_user().get_repo( "TestPyGithub" ) cobaye = self.g.get_user( self.cobayeUser ) From 3a83cc0b1e40788483398eb89e3671b91d648251 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 4 Mar 2012 09:38:09 +0000 Subject: [PATCH 37/56] RepositoryDetails --- IntegrationTest.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/IntegrationTest.py b/IntegrationTest.py index a4cc5030..690031a9 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -474,6 +474,21 @@ class IntegrationTest: p2.edit( state = "closed" ) self.printList( "Pull requests", r.get_pulls(), lambda p: p.title ) + def testRepositoryDetails( self ): + r1 = self.g.get_user().get_repo( "PyGithub" ) + r2 = self.g.get_user().get_repo( "TestPyGithub" ) + self.printList( "Branches", r1.get_branches(), lambda b: b.name ) + self.printList( "Comments", r2.get_comments(), lambda c: c.body ) + r2.get_comment( r2.get_comments()[ 0 ].id ) + self.printList( "Contributors", r1.get_contributors(), lambda m: m.login ) + self.printList( "Forks", r2.get_forks(), lambda r: r.owner.login ) + print "Languages:", r1.get_languages() + self.printList( "Tags", r1.get_tags(), lambda t: t.name ) + self.printList( "Watchers", r1.get_watchers(), lambda m: m.login ) + + r3 = self.g.get_organization( "BeaverSoftware" ).get_repo( "TestPyGithub" ) + self.printList( "Teams", r3.get_teams(), lambda t: t.name ) + def testRepositoryKeys( self ): r = self.g.get_user().get_repo( "TestPyGithub" ) self.printList( "Keys", r.get_keys(), lambda k: k.title ) From 924aef7d9f3a21145492ea165c9268ab0030cbab Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 4 Mar 2012 09:45:59 +0000 Subject: [PATCH 38/56] Typo... --- ReadMe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ReadMe.md b/ReadMe.md index 0b062585..6fe00c38 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -1,4 +1,4 @@ -This is a Python library to access the [Gitub API v3](http://developer.github.com/v3). +This is a Python library to access the [Github API v3](http://developer.github.com/v3). With it, you can manage your Github resources (repositories, user profiles, organizations, etc.) from Python scripts. From f2d89a565f5eb19af605d78762169daec9a701e0 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 23 Feb 2012 21:32:44 +0000 Subject: [PATCH 39/56] Todos for hooks and events --- ReferenceOfApis.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index fa94f5e2..b5cc3eee 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -11,7 +11,7 @@ API `/authorizations/:id` API `/events` ============= -* GET: (TODO) +* GET: (TODO SOON) API `/gists` ============ @@ -59,7 +59,7 @@ API `/issues` API `/networks/:user/:repo/events` ================================== -* GET: (TODO) +* GET: (TODO SOON) API `/orgs/:org` ================ @@ -68,7 +68,7 @@ API `/orgs/:org` API `/orgs/:org/events` ======================= -* GET: (TODO) +* GET: (TODO SOON) API `/orgs/:org/members` ======================== @@ -161,7 +161,7 @@ API `/repos/:user/:repo/downloads/:id` API `/repos/:user/:repo/events` =============================== -* GET: (TODO) +* GET: (TODO SOON) API `/repos/:user/:repo/forks` ============================== @@ -220,18 +220,18 @@ API `/repos/:user/:repo/git/trees/:sha?recursive=1` API `/repos/:user/:repo/hooks` ============================== -* GET: (TODO) -* POST: (TODO) +* GET: (TODO SOON) +* POST: (TODO SOON) API `/repos/:user/:repo/hooks/:id` ================================== -* GET: (TODO) -* PATCH: (TODO) -* DELETE: (TODO) +* GET: (TODO SOON) +* PATCH: (TODO SOON) +* DELETE: (TODO SOON) API `/repos/:user/:repo/hooks/:id/test` ======================================= -* POST: (TODO) +* POST: (TODO SOON) API `/repos/:user/:repo/issues` =============================== @@ -261,7 +261,7 @@ API `/repos/:user/:repo/issues/:id/labels/:name` API `/repos/:user/:repo/issues/:id/events` ========================================== -* GET: (TODO) +* GET: (TODO SOON) API `/repos/:user/:repo/issues/comments/:id` ============================================ @@ -271,11 +271,11 @@ API `/repos/:user/:repo/issues/comments/:id` API `/repos/:user/:repo/issues/events` ====================================== -* GET: (TODO) +* GET: (TODO SOON) API `/repos/:user/:repo/issues/events/:id` ========================================== -* GET: (TODO) +* GET: (TODO SOON) API `/repos/:user/:repo/keys` ============================= @@ -451,15 +451,15 @@ API `/users/:user` API `/users/:user/events` ========================= -* GET: (TODO) +* GET: (TODO SOON) API `/users/:user/events/orgs/:org` =================================== -* GET: (TODO) +* GET: (TODO SOON) API `/users/:user/events/public` ================================ -* GET: (TODO) +* GET: (TODO SOON) API `/users/:user/followers` ============================ @@ -479,11 +479,11 @@ API `/users/:user/orgs` API `/users/:user/received_events` ================================== -* GET: (TODO) +* GET: (TODO SOON) API `/users/:user/received_events/public` ========================================= -* GET: (TODO) +* GET: (TODO SOON) API `/users/:user/repos` ======================== From 0b8ffcc14c6200dda4f9b11c47d6949b5cd3240b Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Thu, 1 Mar 2012 17:35:13 +0100 Subject: [PATCH 40/56] Hooks: step 1 --- ReferenceOfApis.md | 10 +++++----- ReferenceOfClasses.md | 20 ++++++++++++++++++++ github/GithubObjects.py | 16 ++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index b5cc3eee..df596c54 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -220,14 +220,14 @@ API `/repos/:user/:repo/git/trees/:sha?recursive=1` API `/repos/:user/:repo/hooks` ============================== -* GET: (TODO SOON) -* POST: (TODO SOON) +* GET: `Repository.get_hooks` +* POST: `Repository.create_hook` API `/repos/:user/:repo/hooks/:id` ================================== -* GET: (TODO SOON) -* PATCH: (TODO SOON) -* DELETE: (TODO SOON) +* GET: `Repository.get_hook` +* PATCH: `Hook.edit` +* DELETE: `Hook.delete` API `/repos/:user/:repo/hooks/:id/test` ======================================= diff --git a/ReferenceOfClasses.md b/ReferenceOfClasses.md index d26aed04..88be7b4a 100644 --- a/ReferenceOfClasses.md +++ b/ReferenceOfClasses.md @@ -341,6 +341,20 @@ Attributes * `url` * `tree` +Class `Hook` +============ + +Attributes +---------- + +Modification +------------ +* `edit()` + +Deletion +-------- +* `delete()` + Class `Issue` ============= @@ -710,6 +724,12 @@ Languages --------- * `get_languages()`: dictionary of strings to integers +Hooks +----- +* `get_hooks()`: list of `Hook` +* `get_hook( id )`: `Hook` +* `create_hook()`: `Hook` + Keys ---- * `get_keys()`: list of `RepositoryKey` diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 7d925d51..3ff85f2c 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -3,6 +3,17 @@ import urllib from GithubObject import * +Hook = GithubObject( + "Hook", + BaseUrl( lambda obj: obj._repo._baseUrl + "/hooks/" + obj.id ), + InternalSimpleAttributes( + ### @todo + "_repo", ### Ugly hack + ), + Editable( [], [] ), #### @todo + Deletable(), +) + Authorization = GithubObject( "Authorization", BaseUrl( lambda obj: "/authorizations/" + str( obj.id ) ), ### @todo make the lambda return a tuple, and BaseUrl convert elements to strings and join them with "/" @@ -408,6 +419,11 @@ Repository._addAttributePolicy( SeveralAttributePolicies( [ ExternalSimpleAttribute( "languages", "dictionary of strings to integers" ) ], "Languages" ) ) Repository._addAttributePolicy( SeveralAttributePolicies( [ + ExternalListOfObjects( "hooks", "hook", Hook, + ListGetable( [], [], __modifyAttributesForObjectsReferingRepo ), + ElementGetable( [ "id" ], [], __modifyAttributesForObjectsReferingRepo ), + ElementCreatable( [], [], __modifyAttributesForObjectsReferingReferedRepo ), ### @todo + ), ExternalListOfObjects( "keys", "key", RepositoryKey, ListGetable( [], [], __modifyAttributesForObjectsReferingRepo ), ElementGetable( [ "id" ], [], __modifyAttributesForObjectsReferingRepo ), From f03d86c46e4d5b337514277620dc9adbdc68dba2 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 12:36:01 +0000 Subject: [PATCH 41/56] Hooks: step 2 --- IntegrationTest.py | 18 ++++++++++++++++++ github/GithubObjects.py | 9 +++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index 690031a9..04896d0f 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -371,6 +371,24 @@ class IntegrationTest: r.create_git_ref( "refs/tags/tagCreatedByPyGithub", tag.sha ) reTag = r.get_git_tag( tag.sha ) + def testHooks( self ): + u = self.g.get_user() + r = u.get_repo( "TestPyGithub" ) + + self.printList( "Hooks", r.get_hooks(), lambda h: h.name + str( h.config ) ) + h = r.create_hook( "web", { "url": "http://www.invalid.org" } ) + self.printList( "Hooks", r.get_hooks(), lambda h: h.name + str( h.config ) ) + h.edit( "web", { "url": "http://www.postbin.org/w5cgjr" } ) + self.printList( "Hooks", r.get_hooks(), lambda h: h.name + str( h.config ) ) + + sameHook = r.get_hook( h.id ) + + ### @todo Uncomment when API `/repos/:user/:repo/hooks/:id/test` is implemented + # h.test() + + h.delete() + self.printList( "Hooks", r.get_hooks(), lambda h: h.name + str( h.config ) ) + def testIssuesAndMilestones( self ): u = self.g.get_user() r = u.get_repo( "TestPyGithub" ) diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 3ff85f2c..f14e4158 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -5,12 +5,13 @@ from GithubObject import * Hook = GithubObject( "Hook", - BaseUrl( lambda obj: obj._repo._baseUrl + "/hooks/" + obj.id ), + BaseUrl( lambda obj: obj._repo._baseUrl + "/hooks/" + str( obj.id ) ), InternalSimpleAttributes( - ### @todo + "url", "updated_at", "created_at", "name", "events", "active", "config", + "id", "last_response", "_repo", ### Ugly hack ), - Editable( [], [] ), #### @todo + Editable( [ "name", "config" ], [ "events", "add_events", "remove_events", "active" ] ), Deletable(), ) @@ -422,7 +423,7 @@ Repository._addAttributePolicy( SeveralAttributePolicies( [ ExternalListOfObjects( "hooks", "hook", Hook, ListGetable( [], [], __modifyAttributesForObjectsReferingRepo ), ElementGetable( [ "id" ], [], __modifyAttributesForObjectsReferingRepo ), - ElementCreatable( [], [], __modifyAttributesForObjectsReferingReferedRepo ), ### @todo + ElementCreatable( [ "name", "config" ], [ "events", "active" ], __modifyAttributesForObjectsReferingRepo ), ), ExternalListOfObjects( "keys", "key", RepositoryKey, ListGetable( [], [], __modifyAttributesForObjectsReferingRepo ), From 00a832e6d519dac96142f650d6363f24459f9145 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sat, 3 Mar 2012 12:44:54 +0000 Subject: [PATCH 42/56] Hook testing --- IntegrationTest.py | 3 +-- ReferenceOfClasses.md | 23 ++++++++++++++++++----- github/GithubObjects.py | 3 +++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index 04896d0f..2e5c2edd 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -383,8 +383,7 @@ class IntegrationTest: sameHook = r.get_hook( h.id ) - ### @todo Uncomment when API `/repos/:user/:repo/hooks/:id/test` is implemented - # h.test() + h.test() h.delete() self.printList( "Hooks", r.get_hooks(), lambda h: h.name + str( h.config ) ) diff --git a/ReferenceOfClasses.md b/ReferenceOfClasses.md index 88be7b4a..8b0572dd 100644 --- a/ReferenceOfClasses.md +++ b/ReferenceOfClasses.md @@ -302,10 +302,10 @@ Attributes * `sha` * `url` * `message` +* `parents` * `author` * `committer` -* `tree` -* `parents` +* `tree`: `GitTree` Class `GitRef` ============== @@ -346,15 +346,28 @@ Class `Hook` Attributes ---------- +* `url` +* `updated_at` +* `created_at` +* `name` +* `events` +* `active` +* `config` +* `id` +* `last_response` Modification ------------ -* `edit()` +* `edit( name, config, [events, add_events, remove_events, active] )` Deletion -------- * `delete()` +Testing +------- +* `test()` + Class `Issue` ============= @@ -728,7 +741,7 @@ Hooks ----- * `get_hooks()`: list of `Hook` * `get_hook( id )`: `Hook` -* `create_hook()`: `Hook` +* `create_hook( name, config, [events, active] )`: `Hook` Keys ---- @@ -912,7 +925,7 @@ Attributes Modification ------------ -* `edit( title, key )` +* `edit( [title, key] )` Deletion -------- diff --git a/github/GithubObjects.py b/github/GithubObjects.py index f14e4158..b8217841 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -3,6 +3,8 @@ import urllib from GithubObject import * +def __testHook( hook ): + hook._github._statusRequest( "POST", hook._baseUrl + "/test", None, None ) Hook = GithubObject( "Hook", BaseUrl( lambda obj: obj._repo._baseUrl + "/hooks/" + str( obj.id ) ), @@ -13,6 +15,7 @@ Hook = GithubObject( ), Editable( [ "name", "config" ], [ "events", "add_events", "remove_events", "active" ] ), Deletable(), + SeveralAttributePolicies( [ MethodFromCallable( "test", [], [], __testHook, SimpleTypePolicy( None ) ) ], "Testing" ) ) Authorization = GithubObject( From 25c76b4b759173fa42cdf3ebd0214a5ce958b2e4 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 4 Mar 2012 07:56:48 +0000 Subject: [PATCH 43/56] Restore test coverage --- github/Github.UnitTest.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/github/Github.UnitTest.py b/github/Github.UnitTest.py index c1719c96..e614a825 100644 --- a/github/Github.UnitTest.py +++ b/github/Github.UnitTest.py @@ -60,4 +60,12 @@ class TestCase( unittest.TestCase ): self.requester.expect.dataRequest( "GET", "/repos/xxx/yyy/milestones/1/labels", {}, None ).andReturn( [ { "name": "a" } ] ) self.assertIs( r.get_milestone( 1 ).get_labels()[ 0 ]._repo, r ) + def testHooks( self ): + self.requester.expect.dataRequest( "GET", "/user", None, None ).andReturn( { "login": "xxx" } ) + self.requester.expect.dataRequest( "GET", "/repos/xxx/yyy", None, None ).andReturn( { "name": "yyy", "owner": { "login": "xxx" } } ) + self.requester.expect.dataRequest( "GET", "/repos/xxx/yyy/hooks/1", None, None ).andReturn( { "name": "web", "id": 1 } ) + h = self.g.get_user().get_repo( "yyy" ).get_hook( 1 ) + self.requester.expect.statusRequest( "POST", "/repos/xxx/yyy/hooks/1/test", None, None ).andReturn( 204 ) + h.test() + unittest.main() From 01fa4d803b4a541759ba906d194f1fa9bc29faa9 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 4 Mar 2012 10:12:15 +0000 Subject: [PATCH 44/56] Regenerate reference of classes --- ReferenceOfApis.md | 2 +- ReferenceOfClasses.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index df596c54..d0b23274 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -231,7 +231,7 @@ API `/repos/:user/:repo/hooks/:id` API `/repos/:user/:repo/hooks/:id/test` ======================================= -* POST: (TODO SOON) +* POST: `Hook.test` API `/repos/:user/:repo/issues` =============================== diff --git a/ReferenceOfClasses.md b/ReferenceOfClasses.md index 8b0572dd..e17261cd 100644 --- a/ReferenceOfClasses.md +++ b/ReferenceOfClasses.md @@ -162,7 +162,7 @@ Attributes Comments -------- * `get_comments()`: list of `CommitComment` -* `create_comment( body, commit_id, line, path, position )`: `CommitComment` +* `create_comment( body, [commit_id, line, path, position] )`: `CommitComment` Class `CommitComment` ===================== From 44911bf0906912d468cb88001907955ee318fdf7 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Sun, 4 Mar 2012 20:54:56 +0000 Subject: [PATCH 45/56] Events: step 1 --- IntegrationTest.py | 3 ++ ReferenceOfApis.md | 20 +++++----- ReferenceOfClasses.md | 38 +++++++++++++++++++ github/GithubObjects.py | 82 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 10 deletions(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index 2e5c2edd..bf38bb53 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -306,6 +306,9 @@ class IntegrationTest: t.delete() self.printList( "Teams", o.get_teams(), lambda t: t.name ) + def testEvents( self ): + self.g.get_user().get_repo( "TestPyGithub" ).get_events() + def testFollow( self ): cobaye = self.g.get_user( self.cobayeUser ) u = self.g.get_user() diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index d0b23274..f175d68d 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -11,7 +11,7 @@ API `/authorizations/:id` API `/events` ============= -* GET: (TODO SOON) +* GET: `AuthenticatedUser.get_events` API `/gists` ============ @@ -59,7 +59,7 @@ API `/issues` API `/networks/:user/:repo/events` ================================== -* GET: (TODO SOON) +* GET: `Repository.get_network_events` API `/orgs/:org` ================ @@ -68,7 +68,7 @@ API `/orgs/:org` API `/orgs/:org/events` ======================= -* GET: (TODO SOON) +* GET: `Organization.get_events` API `/orgs/:org/members` ======================== @@ -161,7 +161,7 @@ API `/repos/:user/:repo/downloads/:id` API `/repos/:user/:repo/events` =============================== -* GET: (TODO SOON) +* GET: `Repository.get_events` API `/repos/:user/:repo/forks` ============================== @@ -261,7 +261,7 @@ API `/repos/:user/:repo/issues/:id/labels/:name` API `/repos/:user/:repo/issues/:id/events` ========================================== -* GET: (TODO SOON) +* GET: `Issue.get_events` API `/repos/:user/:repo/issues/comments/:id` ============================================ @@ -271,7 +271,7 @@ API `/repos/:user/:repo/issues/comments/:id` API `/repos/:user/:repo/issues/events` ====================================== -* GET: (TODO SOON) +* GET: `Repository.get_issues_events` API `/repos/:user/:repo/issues/events/:id` ========================================== @@ -451,7 +451,7 @@ API `/users/:user` API `/users/:user/events` ========================= -* GET: (TODO SOON) +* GET: `NamedUser.get_events` API `/users/:user/events/orgs/:org` =================================== @@ -459,7 +459,7 @@ API `/users/:user/events/orgs/:org` API `/users/:user/events/public` ================================ -* GET: (TODO SOON) +* GET: `NamedUser.get_public_events` API `/users/:user/followers` ============================ @@ -479,11 +479,11 @@ API `/users/:user/orgs` API `/users/:user/received_events` ================================== -* GET: (TODO SOON) +* GET: `NamedUser.get_received_events` API `/users/:user/received_events/public` ========================================= -* GET: (TODO SOON) +* GET: `NamedUser.get_public_received_events` API `/users/:user/repos` ======================== diff --git a/ReferenceOfClasses.md b/ReferenceOfClasses.md index e17261cd..7fc33028 100644 --- a/ReferenceOfClasses.md +++ b/ReferenceOfClasses.md @@ -70,6 +70,10 @@ Keys * `get_key( id )`: `UserKey` * `create_key( title, key )`: `UserKey` +Events +------ +* `get_events()`: list of `Event` + Followers --------- * `get_followers()`: list of `NamedUser` @@ -219,6 +223,19 @@ Deletion -------- * `delete()` +Class `Event` +============= + +Attributes +---------- +* `type` +* `public` +* `payload` +* `created_at` +* `repo`: `Repository` +* `actor`: `NamedUser` +* `org`: `Organization` + Class `Gist` ============ @@ -412,6 +429,10 @@ Comments * `get_comment( id )`: `IssueComment` * `create_comment( body )`: `IssueComment` +Events +------ +* `get_events()`: list of `Event` + Class `IssueComment` ==================== @@ -517,6 +538,13 @@ Following --------- * `get_following()`: list of `NamedUser` +Events +------ +* `get_events()`: list of `Event` +* `get_public_events()`: list of `Event` +* `get_received_events()`: list of `Event` +* `get_public_received_events()`: list of `Event` + Orgs ---- * `get_orgs()`: list of `Organization` @@ -585,6 +613,10 @@ Members * `has_in_members( member )`: `bool` * `member`: `NamedUser` +Events +------ +* `get_events()`: list of `Event` + Repos ----- * `get_repos( [type] )`: list of `Repository` @@ -725,6 +757,12 @@ Attributes * `parent`: `Repository` * `source`: `Repository` +Events +------ +* `get_events()`: list of `Event` +* `get_network_events()`: list of `Event` +* `get_issues_events()`: list of `Event` + Forks ----- * `get_forks()`: list of `Repository` diff --git a/github/GithubObjects.py b/github/GithubObjects.py index b8217841..35f6cc85 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -3,6 +3,13 @@ import urllib from GithubObject import * +Event = GithubObject( + "Event", + InternalSimpleAttributes( + "type", "public", "payload", "created_at", "id", + ), +) + def __testHook( hook ): hook._github._statusRequest( "POST", hook._baseUrl + "/test", None, None ) Hook = GithubObject( @@ -67,6 +74,10 @@ AuthenticatedUser = GithubObject( ElementGetable( [ "id" ], [] ), ElementCreatable( [ "title", "key" ], [] ), ), + ExternalListOfObjects( "events", "event", Event, + ListGetable( [], [] ), + url = "/events" + ), ) NamedUser = GithubObject( @@ -110,6 +121,38 @@ NamedUser._addAttributePolicy( ListGetable( [], [] ) ) ) +NamedUser._addAttributePolicy( + ExternalListOfObjects( "events", "event", Event, + ListGetable( [], [] ) + ), +) +def __getPublicEvents( user ): + return [ + Event( user._github, attributes ) + for attributes + in user._github._dataRequest( "GET", user._baseUrl + "/events/public", None, None ) + ] +NamedUser._addAttributePolicy( + MethodFromCallable( "get_public_events", [], [], __getPublicEvents, SimpleTypePolicy( "list of `Event`" ) ) +) +def __getReceivedEvents( user ): + return [ + Event( user._github, attributes ) + for attributes + in user._github._dataRequest( "GET", user._baseUrl + "/received_events", None, None ) + ] +NamedUser._addAttributePolicy( + MethodFromCallable( "get_received_events", [], [], __getReceivedEvents, SimpleTypePolicy( "list of `Event`" ) ) +) +def __getPublicReceivedEvents( user ): + return [ + Event( user._github, attributes ) + for attributes + in user._github._dataRequest( "GET", user._baseUrl + "/received_events/public", None, None ) + ] +NamedUser._addAttributePolicy( + MethodFromCallable( "get_public_received_events", [], [], __getPublicReceivedEvents, SimpleTypePolicy( "list of `Event`" ) ) +) Organization = GithubObject( "Organization", @@ -135,6 +178,9 @@ Organization = GithubObject( ElementRemovable(), ElementHasable() ), + ExternalListOfObjects( "events", "event", Event, + ListGetable( [], [] ) + ), ) AuthenticatedUser._addAttributePolicy( @@ -270,6 +316,9 @@ Issue = GithubObject( ElementGetable( [ "id" ], [], __modifyAttributesForObjectsReferingReferedRepo ), ElementCreatable( [ "body" ], [], __modifyAttributesForObjectsReferingReferedRepo ), ), + ExternalListOfObjects( "events", "event", Event, + ListGetable( [], [] ) + ), ) Download = GithubObject( @@ -411,6 +460,29 @@ Repository = GithubObject( ) Repository._addAttributePolicy( InternalObjectAttribute( "parent", Repository ) ) Repository._addAttributePolicy( InternalObjectAttribute( "source", Repository ) ) +Repository._addAttributePolicy( + ExternalListOfObjects( "events", "event", Event, + ListGetable( [], [] ) + ), +) +def __getNetworkEvents( repo ): + return [ + Event( repo._github, attributes ) + for attributes + in repo._github._dataRequest( "GET", repo._baseUrl + "/events", None, None ) + ] +def __getIssuesEvents( repo ): + return [ + Event( repo._github, attributes ) + for attributes + in repo._github._dataRequest( "GET", repo._baseUrl + "/issues/events", None, None ) + ] +Repository._addAttributePolicy( + MethodFromCallable( "get_network_events", [], [], __getNetworkEvents, SimpleTypePolicy( "list of `Event`" ) ) +) +Repository._addAttributePolicy( + MethodFromCallable( "get_issues_events", [], [], __getNetworkEvents, SimpleTypePolicy( "list of `Event`" ) ) +) Repository._addAttributePolicy( ExternalListOfObjects( "forks", "fork", Repository, ListGetable( [], [] ) @@ -657,3 +729,13 @@ def __getStaredGists( user ): AuthenticatedUser._addAttributePolicy( MethodFromCallable( "get_starred_gists", [], [], __getStaredGists, SimpleTypePolicy( "list of `Gist`" ) ), ) + +Event._addAttributePolicy( + InternalObjectAttribute( "repo", Repository ), +) +Event._addAttributePolicy( + InternalObjectAttribute( "actor", NamedUser ), +) +Event._addAttributePolicy( + InternalObjectAttribute( "org", Organization ), +) From 6d51a955d922e92dacf37106a3c52d185fb18423 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Mon, 12 Mar 2012 19:59:56 +0100 Subject: [PATCH 46/56] Fix and add integration tests about events --- IntegrationTest.py | 17 +++++++++++++++-- github/GithubObjects.py | 19 ++++++++++--------- github/Requester.py | 5 ++++- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index bf38bb53..b01fe4ff 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -91,7 +91,7 @@ class IntegrationTest: if record: print "Record mode: this script is really going to do requests to github.com" else: - print "Replay mode: this script will used requests to and replies from github.com recorded in previous runs in record mode" + print "Replay mode: this script will use requests to and replies from github.com recorded in previous runs in record mode" if len( argv ) == 0: tests = self.listTests() @@ -307,7 +307,20 @@ class IntegrationTest: self.printList( "Teams", o.get_teams(), lambda t: t.name ) def testEvents( self ): - self.g.get_user().get_repo( "TestPyGithub" ).get_events() + self.printList( "User events", self.g.get_user( self.cobayeUser ).get_events(), lambda e: e.type ) + self.printList( "User public events", self.g.get_user( self.cobayeUser ).get_public_events(), lambda e: e.type ) + self.printList( "User public received events", self.g.get_user( self.cobayeUser ).get_public_received_events(), lambda e: e.type ) + self.printList( "User received events", self.g.get_user( self.cobayeUser ).get_received_events(), lambda e: e.type ) + + self.printList( "Organization events", self.g.get_organization( self.cobayeOrganization ).get_events(), lambda e: e.type ) + + self.printList( "User events", self.g.get_user().get_events(), lambda e: e.type ) + + self.printList( "Repo events", self.g.get_user().get_repo( "TestPyGithub" ).get_events(), lambda e: e.type ) + self.printList( "Repo issues events", self.g.get_user().get_repo( "TestPyGithub" ).get_issues_events(), lambda e: e.event ) + self.printList( "Repo network events", self.g.get_user().get_repo( "TestPyGithub" ).get_network_events(), lambda e: e.type ) + + self.printList( "Issue events", self.g.get_user().get_repo( "TestPyGithub" ).get_issue( 23 ).get_events(), lambda e: e.event ) def testFollow( self ): cobaye = self.g.get_user( self.cobayeUser ) diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 35f6cc85..5b127bb8 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -6,7 +6,8 @@ from GithubObject import * Event = GithubObject( "Event", InternalSimpleAttributes( - "type", "public", "payload", "created_at", "id", + "type", "public", "payload", "created_at", "id", "commit_id", "url", + "event", "issue", ), ) @@ -128,7 +129,7 @@ NamedUser._addAttributePolicy( ) def __getPublicEvents( user ): return [ - Event( user._github, attributes ) + Event( user._github, attributes, lazy = True ) for attributes in user._github._dataRequest( "GET", user._baseUrl + "/events/public", None, None ) ] @@ -137,7 +138,7 @@ NamedUser._addAttributePolicy( ) def __getReceivedEvents( user ): return [ - Event( user._github, attributes ) + Event( user._github, attributes, lazy = True ) for attributes in user._github._dataRequest( "GET", user._baseUrl + "/received_events", None, None ) ] @@ -146,7 +147,7 @@ NamedUser._addAttributePolicy( ) def __getPublicReceivedEvents( user ): return [ - Event( user._github, attributes ) + Event( user._github, attributes, lazy = True ) for attributes in user._github._dataRequest( "GET", user._baseUrl + "/received_events/public", None, None ) ] @@ -161,7 +162,7 @@ Organization = GithubObject( InternalSimpleAttributes( "login", "id", "url", "avatar_url", "name", "company", "blog", "location", "email", "public_repos", "public_gists", "followers", - "following", "html_url", "created_at", "type", + "following", "html_url", "created_at", "type", "gravatar_id", # Seen only by owners "disk_usage", "collaborators", "billing_email", "plan", "private_gists", "total_private_repos", "owned_private_repos", @@ -467,13 +468,13 @@ Repository._addAttributePolicy( ) def __getNetworkEvents( repo ): return [ - Event( repo._github, attributes ) + Event( repo._github, attributes, lazy = True ) for attributes - in repo._github._dataRequest( "GET", repo._baseUrl + "/events", None, None ) + in repo._github._dataRequest( "GET", "/networks/" + repo.owner.login + "/" + repo.name + "/events", None, None ) ] def __getIssuesEvents( repo ): return [ - Event( repo._github, attributes ) + Event( repo._github, attributes, lazy = True ) for attributes in repo._github._dataRequest( "GET", repo._baseUrl + "/issues/events", None, None ) ] @@ -481,7 +482,7 @@ Repository._addAttributePolicy( MethodFromCallable( "get_network_events", [], [], __getNetworkEvents, SimpleTypePolicy( "list of `Event`" ) ) ) Repository._addAttributePolicy( - MethodFromCallable( "get_issues_events", [], [], __getNetworkEvents, SimpleTypePolicy( "list of `Event`" ) ) + MethodFromCallable( "get_issues_events", [], [], __getIssuesEvents, SimpleTypePolicy( "list of `Event`" ) ) ) Repository._addAttributePolicy( ExternalListOfObjects( "forks", "fork", Repository, diff --git a/github/Requester.py b/github/Requester.py index 13f2a821..0b9aae8b 100644 --- a/github/Requester.py +++ b/github/Requester.py @@ -18,7 +18,8 @@ class Requester: headers, output = self.__statusCheckedRequest( verb, url, parameters, input ) - while "link" in headers and "next" in headers[ "link" ]: + obviouslyFinished = False + while "link" in headers and "next" in headers[ "link" ] and not obviouslyFinished: for link in headers[ "link" ].split( "," ): if "next" in link: linkUrl = link.split( ";" )[ 0 ][ : -1 ] @@ -26,6 +27,8 @@ class Requester: parameters.update( dict( p.split( "=" ) for p in params.split( "&" ) ) ) break headers, newOutput = self.__statusCheckedRequest( verb, url, parameters, input ) + if len( newOutput ) == 0: + obviouslyFinished = True output += newOutput return output From 07b6b437d741df9c94cf34e36045fc78868b63ba Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Mon, 12 Mar 2012 20:43:20 +0100 Subject: [PATCH 47/56] Remove two 'MethodFromCallable' --- github/GithubObjects.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 5b127bb8..42197018 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -136,14 +136,10 @@ def __getPublicEvents( user ): NamedUser._addAttributePolicy( MethodFromCallable( "get_public_events", [], [], __getPublicEvents, SimpleTypePolicy( "list of `Event`" ) ) ) -def __getReceivedEvents( user ): - return [ - Event( user._github, attributes, lazy = True ) - for attributes - in user._github._dataRequest( "GET", user._baseUrl + "/received_events", None, None ) - ] NamedUser._addAttributePolicy( - MethodFromCallable( "get_received_events", [], [], __getReceivedEvents, SimpleTypePolicy( "list of `Event`" ) ) + ExternalListOfObjects( "received_events", "received_event", Event, + ListGetable( [], [] ) + ) ) def __getPublicReceivedEvents( user ): return [ @@ -472,17 +468,13 @@ def __getNetworkEvents( repo ): for attributes in repo._github._dataRequest( "GET", "/networks/" + repo.owner.login + "/" + repo.name + "/events", None, None ) ] -def __getIssuesEvents( repo ): - return [ - Event( repo._github, attributes, lazy = True ) - for attributes - in repo._github._dataRequest( "GET", repo._baseUrl + "/issues/events", None, None ) - ] Repository._addAttributePolicy( MethodFromCallable( "get_network_events", [], [], __getNetworkEvents, SimpleTypePolicy( "list of `Event`" ) ) ) Repository._addAttributePolicy( - MethodFromCallable( "get_issues_events", [], [], __getIssuesEvents, SimpleTypePolicy( "list of `Event`" ) ) + ExternalListOfObjects( "issues/events", "issues_event", Event, + ListGetable( [], [] ) + ) ) Repository._addAttributePolicy( ExternalListOfObjects( "forks", "fork", Repository, From 43369be99710f4386d31daa87db9b5cc48f0544d Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Mon, 12 Mar 2012 21:22:10 +0100 Subject: [PATCH 48/56] Repository.get_issues_event + coverage --- IntegrationTest.py | 16 +++++++++++----- ReferenceOfApis.md | 4 ++-- github/GithubObjects.py | 19 +++++++++++++++---- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index b01fe4ff..73675ce9 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -167,24 +167,29 @@ class IntegrationTest: coveredUrls[ url ].add( verb ) uncoveredMethods = set() + uncoveredApis = set() with open( "ReferenceOfApis.md" ) as file: for line in file.readlines(): line = line.strip() if line.startswith( "API" ): currentApi = line[ 5 : -1 ] apiRegex = re.sub( ":\w+", "\w+", currentApi ) - if line.startswith( "* " ) and line.endswith( "`" ): + if line.startswith( "* " ): verb = line[ 2 : line.find( ":" ) ] for url, verbs in coveredUrls.iteritems(): if re.match( apiRegex, url ) and verb in verbs: break else: - uncoveredMethods.add( line[ line.find( "`" ) + 1 : -1 ] ) + if "`" in line: + uncoveredMethods.add( line[ line.find( "`" ) + 1 : -1 ] ) + else: + uncoveredApis.add( verb + " " + currentApi ) - if len( uncoveredMethods ) != 0: + if len( uncoveredMethods ) != 0 or len( uncoveredApis ) != 0: print - print "Not covered (" + str( len( uncoveredMethods ) ) + "):" + print "Not covered (" + str( len( uncoveredMethods ) + len( uncoveredApis ) ) + "):" print "\n".join( sorted( uncoveredMethods ) ) + print "\n".join( sorted( uncoveredApis ) ) def testAuthenticatedUserDetails( self ): u = self.g.get_user() @@ -318,6 +323,7 @@ class IntegrationTest: self.printList( "Repo events", self.g.get_user().get_repo( "TestPyGithub" ).get_events(), lambda e: e.type ) self.printList( "Repo issues events", self.g.get_user().get_repo( "TestPyGithub" ).get_issues_events(), lambda e: e.event ) + print self.g.get_user().get_repo( "TestPyGithub" ).get_issues_event( 10693379 ).event self.printList( "Repo network events", self.g.get_user().get_repo( "TestPyGithub" ).get_network_events(), lambda e: e.type ) self.printList( "Issue events", self.g.get_user().get_repo( "TestPyGithub" ).get_issue( 23 ).get_events(), lambda e: e.event ) @@ -551,6 +557,6 @@ class IntegrationTest: self.printList( "Emails", u.get_emails() ) def printList( self, title, iterable, f = lambda x: x ): - print title + ":", ", ".join( f( x ) for x in iterable[ :10 ] ), "..." if len( iterable ) > 10 else "" + print title + ":", ", ".join( str( f( x ) ) for x in iterable[ :10 ] ), "..." if len( iterable ) > 10 else "" IntegrationTest().main( sys.argv[ 1: ] ) diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index f175d68d..5aed45d0 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -208,7 +208,7 @@ API `/repos/:user/:repo/git/trees` API `/repos/:user/:repo/git/trees?base_tree=` ============================================= -* POST: `GitTree.create_update` (TODO) +* POST: (TODO) API `/repos/:user/:repo/git/trees/:sha` ======================================= @@ -275,7 +275,7 @@ API `/repos/:user/:repo/issues/events` API `/repos/:user/:repo/issues/events/:id` ========================================== -* GET: (TODO SOON) +* GET: `Repository.get_issues_event` API `/repos/:user/:repo/keys` ============================= diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 42197018..a1af0dc6 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -288,6 +288,16 @@ IssueComment = GithubObject( Deletable(), ) +IssueEvent = GithubObject( + "IssueEvent", + BaseUrl( lambda obj: obj._repo._baseUrl + "/issues/events/" + str( obj.id ) ), + InternalSimpleAttributes( + "id", "url", "created_at", "issue", "event", "commit_id", + "_repo", # Ugly hack + ), + InternalObjectAttribute( "actor", NamedUser ), +) + Issue = GithubObject( "Issue", BaseUrl( lambda obj: obj._repo._baseUrl + "/issues/" + str( obj.number ) ), @@ -313,8 +323,8 @@ Issue = GithubObject( ElementGetable( [ "id" ], [], __modifyAttributesForObjectsReferingReferedRepo ), ElementCreatable( [ "body" ], [], __modifyAttributesForObjectsReferingReferedRepo ), ), - ExternalListOfObjects( "events", "event", Event, - ListGetable( [], [] ) + ExternalListOfObjects( "events", "event", IssueEvent, + ListGetable( [], [], __modifyAttributesForObjectsReferingReferedRepo ) ), ) @@ -472,8 +482,9 @@ Repository._addAttributePolicy( MethodFromCallable( "get_network_events", [], [], __getNetworkEvents, SimpleTypePolicy( "list of `Event`" ) ) ) Repository._addAttributePolicy( - ExternalListOfObjects( "issues/events", "issues_event", Event, - ListGetable( [], [] ) + ExternalListOfObjects( "issues/events", "issues_event", IssueEvent, + ListGetable( [], [], __modifyAttributesForObjectsReferingRepo ), + ElementGetable( [ "id" ], [], __modifyAttributesForObjectsReferingRepo ), ) ) Repository._addAttributePolicy( From 236fcaead6addd284722e4b5fde2e24f6f4ae63b Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Mon, 12 Mar 2012 21:28:26 +0100 Subject: [PATCH 49/56] Restore test coverage --- github/Github.UnitTest.py | 15 +++++++++++++++ github/Requester.UnitTest.py | 6 ++++++ 2 files changed, 21 insertions(+) diff --git a/github/Github.UnitTest.py b/github/Github.UnitTest.py index e614a825..a58a9d36 100644 --- a/github/Github.UnitTest.py +++ b/github/Github.UnitTest.py @@ -68,4 +68,19 @@ class TestCase( unittest.TestCase ): self.requester.expect.statusRequest( "POST", "/repos/xxx/yyy/hooks/1/test", None, None ).andReturn( 204 ) h.test() + def testUserEvents( self ): + self.requester.expect.dataRequest( "GET", "/users/xxx", None, None ).andReturn( { "login": "xxx" } ) + self.requester.expect.dataRequest( "GET", "/users/xxx/events/public", None, None ).andReturn( [] ) + self.requester.expect.dataRequest( "GET", "/users/xxx/received_events/public", None, None ).andReturn( [] ) + u = self.g.get_user( "xxx" ) + u.get_public_events() + u.get_public_received_events() + + def testRepoEvents( self ): + self.requester.expect.dataRequest( "GET", "/user", None, None ).andReturn( { "login": "xxx" } ) + self.requester.expect.dataRequest( "GET", "/repos/xxx/yyy", None, None ).andReturn( { "name": "yyy", "owner": { "login": "xxx" } } ) + self.requester.expect.dataRequest( "GET", "/networks/xxx/yyy/events", None, None ).andReturn( [] ) + r = self.g.get_user().get_repo( "yyy" ) + r.get_network_events() + unittest.main() diff --git a/github/Requester.UnitTest.py b/github/Requester.UnitTest.py index 92fa200f..1901018b 100644 --- a/github/Requester.UnitTest.py +++ b/github/Requester.UnitTest.py @@ -55,4 +55,10 @@ class TestCase( unittest.TestCase ): self.expect( "GET", "/test?page=3", 'null', 200, [ ( "link", "xxx; prev, xxx; first" ) ], '[ 5, 6 ]' ) self.assertEqual( self.r.dataRequest( "GET", "/test", None, None ), [ 1, 2, 3, 4, 5, 6 ] ) + def testPaginationObviouslyFinished( self ): + self.expect( "GET", "/test", 'null', 200, [ ( "link", "; next, xxx; last" ) ], '[ 1, 2 ]' ) + self.expect( "GET", "/test?page=2", 'null', 200, [ ( "link", "xxx; prev, xxx; first, ; next, xxx; last" ) ], '[ 3, 4 ]' ) + self.expect( "GET", "/test?page=3", 'null', 200, [ ( "link", "xxx; prev, xxx; first" ) ], '[]' ) + self.assertEqual( self.r.dataRequest( "GET", "/test", None, None ), [ 1, 2, 3, 4 ] ) + unittest.main() From b12b6ffdfa6f1cca89459438eff6d3420ed199e9 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Mon, 12 Mar 2012 21:48:27 +0100 Subject: [PATCH 50/56] AuthenticatedUser.get_organization_events --- IntegrationTest.py | 2 ++ ReferenceOfApis.md | 2 +- github/Github.UnitTest.py | 8 ++++++++ github/GithubObjects.py | 10 ++++++++++ 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index 73675ce9..440593f5 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -320,6 +320,8 @@ class IntegrationTest: self.printList( "Organization events", self.g.get_organization( self.cobayeOrganization ).get_events(), lambda e: e.type ) self.printList( "User events", self.g.get_user().get_events(), lambda e: e.type ) + o = self.g.get_organization( self.cobayeOrganization ) + self.printList( "Organization events", self.g.get_user().get_organization_events( o ), lambda e: e.type ) self.printList( "Repo events", self.g.get_user().get_repo( "TestPyGithub" ).get_events(), lambda e: e.type ) self.printList( "Repo issues events", self.g.get_user().get_repo( "TestPyGithub" ).get_issues_events(), lambda e: e.event ) diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index 5aed45d0..242c91f7 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -455,7 +455,7 @@ API `/users/:user/events` API `/users/:user/events/orgs/:org` =================================== -* GET: (TODO SOON) +* GET: `AuthenticatedUser.get_organization_events` API `/users/:user/events/public` ================================ diff --git a/github/Github.UnitTest.py b/github/Github.UnitTest.py index a58a9d36..9a8bc589 100644 --- a/github/Github.UnitTest.py +++ b/github/Github.UnitTest.py @@ -83,4 +83,12 @@ class TestCase( unittest.TestCase ): r = self.g.get_user().get_repo( "yyy" ) r.get_network_events() + def testOrgEvents( self ): + self.requester.expect.dataRequest( "GET", "/orgs/ooo", None, None ).andReturn( { "login": "ooo" } ) + self.requester.expect.dataRequest( "GET", "/user", None, None ).andReturn( { "login": "xxx" } ) + self.requester.expect.dataRequest( "GET", "/users/xxx/events/orgs/ooo", None, None ).andReturn( [] ) + u = self.g.get_user() + o = self.g.get_organization( "ooo" ) + u.get_organization_events( o ) + unittest.main() diff --git a/github/GithubObjects.py b/github/GithubObjects.py index a1af0dc6..51deea5f 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -191,6 +191,16 @@ NamedUser._addAttributePolicy( ) ) +def __getOrganizationEvents( user, org ): + return [ + Event( user._github, attributes, lazy = True ) + for attributes + in user._github._dataRequest( "GET", "/users/" + user.login + "/events/orgs/" + org.login, None, None ) + ] +AuthenticatedUser._addAttributePolicy( + MethodFromCallable( "get_organization_events", [ "org" ], [], __getOrganizationEvents, SimpleTypePolicy( "list of `Event`" ) ) +) + GitRef = GithubObject( "GitRef", BaseUrl( lambda obj: obj._repo._baseUrl + "/git/" + obj.ref ), From 0d3b3ffd1e5c143af8725fdee808101f626f683d Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Mon, 12 Mar 2012 21:51:50 +0100 Subject: [PATCH 51/56] Improve coverage analysis --- IntegrationTest.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index 440593f5..bb62fa12 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -185,10 +185,12 @@ class IntegrationTest: else: uncoveredApis.add( verb + " " + currentApi ) - if len( uncoveredMethods ) != 0 or len( uncoveredApis ) != 0: - print - print "Not covered (" + str( len( uncoveredMethods ) + len( uncoveredApis ) ) + "):" + print + if len( uncoveredMethods ) != 0: + print "Not covered (" + str( len( uncoveredMethods ) ) + "):" print "\n".join( sorted( uncoveredMethods ) ) + if len( uncoveredApis ) != 0: + print "Not implemented (" + str( len( uncoveredApis ) ) + "):" print "\n".join( sorted( uncoveredApis ) ) def testAuthenticatedUserDetails( self ): From 366ca58ca004b9129f9d435db8204ce0f5bc57c3 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Mon, 12 Mar 2012 22:08:22 +0100 Subject: [PATCH 52/56] PullRequest.is_merged and PullRequest.merge --- IntegrationTest.py | 7 +++++++ ReferenceOfApis.md | 4 ++-- github/GithubObjects.py | 8 +++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index bb62fa12..61573f2c 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -481,6 +481,13 @@ class IntegrationTest: k.delete() self.printList( "Keys", u.get_keys(), lambda k: k.title ) + def testMergePullRequest( self ): + r = self.g.get_user().get_repo( "TestPyGithub" ) + p = r.get_pull( 26 ) + assert not p.is_merged() + p.merge() + assert p.is_merged() + def testNamedUserDetails( self ): u = self.g.get_user( "jacquev6" ) print u.login, "(" + u.name + ") is from", u.location diff --git a/ReferenceOfApis.md b/ReferenceOfApis.md index 242c91f7..8230f5fd 100644 --- a/ReferenceOfApis.md +++ b/ReferenceOfApis.md @@ -343,8 +343,8 @@ API `/repos/:user/:repo/pulls/:id/files` API `/repos/:user/:repo/pulls/:id/merge` ======================================== -* GET: (TODO) -* PUT: (TODO) +* GET: `PullRequest.is_merged` +* PUT: `PullRequest.merge` API `/repos/:user/:repo/pulls/comments/:id` =========================================== diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 51deea5f..8906c646 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -423,6 +423,10 @@ PullRequestComment = GithubObject( Deletable(), ) +def __pullRequestIsMerged( r ): + return r._github._statusRequest( "GET", r._baseUrl + "/merge", None, None ) == 204 +def __mergePullRequest( r, **data ): + r._github._statusRequest( "PUT", r._baseUrl + "/merge", None, data ) PullRequest = GithubObject( "PullRequest", BaseUrl( lambda obj: obj._repo._baseUrl + "/pulls/" + str( obj.number ) ), @@ -447,6 +451,8 @@ PullRequest = GithubObject( ElementGetable( [ "id" ], [], __modifyAttributesForObjectsReferingReferedRepo ), ElementCreatable( [ "body", "commit_id", "path", "position" ], [], __modifyAttributesForObjectsReferingReferedRepo ), ), + MethodFromCallable( "is_merged", [], [], __pullRequestIsMerged, SimpleTypePolicy( "bool" ) ), + MethodFromCallable( "merge", [], [ "commit_message" ], __mergePullRequest, SimpleTypePolicy( None ) ), ) RepositoryKey = GithubObject( @@ -588,7 +594,7 @@ Repository._addAttributePolicy( SeveralAttributePolicies( [ ), ExternalListOfObjects( "pulls", "pull", PullRequest, ListGetable( [], [ "state" ], __modifyAttributesForObjectsReferingRepo ), - ElementGetable( [ "id" ], [], __modifyAttributesForObjectsReferingRepo ), + ElementGetable( [ "number" ], [], __modifyAttributesForObjectsReferingRepo ), ElementCreatable( [ "title", "body", "base", "head" ], [], __modifyAttributesForObjectsReferingRepo ), ), ] ) ) From 2dd71f3777b87f2ba61cb20d2c67f10401e3eb2c Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Mon, 12 Mar 2012 22:11:40 +0100 Subject: [PATCH 53/56] Restore test coverage --- github/Github.UnitTest.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/github/Github.UnitTest.py b/github/Github.UnitTest.py index 9a8bc589..0c8708b5 100644 --- a/github/Github.UnitTest.py +++ b/github/Github.UnitTest.py @@ -91,4 +91,16 @@ class TestCase( unittest.TestCase ): o = self.g.get_organization( "ooo" ) u.get_organization_events( o ) + def testMergePullRequest( self ): + self.requester.expect.dataRequest( "GET", "/user", None, None ).andReturn( { "login": "xxx" } ) + self.requester.expect.dataRequest( "GET", "/repos/xxx/yyy", None, None ).andReturn( { "name": "yyy", "owner": { "login": "xxx" } } ) + self.requester.expect.dataRequest( "GET", "/repos/xxx/yyy/pulls/42", None, None ).andReturn( { "number": 42 } ) + self.requester.expect.statusRequest( "GET", "/repos/xxx/yyy/pulls/42/merge", None, None ).andReturn( 404 ) + self.requester.expect.statusRequest( "PUT", "/repos/xxx/yyy/pulls/42/merge", None, {} ).andReturn( 204 ) + self.requester.expect.statusRequest( "GET", "/repos/xxx/yyy/pulls/42/merge", None, None ).andReturn( 204 ) + p = self.g.get_user().get_repo( "yyy" ).get_pull( 42 ) + self.assertFalse( p.is_merged() ) + p.merge() + self.assertTrue( p.is_merged() ) + unittest.main() From fc33a6de4f0e08d7ff2de05935517ec3932d212e Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Mon, 12 Mar 2012 22:28:06 +0100 Subject: [PATCH 54/56] Fix bug: _baseUrl is now a method This handles modification of attributes creating the base url --- github/GithubObject.UnitTest.py | 3 +- github/GithubObject.py | 6 ++-- github/GithubObjects.py | 56 ++++++++++++++++---------------- github/ObjectCapacities/Basic.py | 4 +-- github/ObjectCapacities/List.py | 2 +- 5 files changed, 36 insertions(+), 35 deletions(-) diff --git a/github/GithubObject.UnitTest.py b/github/GithubObject.UnitTest.py index aeaf4cbf..ef810ef0 100644 --- a/github/GithubObject.UnitTest.py +++ b/github/GithubObject.UnitTest.py @@ -53,7 +53,8 @@ class GithubObjectWithDocumentationCoveringSpecialCases( TestCaseWithGithubTestO "GithubTestObject", BaseUrl( lambda obj: "/test" ), InternalSimpleAttributes( "a1", "a2", "_a3" ), - MethodFromCallable( "myMethod", [ "mock", "arg" ], [], lambda obj: 42, ObjectTypePolicy( GithubObject ) ) + MethodFromCallable( "myMethod", [ "mock", "arg" ], [], lambda obj: 42, ObjectTypePolicy( GithubObject ) ), + AttributeFromCallable( "myAttr", lambda obj: 42 ) ) def testNothing( self ): diff --git a/github/GithubObject.py b/github/GithubObject.py index 797b5d32..00d61745 100644 --- a/github/GithubObject.py +++ b/github/GithubObject.py @@ -21,20 +21,20 @@ def ExternalSimpleAttribute( attributeName, type ): return ExternalAttribute( attributeName, SimpleTypePolicy( type ) ) def BaseUrl( baseUrl ): - return AttributeFromCallable( "_baseUrl", baseUrl ) + return MethodFromCallable( "_baseUrl", [], [], baseUrl, SimpleTypePolicy( None ) ) def Identity( identity ): return AttributeFromCallable( "_identity", identity ) def Editable( mandatoryParameters, optionalParameters ): def __execute( obj, **data ): - attributes = obj._github._dataRequest( "PATCH", obj._baseUrl, None, data ) + attributes = obj._github._dataRequest( "PATCH", obj._baseUrl(), None, data ) obj._updateAttributes( attributes ) return SeveralAttributePolicies( [ MethodFromCallable( "edit", mandatoryParameters, optionalParameters, __execute, SimpleTypePolicy( None ) ) ], "Modification" ) def Deletable(): def __execute( obj ): - obj._github._statusRequest( "DELETE", obj._baseUrl, None, None ) + obj._github._statusRequest( "DELETE", obj._baseUrl(), None, None ) return SeveralAttributePolicies( [ MethodFromCallable( "delete", [], [], __execute, SimpleTypePolicy( None ) ) ], "Deletion" ) def GithubObject( className, *attributePolicies ): diff --git a/github/GithubObjects.py b/github/GithubObjects.py index 8906c646..7bf493d5 100644 --- a/github/GithubObjects.py +++ b/github/GithubObjects.py @@ -12,10 +12,10 @@ Event = GithubObject( ) def __testHook( hook ): - hook._github._statusRequest( "POST", hook._baseUrl + "/test", None, None ) + hook._github._statusRequest( "POST", hook._baseUrl() + "/test", None, None ) Hook = GithubObject( "Hook", - BaseUrl( lambda obj: obj._repo._baseUrl + "/hooks/" + str( obj.id ) ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/hooks/" + str( obj.id ) ), InternalSimpleAttributes( "url", "updated_at", "created_at", "name", "events", "active", "config", "id", "last_response", @@ -131,7 +131,7 @@ def __getPublicEvents( user ): return [ Event( user._github, attributes, lazy = True ) for attributes - in user._github._dataRequest( "GET", user._baseUrl + "/events/public", None, None ) + in user._github._dataRequest( "GET", user._baseUrl() + "/events/public", None, None ) ] NamedUser._addAttributePolicy( MethodFromCallable( "get_public_events", [], [], __getPublicEvents, SimpleTypePolicy( "list of `Event`" ) ) @@ -145,7 +145,7 @@ def __getPublicReceivedEvents( user ): return [ Event( user._github, attributes, lazy = True ) for attributes - in user._github._dataRequest( "GET", user._baseUrl + "/received_events/public", None, None ) + in user._github._dataRequest( "GET", user._baseUrl() + "/received_events/public", None, None ) ] NamedUser._addAttributePolicy( MethodFromCallable( "get_public_received_events", [], [], __getPublicReceivedEvents, SimpleTypePolicy( "list of `Event`" ) ) @@ -203,7 +203,7 @@ AuthenticatedUser._addAttributePolicy( GitRef = GithubObject( "GitRef", - BaseUrl( lambda obj: obj._repo._baseUrl + "/git/" + obj.ref ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/git/" + obj.ref ), InternalSimpleAttributes( "ref", "url", "object", ### @todo Structure @@ -214,7 +214,7 @@ GitRef = GithubObject( GitTree = GithubObject( "GitTree", - BaseUrl( lambda obj: obj._repo._baseUrl + "/git/trees/" + obj.sha ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/git/trees/" + obj.sha ), InternalSimpleAttributes( "sha", "url", "tree", ### @todo Structure @@ -224,7 +224,7 @@ GitTree = GithubObject( GitCommit = GithubObject( "GitCommit", - BaseUrl( lambda obj: obj._repo._baseUrl + "/git/commits/" + obj.sha ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/git/commits/" + obj.sha ), InternalSimpleAttributes( "sha", "url", "message", "parents", ### @todo Structure @@ -236,7 +236,7 @@ GitCommit = GithubObject( GitBlob = GithubObject( "GitBlob", - BaseUrl( lambda obj: obj._repo._baseUrl + "/git/blobs/" + obj.sha ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/git/blobs/" + obj.sha ), InternalSimpleAttributes( "sha", "size", "url", "content", "encoding", @@ -246,7 +246,7 @@ GitBlob = GithubObject( GitTag = GithubObject( "GitTag", - BaseUrl( lambda obj: obj._repo._baseUrl + "/git/tags/" + obj.sha ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/git/tags/" + obj.sha ), InternalSimpleAttributes( "tag", "sha", "url", "message", @@ -258,7 +258,7 @@ GitTag = GithubObject( Label = GithubObject( "Label", - BaseUrl( lambda obj: obj._repo._baseUrl + "/labels/" + obj._identity ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/labels/" + obj._identity ), Identity( lambda obj: urllib.quote( obj.name ) ), InternalSimpleAttributes( "url", "name", "color", @@ -272,7 +272,7 @@ __modifyAttributesForObjectsReferingReferedRepo = { "_repo": lambda obj: obj._re Milestone = GithubObject( "Milestone", - BaseUrl( lambda obj: obj._repo._baseUrl + "/milestones/" + str( obj.number ) ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/milestones/" + str( obj.number ) ), InternalSimpleAttributes( "url", "number", "state", "title", "description", "open_issues", "closed_issues", "created_at", "due_on", @@ -288,7 +288,7 @@ Milestone = GithubObject( IssueComment = GithubObject( "IssueComment", - BaseUrl( lambda obj: obj._repo._baseUrl + "/issues/comments/" + str( obj.id ) ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/issues/comments/" + str( obj.id ) ), InternalSimpleAttributes( "url", "body", "created_at", "updated_at", "id", "_repo", ### Ugly hack @@ -300,7 +300,7 @@ IssueComment = GithubObject( IssueEvent = GithubObject( "IssueEvent", - BaseUrl( lambda obj: obj._repo._baseUrl + "/issues/events/" + str( obj.id ) ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/issues/events/" + str( obj.id ) ), InternalSimpleAttributes( "id", "url", "created_at", "issue", "event", "commit_id", "_repo", # Ugly hack @@ -310,7 +310,7 @@ IssueEvent = GithubObject( Issue = GithubObject( "Issue", - BaseUrl( lambda obj: obj._repo._baseUrl + "/issues/" + str( obj.number ) ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/issues/" + str( obj.number ) ), InternalSimpleAttributes( "url", "html_url", "number", "state", "title", "body", "labels", "comments", "closed_at", "created_at", "updated_at", "id", "closed_by", @@ -340,7 +340,7 @@ Issue = GithubObject( Download = GithubObject( "Download", - BaseUrl( lambda obj: obj._repo._baseUrl + "/downloads/" + str( obj.id ) ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/downloads/" + str( obj.id ) ), InternalSimpleAttributes( "url", "html_url", "id", "name", "description", "size", "download_count", "content_type", "policy", "signature", "bucket", @@ -353,7 +353,7 @@ Download = GithubObject( CommitComment = GithubObject( "CommitComment", - BaseUrl( lambda obj: obj._repo._baseUrl + "/comments/" + str( obj.id ) ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/comments/" + str( obj.id ) ), InternalSimpleAttributes( "url", "id", "body", "path", "position", "commit_id", "created_at", "updated_at", "html_url", "line", @@ -366,7 +366,7 @@ CommitComment = GithubObject( Commit = GithubObject( "Commit", - BaseUrl( lambda obj: obj._repo._baseUrl + "/commits/" + str( obj.sha ) ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/commits/" + str( obj.sha ) ), InternalSimpleAttributes( "sha", "url", "parents", ### @todo Structure @@ -412,7 +412,7 @@ PullRequestFile = GithubObject( PullRequestComment = GithubObject( "PullRequestComment", - BaseUrl( lambda obj: obj._repo._baseUrl + "/pulls/comments/" + str( obj.id ) ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/pulls/comments/" + str( obj.id ) ), InternalSimpleAttributes( "url", "id", "body", "path", "position", "commit_id", "created_at", "updated_at", "html_url", "line", @@ -424,12 +424,12 @@ PullRequestComment = GithubObject( ) def __pullRequestIsMerged( r ): - return r._github._statusRequest( "GET", r._baseUrl + "/merge", None, None ) == 204 + return r._github._statusRequest( "GET", r._baseUrl() + "/merge", None, None ) == 204 def __mergePullRequest( r, **data ): - r._github._statusRequest( "PUT", r._baseUrl + "/merge", None, data ) + r._github._statusRequest( "PUT", r._baseUrl() + "/merge", None, data ) PullRequest = GithubObject( "PullRequest", - BaseUrl( lambda obj: obj._repo._baseUrl + "/pulls/" + str( obj.number ) ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/pulls/" + str( obj.number ) ), InternalSimpleAttributes( "id", "url", "html_url", "diff_url", "patch_url", "issue_url", "number", "state", "title", "body", "created_at", "updated_at", "closed_at", @@ -457,7 +457,7 @@ PullRequest = GithubObject( RepositoryKey = GithubObject( "RepositoryKey", - BaseUrl( lambda obj: obj._repo._baseUrl + "/keys/" + str( obj.id ) ), + BaseUrl( lambda obj: obj._repo._baseUrl() + "/keys/" + str( obj.id ) ), InternalSimpleAttributes( "url", "id", "title", "key", "_repo", ### Ugly hack @@ -639,11 +639,11 @@ NamedUser._addAttributePolicy( def __createForkForUser( user, repo ): assert isinstance( repo, Repository ) - return Repository( user._github, user._github._dataRequest( "POST", repo._baseUrl + "/forks", None, None ), lazy = True ) + return Repository( user._github, user._github._dataRequest( "POST", repo._baseUrl() + "/forks", None, None ), lazy = True ) AuthenticatedUser._addAttributePolicy( SeveralAttributePolicies( [ MethodFromCallable( "create_fork", [ "repo" ], [], __createForkForUser, ObjectTypePolicy( Repository ) ) ], "Forking" ) ) def __createForkForOrg( org, repo ): assert isinstance( repo, Repository ) - return Repository( org._github, org._github._dataRequest( "POST", repo._baseUrl + "/forks", { "org": org.login }, None ), lazy = True ) + return Repository( org._github, org._github._dataRequest( "POST", repo._baseUrl() + "/forks", { "org": org.login }, None ), lazy = True ) Organization._addAttributePolicy( SeveralAttributePolicies( [ MethodFromCallable( "create_fork", [ "repo" ], [], __createForkForOrg, ObjectTypePolicy( Repository ) ) ], "Forking" ) ) Team = GithubObject( @@ -694,11 +694,11 @@ GistComment = GithubObject( ) def __isStarred( gist ): - return gist._github._statusRequest( "GET", gist._baseUrl + "/star", None, None ) == 204 + return gist._github._statusRequest( "GET", gist._baseUrl() + "/star", None, None ) == 204 def __setStarred( gist ): - gist._github._statusRequest( "PUT", gist._baseUrl + "/star", None, None ) + gist._github._statusRequest( "PUT", gist._baseUrl() + "/star", None, None ) def __resetStarred( gist ): - gist._github._statusRequest( "DELETE", gist._baseUrl + "/star", None, None ) + gist._github._statusRequest( "DELETE", gist._baseUrl() + "/star", None, None ) Gist = GithubObject( "Gist", BaseUrl( lambda obj: "/gists/" + str( obj.id ) ), @@ -722,7 +722,7 @@ Gist = GithubObject( ], "Starring" ), ) def __createFork( gist ): - return Gist( gist._github, gist._github._dataRequest( "POST", gist._baseUrl + "/fork", None, None ), lazy = True ) + return Gist( gist._github, gist._github._dataRequest( "POST", gist._baseUrl() + "/fork", None, None ), lazy = True ) Gist._addAttributePolicy( SeveralAttributePolicies( [ MethodFromCallable( "create_fork", [], [], __createFork, ObjectTypePolicy( Gist ) ), ], "Forking" ), diff --git a/github/ObjectCapacities/Basic.py b/github/ObjectCapacities/Basic.py index cdf8fcf7..8fc7685a 100644 --- a/github/ObjectCapacities/Basic.py +++ b/github/ObjectCapacities/Basic.py @@ -59,7 +59,7 @@ class InternalAttribute: return self.__typePolicy.createLazy( obj, rawValue ) def updateAttributes( self, obj ): - attributes = obj._github._dataRequest( "GET", obj._baseUrl, None, None ) + attributes = obj._github._dataRequest( "GET", obj._baseUrl(), None, None ) obj._updateAttributes( attributes ) obj._markAsCompleted() @@ -93,7 +93,7 @@ class ExternalAttribute: def __execute( self, obj ): return self.__typePolicy.createLazy( obj, - obj._github._dataRequest( "GET", obj._baseUrl + "/" + self.__attributeName, None, None ) + obj._github._dataRequest( "GET", obj._baseUrl() + "/" + self.__attributeName, None, None ) ) def autoDocument( self ): diff --git a/github/ObjectCapacities/List.py b/github/ObjectCapacities/List.py index 0148c3f8..f7ef4cab 100644 --- a/github/ObjectCapacities/List.py +++ b/github/ObjectCapacities/List.py @@ -15,7 +15,7 @@ class ListCapacity: def baseUrl( self, obj ): if self.__url is None: - return obj._baseUrl + "/" + self.attributeName + return obj._baseUrl() + "/" + self.attributeName else: return self.__url From 97f308e67383368a2d15788cac28e126c8528bb2 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Mon, 12 Mar 2012 22:31:09 +0100 Subject: [PATCH 55/56] Restore integration test after bugfix --- IntegrationTest.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/IntegrationTest.py b/IntegrationTest.py index 61573f2c..2a23bec3 100644 --- a/IntegrationTest.py +++ b/IntegrationTest.py @@ -445,9 +445,8 @@ class IntegrationTest: self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) labelD = r.create_label( "D", "FF0000" ) self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) - ### @todo Uncomment after fixing bug about BaseUrl depending on editable attribute - # labelD.edit( "Dada", "00FF00" ) - # self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) + labelD.edit( "Dada", "00FF00" ) + self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) labelD.delete() self.printList( "Repository labels", r.get_labels(), lambda l: l.name ) From 7b7ac20c6fa27f72a24483c73ab1bf4deffc89f0 Mon Sep 17 00:00:00 2001 From: Vincent Jacques Date: Mon, 12 Mar 2012 22:36:59 +0100 Subject: [PATCH 56/56] Add a unit test with a changing _baseUrl --- github/GithubObject.UnitTest.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/github/GithubObject.UnitTest.py b/github/GithubObject.UnitTest.py index ef810ef0..9a546a58 100644 --- a/github/GithubObject.UnitTest.py +++ b/github/GithubObject.UnitTest.py @@ -3,10 +3,6 @@ import MockMockMock from GithubObject import * -### @todo add a test where BaseUrl depends on some editable attribute. -### Show that BaseUrl is faithfull to the edited attribute -### (currently not the case for Label, whish has a BaseUrl depending on its name) - class GithubObjectTestCase( unittest.TestCase ): def testDuplicatedAttributeInOnePolicy( self ): with self.assertRaises( BadGithubObjectException ): @@ -60,6 +56,20 @@ class GithubObjectWithDocumentationCoveringSpecialCases( TestCaseWithGithubTestO def testNothing( self ): pass +class GithubObjectWithBaseUrlDependingOnAttribute( TestCaseWithGithubTestObject ): + GithubTestObject = GithubObject( + "GithubTestObject", + BaseUrl( lambda obj: "/test/" + str( obj.a1 ) ), + InternalSimpleAttributes( "a1", "a2", "a3", "a4" ), + Editable( [ "a1" ], [] ) + ) + + def test( self ): + self.expectDataPatch( "/test/1", { "a1": 11 } ).andReturn( { "a1": 110 } ) + self.expectDataPatch( "/test/110", { "a1": 111 } ).andReturn( { "a1": 1110 } ) + self.o.edit( 11 ) + self.o.edit( 111 ) + class GithubObjectWithOnlyInternalSimpleAttributes( TestCaseWithGithubTestObject ): GithubTestObject = GithubObject( "GithubTestObject",