"""autodoc directive for sphinx."""from__future__importannotationsfromcontextlibimportcontextmanagerimporttypingastfromdocutilsimportnodesfromdocutils.parsers.rstimportdirectivesfromsphinx.environmentimportBuildEnvironmentfromsphinx.util.docutilsimportSphinxDirectivefromautodoc2.sphinx.utilsimport(get_all_analyser,get_database,load_config,nested_parse_generated,warn_sphinx,)fromautodoc2.utilsimportItemData,WarningSubtypestry:importtomllibexceptImportError:# python < 3.11importtomliastomllib# type: ignore
[docs]classAutodocObject(SphinxDirective):"""Directive to render a docstring of an object."""required_arguments=1# the full namefinal_argument_whitespace=Falsehas_content=True# TODO autogenerate this from the configoption_spec:t.ClassVar[dict[str,t.Any]]={"literal":directives.flag,# return the literal render string"literal-lexer":directives.unchanged,# the lexer to use for literal}
[docs]defrun(self)->list[nodes.Node]:source,line=self.get_source_info()# warnings take the docname and line numberwarning_loc=(self.env.docname,line)full_name=self.arguments[0]autodoc2_db=get_database(self.env)iffull_namenotinautodoc2_db:warn_sphinx(f"Could not find {full_name}",WarningSubtypes.NAME_NOT_FOUND,location=warning_loc,)return[]# find the parent class/modulemod_parent=Noneclass_parent=Noneforancestorinautodoc2_db.get_ancestors(full_name,include_self=True):ifancestorisNone:break# should never happenifclass_parentisNoneandancestor["type"]=="class":class_parent=ancestorifancestor["type"]in("module","package"):mod_parent=ancestorbreakifmod_parentisNone:warn_sphinx(f"Could not find parent module {full_name}",WarningSubtypes.NAME_NOT_FOUND,location=warning_loc,)return[]# ensure rebuilds when the source file changesfile_path=mod_parent.get("file_path")iffile_path:self.env.note_dependency(file_path)# load the configuration with overridesoverrides={}try:overrides=tomllib.loads("\n".join(self.content))ifself.contentelse{}exceptExceptionaserr:warn_sphinx(f"Could not parse TOML config: {err}",WarningSubtypes.CONFIG_ERROR,location=warning_loc,)config=load_config(self.env.app,overrides=overrides,location=warning_loc)# setup warningsdef_warn_render(msg:str,type_:WarningSubtypes)->None:warn_sphinx(msg,type_,location=warning_loc)# create the content from the renderercontent=list(config.render_plugin(autodoc2_db,config,all_resolver=get_all_analyser(self.env),warn=_warn_render,standalone=True,).render_item(full_name))if"literal"inself.options:literal=nodes.literal_block(text="\n".join(content))self.set_source_info(literal)if"literal-lexer"inself.options:literal["language"]=self.options["literal-lexer"]return[literal]with_set_parents(self.env,mod_parent,class_parent):base=nested_parse_generated(self.state,content,source,line,match_titles=True,# TODO)returnbase.childrenor[]
[docs]@contextmanagerdef_set_parents(env:BuildEnvironment,mod:ItemData,klass:ItemData|None)->t.Generator[None,None,None]:"""Ensure we setup the correct parent This allows sphinx to properly process the `py` directives. """current_module=env.ref_context.get("py:module")current_class=env.ref_context.get("py:class")env.ref_context["py:module"]=mod["full_name"]ifklass:env.ref_context["py:class"]=klass["full_name"]try:yieldfinally:env.ref_context["py:module"]=current_moduleenv.ref_context["py:class"]=current_class