diff --git a/doc/ReferenceOfApis.md b/doc/ReferenceOfApis.md index 73586918..f1666989 100644 --- a/doc/ReferenceOfApis.md +++ b/doc/ReferenceOfApis.md @@ -133,7 +133,7 @@ API `/rate_limit` API `/repos/:user/:repo` ======================== -* GET: `AuthenticatedUser.get_repo`, `NamedUser.get_repo` or `Organization.get_repo` +* GET: `AuthenticatedUser.get_repo` or `NamedUser.get_repo` or `Organization.get_repo` * PATCH: `Repository.edit` * DELETE: `Repository.delete` @@ -219,7 +219,7 @@ API `/repos/:user/:repo/events` API `/repos/:user/:repo/forks` ============================== * GET: `Repository.get_forks` -* POST: `AuthenticatedUser.create_fork` +* POST: `AuthenticatedUser.create_fork` or `Organization.create_fork` API `/repos/:user/:repo/git/blobs` ================================== @@ -433,7 +433,7 @@ API `/repos/:user/:repo/watchers` API `/teams/:id` ================ -* GET: Lazy completion of `Team` +* GET: `Organization.get_team` * PATCH: `Team.edit` * DELETE: `Team.delete` diff --git a/doc/ReferenceOfClasses.md b/doc/ReferenceOfClasses.md index 3db332e4..19e745a4 100644 --- a/doc/ReferenceOfClasses.md +++ b/doc/ReferenceOfClasses.md @@ -47,7 +47,9 @@ You can iterate on it in a `for f in user.get_followers():` loop or with any [it You cannot know the number of objects returned before the end of the iteration. If that's *really* what you need, you cant use `len( list( user.get_followers() ) )`, which does all the requests needed to enumerate the user's followers. Note that there is often an attribute giving this value (in that case `user.followers`). -You can also call `get_page( page )` where `page` is an integer starting at 0, to explicitely get a specific page if you don't want to hide pagination. +You can also call `get_page( page )` to explicitely get a specific page if you don't want to hide pagination. `page` starts at 0. +* `get_page( page )`: list + * `page`: integer Class `GithubException` ======================= @@ -1042,14 +1044,22 @@ Attributes Review comments --------------- -* `create_comment( body, commit_id, path, position )` or `create_review_comment( body, commit_id, path, position )`: `PullRequestComment` +* `create_comment( body, commit_id, path, position )`: `PullRequestComment` * `body`: string * `commit_id`: `Commit` * `path`: string * `position`: integer -* `get_comment( id )` or `get_review_comment( id )`: `PullRequestComment` +* `create_review_comment( body, commit_id, path, position )`: `PullRequestComment` + * `body`: string + * `commit_id`: `Commit` + * `path`: string + * `position`: integer +* `get_comment( id )`: `PullRequestComment` * `id`: integer -* `get_comments()` or `get_review_comments()`: `PaginatedList` of `PullRequestComment` +* `get_review_comment( id )`: `PullRequestComment` + * `id`: integer +* `get_comments()`: `PaginatedList` of `PullRequestComment` +* `get_review_comments()`: `PaginatedList` of `PullRequestComment` Commits ------- diff --git a/generateDocstrings.py b/generateDocstrings.py new file mode 100644 index 00000000..b041fdf5 --- /dev/null +++ b/generateDocstrings.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python + +import subprocess +import glob +import re +import collections + +class ClassDescription: + def __init__( self ): + self.properties = dict() + self.methods = collections.OrderedDict() + +class MethodDescription: + def __init__( self, returnType ): + self.verb = None + self.url = None + self.returnType = returnType + self.parameters = collections.OrderedDict() + +class Generator(): + privateClasses = [ + "PaginatedList", + "PaginatedListBase", + "GithubObject", + "BasicGithubObject", + "_NotSetType", + "Requester", + ] + + def getClassDocstring( self, className ): + if className in self.privateClasses: + return [] + else: + return [ + "Please edit this generated docstring for class " + className + ".", + ] + + def getMemberDocstring( self, className, memberName ): + if className in self.privateClasses: + return [] + elif className in self.classDescriptions: + classDescription = self.classDescriptions[ className ] + if memberName in classDescription.properties: + return [ + "Please edit this generated docstring for property " + className + "." + memberName + ".", + classDescription.properties[ memberName ] + ] + elif memberName in classDescription.methods: + return [ + "Please edit this generated docstring for method " + className + "." + memberName + ".", + "Calls " + ( classDescription.methods[ memberName ].verb or "WTF" ) + " " + ( classDescription.methods[ memberName ].url or "WTF" ) + ] + [ + ":param " + parameterName + ": " + parameterType for parameterName, parameterType in classDescription.methods[ memberName ].parameters.items() + ] + [ + ":return: " + str( classDescription.methods[ memberName ].returnType ) + ] + elif memberName.startswith( "_" ): # private member + return [] + else: + print "Unknown member", className, memberName + return [] + else: + print "Unknown class", className + return [] + + def __init__( self ): + pass + + def run( self ): + self.restoreSources() + self.readReferenceOfClasses() + self.readReferenceOfApis() + self.generate() + + def restoreSources( self ): + subprocess.check_call( [ "git", "checkout", "--", "github" ] ) + + def readReferenceOfClasses( self ): + self.classDescriptions = dict() + with open( "doc/ReferenceOfClasses.md" ) as f: + for line in f: + line = line.rstrip() + if line.startswith( "Class `" ): + className = line[ 7 : -1 ] + self.classDescriptions[ className ] = ClassDescription() + if line.startswith( "*" ): + if "rate_limiting" in line: + self.classDescriptions[ className ].properties[ "rate_limiting" ] = "( int, int )" + elif "(" in line: + methodName, returnType = re.match( "^\* `(.*)\(.*\)`(?:: (.*))?$", line ).groups() + self.classDescriptions[ className ].methods[ methodName ] = MethodDescription( returnType ) + else: + attributeName, attributeType = re.match( "^\* `(.*)`: (.*)$", line ).groups() + self.classDescriptions[ className ].properties[ attributeName ] = attributeType + if line.startswith( " *" ): + parameterName, parameterType = re.match( "^ \* `(.*)`: (.*)$", line ).groups() + self.classDescriptions[ className ].methods[ methodName ].parameters[ parameterName ] = parameterType + + def readReferenceOfApis( self ): + with open( "doc/ReferenceOfApis.md" ) as f: + for line in f: + line = line.rstrip() + if line.startswith( "API" ): + url = line[ 5 : -1 ] + if line.startswith( "*" ) and line not in [ "* POST: see API `/markdown`", "* GET: Not implemented, see `Github.rate_limiting`" ]: + verb, methods = re.match( "^\* (.*): (.*)$", line ).groups() + for method in methods.split( " or " ): + className, methodName = re.match( "^`(.*)\.(.*)`", method ).groups() + self.classDescriptions[ className ].methods[ methodName ].verb = verb + self.classDescriptions[ className ].methods[ methodName ].url = url + + def generate( self ): + for f in glob.glob( "github/*.py" ): + self.generateForFile( f ) + + def generateForFile( self, fileName ): + self.writeLines( fileName, self.processLines( self.readLines( fileName ) ) ) + + def processLines( self, lines ): + nextDefIsStaticMethod = False + nextDefIsClassMethod = False + + for line in lines: + yield line + if line.startswith( "class" ): + className = re.match( "^class (.*?)(?:\(.*\))?:$", line ).group( 1 ) + for docStringLine in self.formatDocstring( " ", self.getClassDocstring( className ) ): + yield docStringLine + if line.startswith( " def" ): + if nextDefIsStaticMethod or nextDefIsClassMethod: + pass + else: + memberName = re.match( "^ def (.*?)\( self.* \):$", line ).group( 1 ) + for docStringLine in self.formatDocstring( " ", self.getMemberDocstring( className, memberName ) ): + yield docStringLine + + nextDefIsStaticMethod = line == " @staticmethod" + nextDefIsClassMethod = line == " @classmethod" + + def formatDocstring( self, indent, lines ): + if len( lines ) != 0: + yield indent + '"""' + for docStringLine in lines: + yield indent + docStringLine + yield indent + '"""' + yield "" + + def readLines( self, fileName ): + with open( fileName ) as f: + return list( line.rstrip() for line in f ) + + def writeLines( self, fileName, lines ): + with open( fileName, "wb" ) as f: + for line in lines: + f.write( line + "\n" ) + +if __name__ == "__main__": + Generator().run() diff --git a/github/Github.py b/github/Github.py index fa8b63e7..88b79fee 100644 --- a/github/Github.py +++ b/github/Github.py @@ -28,7 +28,7 @@ DEFAULT_BASE_URL = "https://api.github.com" DEFAULT_TIMEOUT = 10 class Github( object ): - def __init__( self, login_or_token = None, password = None, base_url = DEFAULT_BASE_URL, timeout = DEFAULT_TIMEOUT): + def __init__( self, login_or_token = None, password = None, base_url = DEFAULT_BASE_URL, timeout = DEFAULT_TIMEOUT ): self.__requester = Requester( login_or_token, password, base_url, timeout ) @property diff --git a/github/GithubObject.py b/github/GithubObject.py index 10d2f789..8622bc8e 100644 --- a/github/GithubObject.py +++ b/github/GithubObject.py @@ -20,7 +20,7 @@ class _NotSetType: NotSet = _NotSetType() class BasicGithubObject( object ): - def __init__( self, requester, attributes, completed ): ### 'completed' may be removed if I find a way + def __init__( self, requester, attributes ): self._requester = requester self._initAttributes() self._useAttributes( attributes )