# -*- coding: utf-8 -*-""" sphinx.ext.autodoc ~~~~~~~~~~~~~~~~~~ Automatically insert docstrings for functions, classes or whole modules into the doctree, thus avoiding duplication between docstrings and documentation for those who like elaborate docstrings. :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. :license: BSD, see LICENSE for details."""importreimportsysimportinspectimporttracebackfromtypesimportFunctionType,BuiltinFunctionType,MethodTypefromdocutilsimportnodesfromdocutils.utilsimportassemble_option_dictfromdocutils.statemachineimportViewListfromsphinx.utilimportrpartition,force_decodefromsphinx.localeimport_fromsphinx.pycodeimportModuleAnalyzer,PycodeErrorfromsphinx.applicationimportExtensionErrorfromsphinx.util.nodesimportnested_parse_with_titlesfromsphinx.util.compatimportDirectivefromsphinx.util.inspectimportgetargspec,isdescriptor,safe_getmembers, \
safe_getattr,safe_reprfromsphinx.util.pycompatimportbase_exception,class_typesfromsphinx.util.docstringsimportprepare_docstring#: extended signature RE: with explicit module name separated by ::py_ext_sig_re=re.compile(r'''^ ([\w.]+::)? # explicit module name ([\w.]+\.)? # module and/or class name(s) (\w+) \s* # thing name (?: \((.*)\) # optional: arguments (?:\s* -> \s* (.*))? # return annotation )? $ # and nothing more ''',re.VERBOSE)classDefDict(dict):"""A dict that returns a default on nonexisting keys."""def__init__(self,default):dict.__init__(self)self.default=defaultdef__getitem__(self,key):try:returndict.__getitem__(self,key)exceptKeyError:returnself.defaultdef__nonzero__(self):# docutils check "if option_spec"returnTrueidentity=lambdax:xclassOptions(dict):"""A dict/attribute hybrid that returns None on nonexisting keys."""def__getattr__(self,name):try:returnself[name.replace('_','-')]exceptKeyError:returnNoneALL=object()INSTANCEATTR=object()defmembers_option(arg):"""Used to convert the :members: option to auto directives."""ifargisNone:returnALLreturn[x.strip()forxinarg.split(',')]defmembers_set_option(arg):"""Used to convert the :members: option to auto directives."""ifargisNone:returnALLreturnset(x.strip()forxinarg.split(','))defbool_option(arg):"""Used to convert flag options to auto directives. (Instead of directives.flag(), which returns None). """returnTrueclassAutodocReporter(object):""" A reporter replacement that assigns the correct source name and line number to a system message, as recorded in a ViewList. """def__init__(self,viewlist,reporter):self.viewlist=viewlistself.reporter=reporterdef__getattr__(self,name):returngetattr(self.reporter,name)defsystem_message(self,level,message,*children,**kwargs):if'line'inkwargsand'source'notinkwargs:try:source,line=self.viewlist.items[kwargs['line']]exceptIndexError:passelse:kwargs['source']=sourcekwargs['line']=linereturnself.reporter.system_message(level,message,*children,**kwargs)defdebug(self,*args,**kwargs):ifself.reporter.debug_flag:returnself.system_message(0,*args,**kwargs)definfo(self,*args,**kwargs):returnself.system_message(1,*args,**kwargs)defwarning(self,*args,**kwargs):returnself.system_message(2,*args,**kwargs)deferror(self,*args,**kwargs):returnself.system_message(3,*args,**kwargs)defsevere(self,*args,**kwargs):returnself.system_message(4,*args,**kwargs)# Some useful event listener factories for autodoc-process-docstring.defcut_lines(pre,post=0,what=None):"""Return a listener that removes the first *pre* and last *post* lines of every docstring. If *what* is a sequence of strings, only docstrings of a type in *what* will be processed. Use like this (e.g. in the ``setup()`` function of :file:`conf.py`):: from sphinx.ext.autodoc import cut_lines app.connect('autodoc-process-docstring', cut_lines(4, what=['module'])) This can (and should) be used in place of :confval:`automodule_skip_lines`. """defprocess(app,what_,name,obj,options,lines):ifwhatandwhat_notinwhat:returndellines[:pre]ifpost:# remove one trailing blank line.iflinesandnotlines[-1]:lines.pop(-1)dellines[-post:]# make sure there is a blank line at the endiflinesandlines[-1]:lines.append('')returnprocessdefbetween(marker,what=None,keepempty=False,exclude=False):"""Return a listener that either keeps, or if *exclude* is True excludes, lines between lines that match the *marker* regular expression. If no line matches, the resulting docstring would be empty, so no change will be made unless *keepempty* is true. If *what* is a sequence of strings, only docstrings of a type in *what* will be processed. """marker_re=re.compile(marker)defprocess(app,what_,name,obj,options,lines):ifwhatandwhat_notinwhat:returndeleted=0delete=notexcludeorig_lines=lines[:]fori,lineinenumerate(orig_lines):ifdelete:lines.pop(i-deleted)deleted+=1ifmarker_re.match(line):delete=notdeleteifdelete:lines.pop(i-deleted)deleted+=1ifnotlinesandnotkeepempty:lines[:]=orig_lines# make sure there is a blank line at the endiflinesandlines[-1]:lines.append('')returnprocessclassDocumenter(object):""" A Documenter knows how to autodocument a single object type. When registered with the AutoDirective, it will be used to document objects of that type when needed by autodoc. Its *objtype* attribute selects what auto directive it is assigned to (the directive name is 'auto' + objtype), and what directive it generates by default, though that can be overridden by an attribute called *directivetype*. A Documenter has an *option_spec* that works like a docutils directive's; in fact, it will be used to parse an auto directive's options that matches the documenter. """#: name by which the directive is called (auto...) and the default#: generated directive nameobjtype='object'#: indentation by which to indent the directive contentcontent_indent=u' '#: priority if multiple documenters return True from can_document_memberpriority=0#: order if autodoc_member_order is set to 'groupwise'member_order=0#: true if the generated content may contain titlestitles_allowed=Falseoption_spec={'noindex':bool_option}@staticmethoddefget_attr(obj,name,*defargs):"""getattr() override for types such as Zope interfaces."""fortyp,funcinAutoDirective._special_attrgetters.iteritems():ifisinstance(obj,typ):returnfunc(obj,name,*defargs)returnsafe_getattr(obj,name,*defargs)@classmethoddefcan_document_member(cls,member,membername,isattr,parent):"""Called to see if a member can be documented by this documenter."""raiseNotImplementedError('must be implemented in subclasses')def__init__(self,directive,name,indent=u''):self.directive=directiveself.env=directive.envself.options=directive.genoptself.name=nameself.indent=indent# the module and object path within the module, and the fully# qualified name (all set after resolve_name succeeds)self.modname=Noneself.module=Noneself.objpath=Noneself.fullname=None# extra signature items (arguments and return annotation,# also set after resolve_name succeeds)self.args=Noneself.retann=None# the object to document (set after import_object succeeds)self.object=Noneself.object_name=None# the parent/owner of the object to documentself.parent=None# the module analyzer to get at attribute docs, or Noneself.analyzer=Nonedefadd_line(self,line,source,*lineno):"""Append one line of generated reST to the output."""self.directive.result.append(self.indent+line,source,*lineno)defresolve_name(self,modname,parents,path,base):"""Resolve the module and name of the object to document given by the arguments and the current module/class. Must return a pair of the module name and a chain of attributes; for example, it would return ``('zipfile', ['ZipFile', 'open'])`` for the ``zipfile.ZipFile.open`` method. """raiseNotImplementedError('must be implemented in subclasses')defparse_name(self):"""Determine what module to import and what attribute to document. Returns True and sets *self.modname*, *self.objpath*, *self.fullname*, *self.args* and *self.retann* if parsing and resolving was successful. """# first, parse the definition -- auto directives for classes and# functions can contain a signature which is then used instead of# an autogenerated onetry:explicit_modname,path,base,args,retann= \
py_ext_sig_re.match(self.name).groups()exceptAttributeError:self.directive.warn('invalid signature for auto%s (%r)'%(self.objtype,self.name))returnFalse# support explicit module and class name separation via ::ifexplicit_modnameisnotNone:modname=explicit_modname[:-2]parents=pathandpath.rstrip('.').split('.')or[]else:modname=Noneparents=[]self.modname,self.objpath= \
self.resolve_name(modname,parents,path,base)ifnotself.modname:returnFalseself.args=argsself.retann=retannself.fullname=(self.modnameor'')+ \
(self.objpathand'.'+'.'.join(self.objpath)or'')returnTruedefimport_object(self):"""Import the object given by *self.modname* and *self.objpath* and set it as *self.object*. Returns True if successful, False if an error occurred. """try:__import__(self.modname)parent=Noneobj=self.module=sys.modules[self.modname]forpartinself.objpath:parent=objobj=self.get_attr(obj,part)self.object_name=partself.parent=parentself.object=objreturnTrue# this used to only catch SyntaxError, ImportError and AttributeError,# but importing modules with side effects can raise all kinds of errorsexceptException,err:ifself.env.appandnotself.env.app.quiet:self.env.app.info(traceback.format_exc().rstrip())self.directive.warn('autodoc can\'t import/find %s%r, it reported error: ''"%s", please check your spelling and sys.path'%(self.objtype,str(self.fullname),err))self.env.note_reread()returnFalsedefget_real_modname(self):"""Get the real module name of an object to document. It can differ from the name of the module through which the object was imported. """returnself.get_attr(self.object,'__module__',None)orself.modnamedefcheck_module(self):"""Check if *self.object* is really defined in the module given by *self.modname*. """modname=self.get_attr(self.object,'__module__',None)ifmodnameandmodname!=self.modname:returnFalsereturnTruedefformat_args(self):"""Format the argument signature of *self.object*. Should return None if the object does not have a signature. """returnNonedefformat_name(self):"""Format the name of *self.object*. This normally should be something that can be parsed by the generated directive, but doesn't need to be (Sphinx will display it unparsed then). """# normally the name doesn't contain the module (except for module# directives of course)return'.'.join(self.objpath)orself.modnamedefformat_signature(self):"""Format the signature (arguments and return annotation) of the object. Let the user process it via the ``autodoc-process-signature`` event. """ifself.argsisnotNone:# signature given explicitlyargs="(%s)"%self.argselse:# try to introspect the signaturetry:args=self.format_args()exceptException,err:self.directive.warn('error while formatting arguments for ''%s: %s'%(self.fullname,err))args=Noneretann=self.retannresult=self.env.app.emit_firstresult('autodoc-process-signature',self.objtype,self.fullname,self.object,self.options,args,retann)ifresult:args,retann=resultifargsisnotNone:returnargs+(retannand(' -> %s'%retann)or'')else:return''defadd_directive_header(self,sig):"""Add the directive header and options to the generated content."""domain=getattr(self,'domain','py')directive=getattr(self,'directivetype',self.objtype)name=self.format_name()self.add_line(u'.. %s:%s:: %s%s'%(domain,directive,name,sig),'<autodoc>')ifself.options.noindex:self.add_line(u' :noindex:','<autodoc>')ifself.objpath:# Be explicit about the module, this is necessary since .. class::# etc. don't support a prepended module nameself.add_line(u' :module: %s'%self.modname,'<autodoc>')defget_doc(self,encoding=None,ignore=1):"""Decode and return lines of the docstring(s) for the object."""docstring=self.get_attr(self.object,'__doc__',None)# make sure we have Unicode docstrings, then sanitize and split# into linesifisinstance(docstring,unicode):return[prepare_docstring(docstring,ignore)]elifdocstring:return[prepare_docstring(force_decode(docstring,encoding),ignore)]return[]defprocess_doc(self,docstrings):"""Let the user process the docstrings before adding them."""fordocstringlinesindocstrings:ifself.env.app:# let extensions preprocess docstringsself.env.app.emit('autodoc-process-docstring',self.objtype,self.fullname,self.object,self.options,docstringlines)forlineindocstringlines:yieldlinedefadd_content(self,more_content,no_docstring=False):"""Add content from docstrings, attribute documentation and user."""# set sourcename and add content from attribute documentationifself.analyzer:# prevent encoding errors when the file name is non-ASCIIifnotisinstance(self.analyzer.srcname,unicode):filename=unicode(self.analyzer.srcname,sys.getfilesystemencoding(),'replace')else:filename=self.analyzer.srcnamesourcename=u'%s:docstring of %s'%(filename,self.fullname)attr_docs=self.analyzer.find_attr_docs()ifself.objpath:key=('.'.join(self.objpath[:-1]),self.objpath[-1])ifkeyinattr_docs:no_docstring=Truedocstrings=[attr_docs[key]]fori,lineinenumerate(self.process_doc(docstrings)):self.add_line(line,sourcename,i)else:sourcename=u'docstring of %s'%self.fullname# add content from docstringsifnotno_docstring:encoding=self.analyzerandself.analyzer.encodingdocstrings=self.get_doc(encoding)ifnotdocstrings:# append at least a dummy docstring, so that the event# autodoc-process-docstring is fired and can add some# content if desireddocstrings.append([])fori,lineinenumerate(self.process_doc(docstrings)):self.add_line(line,sourcename,i)# add additional content (e.g. from document), if presentifmore_content:forline,srcinzip(more_content.data,more_content.items):self.add_line(line,src[0],src[1])defget_object_members(self,want_all):"""Return `(members_check_module, members)` where `members` is a list of `(membername, member)` pairs of the members of *self.object*. If *want_all* is True, return all members. Else, only return those members given by *self.options.members* (which may also be none). """ifnotwant_all:ifnotself.options.members:returnFalse,[]# specific members givenret=[]formnameinself.options.members:try:ret.append((mname,self.get_attr(self.object,mname)))exceptAttributeError:self.directive.warn('missing attribute %s in object %s'%(mname,self.fullname))returnFalse,retifself.options.inherited_members:# safe_getmembers() uses dir() which pulls in members from all# base classesmembers=safe_getmembers(self.object)else:# __dict__ contains only the members directly defined in# the class (but get them via getattr anyway, to e.g. get# unbound method objects instead of function objects);# using keys() because apparently there are objects for which# __dict__ changes while getting attributestry:obj_dict=self.get_attr(self.object,'__dict__')exceptAttributeError:members=[]else:members=[(mname,self.get_attr(self.object,mname,None))formnameinobj_dict.keys()]membernames=set(m[0]forminmembers)# add instance attributes from the analyzerifself.analyzer:attr_docs=self.analyzer.find_attr_docs()namespace='.'.join(self.objpath)foriteminattr_docs.iteritems():ifitem[0][0]==namespace:ifitem[0][1]notinmembernames:members.append((item[0][1],INSTANCEATTR))returnFalse,sorted(members)deffilter_members(self,members,want_all):"""Filter the given member list. Members are skipped if - they are private (except if given explicitly or the private-members option is set) - they are special methods (except if given explicitly or the special-members option is set) - they are undocumented (except if the undoc-members option is set) The user can override the skipping decision by connecting to the ``autodoc-skip-member`` event. """ret=[]# search for members in source code toonamespace='.'.join(self.objpath)# will be empty for modulesifself.analyzer:attr_docs=self.analyzer.find_attr_docs()else:attr_docs={}# process members and determine which to skipfor(membername,member)inmembers:# if isattr is True, the member is documented as an attributeisattr=Falsedoc=self.get_attr(member,'__doc__',None)# if the member __doc__ is the same as self's __doc__, it's just# inherited and therefore not the member's doccls=self.get_attr(member,'__class__',None)ifcls:cls_doc=self.get_attr(cls,'__doc__',None)ifcls_doc==doc:doc=Nonehas_doc=bool(doc)keep=Falseifwant_allandmembername.startswith('__')and \
membername.endswith('__')andlen(membername)>4:# special __methods__ifself.options.special_membersisALLand \
membername!='__doc__':keep=has_docorself.options.undoc_memberselifself.options.special_membersand \
membernameinself.options.special_members:keep=has_docorself.options.undoc_memberselifwant_allandmembername.startswith('_'):# ignore members whose name starts with _ by defaultkeep=self.options.private_membersand \
(has_docorself.options.undoc_members)elif(namespace,membername)inattr_docs:# keep documented attributeskeep=Trueisattr=Trueelse:# ignore undocumented members if :undoc-members: is not givenkeep=has_docorself.options.undoc_members# give the user a chance to decide whether this member# should be skippedifself.env.app:# let extensions preprocess docstringsskip_user=self.env.app.emit_firstresult('autodoc-skip-member',self.objtype,membername,member,notkeep,self.options)ifskip_userisnotNone:keep=notskip_userifkeep:ret.append((membername,member,isattr))returnretdefdocument_members(self,all_members=False):"""Generate reST for member documentation. If *all_members* is True, do all members, else those given by *self.options.members*. """# set current namespace for finding membersself.env.temp_data['autodoc:module']=self.modnameifself.objpath:self.env.temp_data['autodoc:class']=self.objpath[0]want_all=all_membersorself.options.inherited_membersor \
self.options.membersisALL# find out which members are documentablemembers_check_module,members=self.get_object_members(want_all)# remove members given by exclude-membersifself.options.exclude_members:members=[(membername,member)for(membername,member)inmembersifmembernamenotinself.options.exclude_members]# document non-skipped membersmemberdocumenters=[]for(mname,member,isattr)inself.filter_members(members,want_all):classes=[clsforclsinAutoDirective._registry.itervalues()ifcls.can_document_member(member,mname,isattr,self)]ifnotclasses:# don't know how to document this membercontinue# prefer the documenter with the highest priorityclasses.sort(key=lambdacls:cls.priority)# give explicitly separated module name, so that members# of inner classes can be documentedfull_mname=self.modname+'::'+ \
'.'.join(self.objpath+[mname])documenter=classes[-1](self.directive,full_mname,self.indent)memberdocumenters.append((documenter,isattr))member_order=self.options.member_orderor \
self.env.config.autodoc_member_orderifmember_order=='groupwise':# sort by group; relies on stable sort to keep items in the# same group sorted alphabeticallymemberdocumenters.sort(key=lambdae:e[0].member_order)elifmember_order=='bysource'andself.analyzer:# sort by source order, by virtue of the module analyzertagorder=self.analyzer.tagorderdefkeyfunc(entry):fullname=entry[0].name.split('::')[1]returntagorder.get(fullname,len(tagorder))memberdocumenters.sort(key=keyfunc)fordocumenter,isattrinmemberdocumenters:documenter.generate(all_members=True,real_modname=self.real_modname,check_module=members_check_moduleandnotisattr)# reset current objectsself.env.temp_data['autodoc:module']=Noneself.env.temp_data['autodoc:class']=Nonedefgenerate(self,more_content=None,real_modname=None,check_module=False,all_members=False):"""Generate reST for the object given by *self.name*, and possibly for its members. If *more_content* is given, include that content. If *real_modname* is given, use that module name to find attribute docs. If *check_module* is True, only generate if the object is defined in the module name it is imported from. If *all_members* is True, document all members. """ifnotself.parse_name():# need a module to importself.directive.warn('don\'t know which module to import for autodocumenting ''%r (try placing a "module" or "currentmodule" directive ''in the document, or giving an explicit module name)'%self.name)return# now, import the module and get object to documentifnotself.import_object():return# If there is no real module defined, figure out which to use.# The real module is used in the module analyzer to look up the module# where the attribute documentation would actually be found in.# This is used for situations where you have a module that collects the# functions and classes of internal submodules.self.real_modname=real_modnameorself.get_real_modname()# try to also get a source code analyzer for attribute docstry:self.analyzer=ModuleAnalyzer.for_module(self.real_modname)# parse right now, to get PycodeErrors on parsing (results will# be cached anyway)self.analyzer.find_attr_docs()exceptPycodeError:# no source file -- e.g. for builtin and C modulesself.analyzer=None# at least add the module.__file__ as a dependencyifhasattr(self.module,'__file__')andself.module.__file__:self.directive.filename_set.add(self.module.__file__)else:self.directive.filename_set.add(self.analyzer.srcname)# check __module__ of object (for members not given explicitly)ifcheck_module:ifnotself.check_module():return# make sure that the result starts with an empty line. This is# necessary for some situations where another directive preprocesses# reST and no starting newline is presentself.add_line(u'','<autodoc>')# format the object's signature, if anysig=self.format_signature()# generate the directive header and options, if applicableself.add_directive_header(sig)self.add_line(u'','<autodoc>')# e.g. the module directive doesn't have contentself.indent+=self.content_indent# add all content (from docstrings, attribute docs etc.)self.add_content(more_content)# document members, if possibleself.document_members(all_members)classModuleDocumenter(Documenter):""" Specialized Documenter subclass for modules. """objtype='module'content_indent=u''titles_allowed=Trueoption_spec={'members':members_option,'undoc-members':bool_option,'noindex':bool_option,'inherited-members':bool_option,'show-inheritance':bool_option,'synopsis':identity,'platform':identity,'deprecated':bool_option,'member-order':identity,'exclude-members':members_set_option,'private-members':bool_option,'special-members':members_option,}@classmethoddefcan_document_member(cls,member,membername,isattr,parent):# don't document submodules automaticallyreturnFalsedefresolve_name(self,modname,parents,path,base):ifmodnameisnotNone:self.directive.warn('"::" in automodule name doesn\'t make sense')return(pathor'')+base,[]defparse_name(self):ret=Documenter.parse_name(self)ifself.argsorself.retann:self.directive.warn('signature arguments or return annotation ''given for automodule %s'%self.fullname)returnretdefadd_directive_header(self,sig):Documenter.add_directive_header(self,sig)# add some module-specific optionsifself.options.synopsis:self.add_line(u' :synopsis: '+self.options.synopsis,'<autodoc>')ifself.options.platform:self.add_line(u' :platform: '+self.options.platform,'<autodoc>')ifself.options.deprecated:self.add_line(u' :deprecated:','<autodoc>')defget_object_members(self,want_all):ifwant_all:ifnothasattr(self.object,'__all__'):# for implicit module members, check __module__ to avoid# documenting imported objectsreturnTrue,safe_getmembers(self.object)else:memberlist=self.object.__all__else:memberlist=self.options.membersor[]ret=[]formnameinmemberlist:try:ret.append((mname,safe_getattr(self.object,mname)))exceptAttributeError:self.directive.warn('missing attribute mentioned in :members: or __all__: ''module %s, attribute %s'%(safe_getattr(self.object,'__name__','???'),mname))returnFalse,retclassModuleLevelDocumenter(Documenter):""" Specialized Documenter subclass for objects on module level (functions, classes, data/constants). """defresolve_name(self,modname,parents,path,base):ifmodnameisNone:ifpath:modname=path.rstrip('.')else:# if documenting a toplevel object without explicit module,# it can be contained in another auto directive ...modname=self.env.temp_data.get('autodoc:module')# ... or in the scope of a module directiveifnotmodname:modname=self.env.temp_data.get('py:module')# ... else, it stays None, which means invalidreturnmodname,parents+[base]classClassLevelDocumenter(Documenter):""" Specialized Documenter subclass for objects on class level (methods, attributes). """defresolve_name(self,modname,parents,path,base):ifmodnameisNone:ifpath:mod_cls=path.rstrip('.')else:mod_cls=None# if documenting a class-level object without path,# there must be a current class, either from a parent# auto directive ...mod_cls=self.env.temp_data.get('autodoc:class')# ... or from a class directiveifmod_clsisNone:mod_cls=self.env.temp_data.get('py:class')# ... if still None, there's no way to knowifmod_clsisNone:returnNone,[]modname,cls=rpartition(mod_cls,'.')parents=[cls]# if the module name is still missing, get it like aboveifnotmodname:modname=self.env.temp_data.get('autodoc:module')ifnotmodname:modname=self.env.temp_data.get('py:module')# ... else, it stays None, which means invalidreturnmodname,parents+[base]classDocstringSignatureMixin(object):""" Mixin for FunctionDocumenter and MethodDocumenter to provide the feature of reading the signature from the docstring. """def_find_signature(self,encoding=None):docstrings=Documenter.get_doc(self,encoding)iflen(docstrings)!=1:returndoclines=docstrings[0]setattr(self,'__new_doclines',doclines)ifnotdoclines:return# match first line of docstring against signature REmatch=py_ext_sig_re.match(doclines[0])ifnotmatch:returnexmod,path,base,args,retann=match.groups()# the base name must match oursifnotself.objpathorbase!=self.objpath[-1]:return# re-prepare docstring to ignore indentation after signaturedocstrings=Documenter.get_doc(self,encoding,2)doclines=docstrings[0]# ok, now jump over remaining empty lines and set the remaining# lines as the new doclinesi=1whilei<len(doclines)andnotdoclines[i].strip():i+=1setattr(self,'__new_doclines',doclines[i:])returnargs,retanndefget_doc(self,encoding=None,ignore=1):lines=getattr(self,'__new_doclines',None)iflinesisnotNone:return[lines]returnDocumenter.get_doc(self,encoding,ignore)defformat_signature(self):ifself.argsisNoneandself.env.config.autodoc_docstring_signature:# only act if a signature is not explicitly given already, and if# the feature is enabledresult=self._find_signature()ifresultisnotNone:self.args,self.retann=resultreturnDocumenter.format_signature(self)classFunctionDocumenter(DocstringSignatureMixin,ModuleLevelDocumenter):""" Specialized Documenter subclass for functions. """objtype='function'member_order=30@classmethoddefcan_document_member(cls,member,membername,isattr,parent):returnisinstance(member,(FunctionType,BuiltinFunctionType))defformat_args(self):ifinspect.isbuiltin(self.object)or \
inspect.ismethoddescriptor(self.object):# cannot introspect arguments of a C function or methodreturnNonetry:argspec=getargspec(self.object)exceptTypeError:# if a class should be documented as function (yay duck# typing) we try to use the constructor signature as function# signature without the first argument.try:argspec=getargspec(self.object.__new__)exceptTypeError:argspec=getargspec(self.object.__init__)ifargspec[0]:delargspec[0][0]args=inspect.formatargspec(*argspec)# escape backslashes for reSTargs=args.replace('\\','\\\\')returnargsdefdocument_members(self,all_members=False):passclassClassDocumenter(ModuleLevelDocumenter):""" Specialized Documenter subclass for classes. """objtype='class'member_order=20option_spec={'members':members_option,'undoc-members':bool_option,'noindex':bool_option,'inherited-members':bool_option,'show-inheritance':bool_option,'member-order':identity,'exclude-members':members_set_option,'private-members':bool_option,'special-members':members_option,}@classmethoddefcan_document_member(cls,member,membername,isattr,parent):returnisinstance(member,class_types)defimport_object(self):ret=ModuleLevelDocumenter.import_object(self)# if the class is documented under another name, document it# as data/attributeifret:ifhasattr(self.object,'__name__'):self.doc_as_attr=(self.objpath[-1]!=self.object.__name__)else:self.doc_as_attr=Truereturnretdefformat_args(self):# for classes, the relevant signature is the __init__ method'sinitmeth=self.get_attr(self.object,'__init__',None)# classes without __init__ method, default __init__ or# __init__ written in C?ifinitmethisNoneorinitmethisobject.__init__ornot \
(inspect.ismethod(initmeth)orinspect.isfunction(initmeth)):returnNonetry:argspec=getargspec(initmeth)exceptTypeError:# still not possible: happens e.g. for old-style classes# with __init__ in CreturnNoneifargspec[0]andargspec[0][0]in('cls','self'):delargspec[0][0]returninspect.formatargspec(*argspec)defformat_signature(self):ifself.doc_as_attr:return''returnModuleLevelDocumenter.format_signature(self)defadd_directive_header(self,sig):ifself.doc_as_attr:self.directivetype='attribute'Documenter.add_directive_header(self,sig)# add inheritance info, if wantedifnotself.doc_as_attrandself.options.show_inheritance:self.add_line(u'','<autodoc>')iflen(self.object.__bases__):bases=[b.__module__=='__builtin__'andu':class:`%s`'%b.__name__oru':class:`%s.%s`'%(b.__module__,b.__name__)forbinself.object.__bases__]self.add_line(_(u' Bases: %s')%', '.join(bases),'<autodoc>')defget_doc(self,encoding=None,ignore=1):content=self.env.config.autoclass_contentdocstrings=[]attrdocstring=self.get_attr(self.object,'__doc__',None)ifattrdocstring:docstrings.append(attrdocstring)# for classes, what the "docstring" is can be controlled via a# config value; the default is only the class docstringifcontentin('both','init'):initdocstring=self.get_attr(self.get_attr(self.object,'__init__',None),'__doc__')# for new-style classes, no __init__ means default __init__ifinitdocstring==object.__init__.__doc__:initdocstring=Noneifinitdocstring:ifcontent=='init':docstrings=[initdocstring]else:docstrings.append(initdocstring)doc=[]fordocstringindocstrings:ifnotisinstance(docstring,unicode):docstring=force_decode(docstring,encoding)doc.append(prepare_docstring(docstring))returndocdefadd_content(self,more_content,no_docstring=False):ifself.doc_as_attr:classname=safe_getattr(self.object,'__name__',None)ifclassname:content=ViewList([_('alias of :class:`%s`')%classname],source='')ModuleLevelDocumenter.add_content(self,content,no_docstring=True)else:ModuleLevelDocumenter.add_content(self,more_content)defdocument_members(self,all_members=False):ifself.doc_as_attr:returnModuleLevelDocumenter.document_members(self,all_members)classExceptionDocumenter(ClassDocumenter):""" Specialized ClassDocumenter subclass for exceptions. """objtype='exception'member_order=10# needs a higher priority than ClassDocumenterpriority=10@classmethoddefcan_document_member(cls,member,membername,isattr,parent):returnisinstance(member,class_types)and \
issubclass(member,base_exception)classDataDocumenter(ModuleLevelDocumenter):""" Specialized Documenter subclass for data items. """objtype='data'member_order=40priority=-10@classmethoddefcan_document_member(cls,member,membername,isattr,parent):returnisinstance(parent,ModuleDocumenter)andisattrdefadd_directive_header(self,sig):ModuleLevelDocumenter.add_directive_header(self,sig)try:objrepr=safe_repr(self.object)exceptValueError:passelse:self.add_line(u' :annotation: = '+objrepr,'<autodoc>')defdocument_members(self,all_members=False):passclassMethodDocumenter(DocstringSignatureMixin,ClassLevelDocumenter):""" Specialized Documenter subclass for methods (normal, static and class). """objtype='method'member_order=50priority=1@classmethoddefcan_document_member(cls,member,membername,isattr,parent):returninspect.isroutine(member)and \
notisinstance(parent,ModuleDocumenter)ifsys.version_info>=(3,0):defimport_object(self):ret=ClassLevelDocumenter.import_object(self)obj_from_parent=self.parent.__dict__.get(self.object_name)ifisinstance(obj_from_parent,classmethod):self.directivetype='classmethod'self.member_order=self.member_order-1elifisinstance(obj_from_parent,staticmethod):self.directivetype='staticmethod'self.member_order=self.member_order-1else:self.directivetype='method'returnretelse:defimport_object(self):ret=ClassLevelDocumenter.import_object(self)ifisinstance(self.object,classmethod)or \
(isinstance(self.object,MethodType)andself.object.im_selfisnotNone):self.directivetype='classmethod'# document class and static members before ordinary onesself.member_order=self.member_order-1elifisinstance(self.object,FunctionType)or \
(isinstance(self.object,BuiltinFunctionType)andhasattr(self.object,'__self__')andself.object.__self__isnotNone):self.directivetype='staticmethod'# document class and static members before ordinary onesself.member_order=self.member_order-1else:self.directivetype='method'returnretdefformat_args(self):ifinspect.isbuiltin(self.object)or \
inspect.ismethoddescriptor(self.object):# can never get arguments of a C function or methodreturnNoneargspec=getargspec(self.object)ifargspec[0]andargspec[0][0]in('cls','self'):delargspec[0][0]returninspect.formatargspec(*argspec)defdocument_members(self,all_members=False):passclassAttributeDocumenter(ClassLevelDocumenter):""" Specialized Documenter subclass for attributes. """objtype='attribute'member_order=60# must be higher than the MethodDocumenter, else it will recognize# some non-data descriptors as methodspriority=10method_types=(FunctionType,BuiltinFunctionType,MethodType)@classmethoddefcan_document_member(cls,member,membername,isattr,parent):isdatadesc=isdescriptor(member)andnot \
isinstance(member,cls.method_types)andnot \
type(member).__name__=="method_descriptor"returnisdatadescor(notisinstance(parent,ModuleDocumenter)andnotinspect.isroutine(member)andnotisinstance(member,class_types))defdocument_members(self,all_members=False):passdefimport_object(self):ret=ClassLevelDocumenter.import_object(self)ifisdescriptor(self.object)and \
notisinstance(self.object,self.method_types):self._datadescriptor=Trueelse:# if it's not a data descriptorself._datadescriptor=Falsereturnretdefget_real_modname(self):returnself.get_attr(self.parentorself.object,'__module__',None) \
orself.modnamedefadd_directive_header(self,sig):ClassLevelDocumenter.add_directive_header(self,sig)ifnotself._datadescriptor:try:objrepr=safe_repr(self.object)exceptValueError:passelse:self.add_line(u' :annotation: = '+objrepr,'<autodoc>')defadd_content(self,more_content,no_docstring=False):ifnotself._datadescriptor:# if it's not a data descriptor, its docstring is very probably the# wrong thing to displayno_docstring=TrueClassLevelDocumenter.add_content(self,more_content,no_docstring)classInstanceAttributeDocumenter(AttributeDocumenter):""" Specialized Documenter subclass for attributes that cannot be imported because they are instance attributes (e.g. assigned in __init__). """objtype='instanceattribute'directivetype='attribute'member_order=60# must be higher than AttributeDocumenterpriority=11@classmethoddefcan_document_member(cls,member,membername,isattr,parent):"""This documents only INSTANCEATTR members."""returnisattrand(memberisINSTANCEATTR)defimport_object(self):"""Never import anything."""# disguise as an attributeself.objtype='attribute'self._datadescriptor=FalsereturnTruedefadd_content(self,more_content,no_docstring=False):"""Never try to get a docstring from the object."""AttributeDocumenter.add_content(self,more_content,no_docstring=True)classAutoDirective(Directive):""" The AutoDirective class is used for all autodoc directives. It dispatches most of the work to one of the Documenters, which it selects through its *_registry* dictionary. The *_special_attrgetters* attribute is used to customize ``getattr()`` calls that the Documenters make; its entries are of the form ``type: getattr_function``. Note: When importing an object, all items along the import chain are accessed using the descendant's *_special_attrgetters*, thus this dictionary should include all necessary functions for accessing attributes of the parents. """# a registry of objtype -> documenter class_registry={}# a registry of type -> getattr function_special_attrgetters={}# flags that can be given in autodoc_default_flags_default_flags=set(['members','undoc-members','inherited-members','show-inheritance','private-members','special-members',])# standard docutils directive settingshas_content=Truerequired_arguments=1optional_arguments=0final_argument_whitespace=True# allow any options to be passed; the options are parsed further# by the selected Documenteroption_spec=DefDict(identity)defwarn(self,msg):self.warnings.append(self.reporter.warning(msg,line=self.lineno))defrun(self):self.filename_set=set()# a set of dependent filenamesself.reporter=self.state.document.reporterself.env=self.state.document.settings.envself.warnings=[]self.result=ViewList()# find out what documenter to callobjtype=self.name[4:]doc_class=self._registry[objtype]# add default flagsforflaginself._default_flags:ifflagnotindoc_class.option_spec:continuenegated=self.options.pop('no-'+flag,'not given')isNoneifflaginself.env.config.autodoc_default_flagsand \
notnegated:self.options[flag]=None# process the options with the selected documenter's option_specself.genopt=Options(assemble_option_dict(self.options.items(),doc_class.option_spec))# generate the outputdocumenter=doc_class(self,self.arguments[0])documenter.generate(more_content=self.content)ifnotself.result:returnself.warnings# record all filenames as dependencies -- this will at least# partially make automatic invalidation possibleforfninself.filename_set:self.state.document.settings.record_dependencies.add(fn)# use a custom reporter that correctly assigns lines to source# filename/description and linenoold_reporter=self.state.memo.reporterself.state.memo.reporter=AutodocReporter(self.result,self.state.memo.reporter)ifdocumenter.titles_allowed:node=nodes.section()# necessary so that the child nodes get the right source/line setnode.document=self.state.documentnested_parse_with_titles(self.state,self.result,node)else:node=nodes.paragraph()node.document=self.state.documentself.state.nested_parse(self.result,0,node)self.state.memo.reporter=old_reporterreturnself.warnings+node.childrendefadd_documenter(cls):"""Register a new Documenter."""ifnotissubclass(cls,Documenter):raiseExtensionError('autodoc documenter %r must be a subclass ''of Documenter'%cls)# actually, it should be possible to override Documenters#if cls.objtype in AutoDirective._registry:# raise ExtensionError('autodoc documenter for %r is already '# 'registered' % cls.objtype)AutoDirective._registry[cls.objtype]=clsdefsetup(app):app.add_autodocumenter(ModuleDocumenter)app.add_autodocumenter(ClassDocumenter)app.add_autodocumenter(ExceptionDocumenter)app.add_autodocumenter(DataDocumenter)app.add_autodocumenter(FunctionDocumenter)app.add_autodocumenter(MethodDocumenter)app.add_autodocumenter(AttributeDocumenter)app.add_autodocumenter(InstanceAttributeDocumenter)app.add_config_value('autoclass_content','class',True)app.add_config_value('autodoc_member_order','alphabetic',True)app.add_config_value('autodoc_default_flags',[],True)app.add_config_value('autodoc_docstring_signature',True,True)app.add_event('autodoc-process-docstring')app.add_event('autodoc-process-signature')app.add_event('autodoc-skip-member')classtestcls:"""test doc string"""def__getattr__(self,x):returnxdef__setattr__(self,x,y):"""Attr setter."""