def __init__(self, directive: DocumenterBridge, name: str, indent: str = '') -> None: super().__init__(directive=directive, name=name, indent=indent) self.options = Options(self.options.copy()) self._datadescriptor = True
def __init__(self, directive: DocumenterBridge, name: str, indent: str = '') -> None: super().__init__(directive=directive, name=name, indent=indent) self.options = Options(self.options.copy()) add_nbsp_substitution(self.env.app.config)
def run(self): """Add a MarkdownNode when this directive is loaded """ env = self.state.document.settings.env node = MarkdownNode() options = Options(self.options) node.filename = options.get('filename') node.extensions = env.config.markdown_extensions node.load_markdown() return [node]
def __init__(self, *args: Any) -> None: super().__init__(*args) self.options = Options(self.options.copy()) alphabetical = self.options.get("alphabetical", False) if alphabetical: self.options["member-order"] = "alphabetical" else: self.options["member-order"] = "bysource" for key in {"inherited-members", "special-members"}: # pragma: no cover if key in self.options: del self.options[key]
def setup_test(): global options, directive global processed_docstrings, processed_signatures options = Options( inherited_members=False, undoc_members=False, private_members=False, special_members=False, imported_members=False, show_inheritance=False, noindex=False, annotation=None, synopsis='', platform='', deprecated=False, members=[], member_order='alphabetic', exclude_members=set(), ) directive = Struct( env=app.builder.env, genopt=options, result=ViewList(), filename_set=set(), ) processed_docstrings = [] processed_signatures = []
def run(self): # type: () -> List[nodes.Node] self.env = env = self.state.document.settings.env self.genopt = Options() self.warnings = [] # type: List[nodes.Node] self.result = ViewList() names = [x.strip().split()[0] for x in self.content if x.strip() and re.search(r'^[~a-zA-Z_]', x.strip()[0])] items = self.get_items(names) nodes = self.get_table(items) if 'toctree' in self.options: dirname = posixpath.dirname(env.docname) tree_prefix = self.options['toctree'].strip() docnames = [] for name, sig, summary, real_name in items: docname = posixpath.join(tree_prefix, real_name) docname = posixpath.normpath(posixpath.join(dirname, docname)) if docname not in env.found_docs: self.warn('toctree references unknown document %r' % docname) docnames.append(docname) tocnode = addnodes.toctree() tocnode['includefiles'] = docnames tocnode['entries'] = [(None, docn) for docn in docnames] tocnode['maxdepth'] = -1 tocnode['glob'] = None tocnode = autosummary_toc('', '', tocnode) nodes.append(tocnode) return self.warnings + nodes
def process_documenter_options(documenter: Type[Documenter], config: Config, options: Dict) -> Options: """Recognize options of Documenter from user input.""" for name in AUTODOC_DEFAULT_OPTIONS: if name not in documenter.option_spec: continue else: negated = options.pop('no-' + name, True) is None if name in config.autodoc_default_options and not negated: if name in options and isinstance( config.autodoc_default_options[name], str): # take value from options if present or extend it # with autodoc_default_options if necessary if name in AUTODOC_EXTENDABLE_OPTIONS: if options[name] is not None and options[ name].startswith('+'): options[name] = ','.join([ config.autodoc_default_options[name], options[name][1:] ]) else: options[name] = config.autodoc_default_options[name] elif options.get(name) is not None: # remove '+' from option argument if there's nothing to merge it with options[name] = options[name].lstrip('+') return Options( assemble_option_dict(options.items(), documenter.option_spec))
def generate_func_autodoc(app, func, add_title=True): ad = AutoDirective( name="autofunc", arguments=[FULL_NAMES[func]], options={"noindex": True}, content=StringList([], items=[]), lineno=0, content_offset=1, block_text="", state=None, state_machine=None, ) ad.env = BuildEnvironment(app) ad.genopt = Options(noindex=True) ad.filename_set = set() ad.result = ViewList() documenter = FunctionDocumenter(ad, ad.arguments[0]) documenter.generate(all_members=True) title = 'Parameter Grids' with open(OUTPUT_FILES[func], "a") as fid: if add_title: fid.write(title + '\n') fid.write(''.join(['='] * len(title)) + '\n') for line in ad.result: fid.write(line + "\n")
def process_documenter_options( documenter: Type[Documenter], config: Config, options: Dict, ) -> Options: """ Recognize options of Documenter from user input. :param documenter: :param config: :param options: """ for name in sphinx.ext.autodoc.directive.AUTODOC_DEFAULT_OPTIONS: if name not in documenter.option_spec: # pragma: no cover continue else: negated = options.pop("no-" + name, True) is None if name in config.autodoc_default_options and not negated: default_value = config.autodoc_default_options[name] existing_value = options.get(name, None) values: List[str] = [ v for v in [default_value, existing_value] if v not in {None, True, False} ] if values: options[name] = ','.join(values) else: options[name] = None # pragma: no cover return Options( assemble_option_dict(options.items(), documenter.option_spec))
def generate_class_autodoc(app, cls): ad = AutoDirective( name="autoclass", arguments=[FULL_NAMES[cls]], options={"noindex": True}, content=StringList([], items=[]), lineno=0, content_offset=1, block_text="", state=None, state_machine=None, ) ad.env = BuildEnvironment(app) ad.genopt = Options(noindex=True) ad.filename_set = set() ad.result = ViewList() documenter = ClassDocumenter(ad, ad.arguments[0]) documenter.generate(all_members=True) with open(OUTPUT_FILES[cls], "w") as fid: fid.write(cls + '\n') fid.write(''.join(['='] * len(cls)) + '\n') for line in ad.result: fid.write(line + "\n")
def create_directive(self): """ Helper function to create a a "directive" suitable for instantiating the TraitDocumenter with, along with resources to support that directive, and clean up the resources afterwards. Returns ------- contextmanager A context manager that returns a DocumenterBridge instance. """ with self.tmpdir() as tmpdir: # Ensure configuration file exists. conf_file = os.path.join(tmpdir, "conf.py") with open(conf_file, "w", encoding="utf-8") as f: f.write(CONF_PY) app = SphinxTestApp(srcdir=path(tmpdir)) app.builder.env.app = app app.builder.env.temp_data["docname"] = "dummy" kwds = {} state = mock.Mock() state.document.settings.tab_width = 8 kwds["state"] = state yield DocumenterBridge( app.env, LoggingReporter(''), Options(), 1, **kwds)
def __init__(self, *args, **kwargs): super(NoDataAttributeDocumenter, self).__init__(*args, **kwargs) fullname = '.'.join(self.name.rsplit('::', 1)) if hasattr(self.env, 'config') and dont_document_data( self.env.config, fullname): self.options = Options(self.options) self.options.annotation = ' '
def create_directive(self): """ Helper function to create a a "directive" suitable for instantiating the TraitDocumenter with, along with resources to support that directive, and clean up the resources afterwards. Returns ------- contextmanager A context manager that returns a DocumenterBridge instance. """ with self.tmpdir() as tmpdir: # Ensure configuration file exists. conf_file = os.path.join(tmpdir, "conf.py") with open(conf_file, "w", encoding="utf-8") as f: f.write(CONF_PY) app = SphinxTestApp(srcdir=path(tmpdir)) app.builder.env.app = app app.builder.env.temp_data["docname"] = "dummy" # Backwards compatibility hack: for now, we need to be compatible # with both Sphinx < 2.1 (whose DocumenterBridge doesn't take # a state argument) and Sphinx >= 2.3 (which warns if the state # isn't passed). Eventually we should be able to drop support # for Sphinx < 2.1. kwds = {} if sphinx.version_info >= (2, 1): state = mock.Mock() state.document.settings.tab_width = 8 kwds["state"] = state yield DocumenterBridge( app.env, LoggingReporter(''), Options(), 1, **kwds)
class FixtureDocumenter(FunctionDocumenter): """ Sphinx autodoc :class:`~sphinx.ext.autodoc.Documenter` for documenting pytest fixtures. """ objtype = "fixture" directivetype = "fixture" priority = 20 object: Union[FunctionType, MethodType] # noqa: A003 # pylint: disable=redefined-builtin def __init__(self, directive: DocumenterBridge, name: str, indent: str = '') -> None: super().__init__(directive, name, indent) self.options = Options(self.options.copy()) @classmethod def can_document_member( cls, member: Any, membername: str, isattr: bool, parent: Any, ) -> bool: """ Called to see if a member can be documented by this documenter. :param member: The member being checked. :param membername: The name of the member. :param isattr: :param parent: The parent of the member. """ if isinstance(member, FunctionType): return is_fixture(member)[0] else: # pragma: no cover return False def add_directive_header(self, sig: str = '') -> None: """ Add the directive's header. :param sig: Unused -- fixtures have no useful signature. :no-default sig: """ # doc_lines = (self.object.__doc__ or '').splitlines() # docstring = StringList([dedent(doc_lines[0]) + dedent("\n".join(doc_lines))[1:]]) # print(docstring) # input(">>>") super().add_directive_header('') self.add_line('', self.get_sourcename()) self.add_line( f" **Scope:** |nbsp| |nbsp| |nbsp| |nbsp| {is_fixture(self.object)[1]}", self.get_sourcename(), )
def add_directive_header(self, sig: str) -> None: """ Add the directive header and options to the generated content. """ self.options = Options(self.options) self.options["annotation"] = SUPPRESS super().add_directive_header(sig)
def process_documenter_options(documenter: "Type[Documenter]", config: Config, options: Dict ) -> Options: """Recognize options of Documenter from user input.""" for name in AUTODOC_DEFAULT_OPTIONS: if name not in documenter.option_spec: continue else: negated = options.pop('no-' + name, True) is None if name in config.autodoc_default_options and not negated: options[name] = config.autodoc_default_options[name] return Options(assemble_option_dict(options.items(), documenter.option_spec))
def import_object(self): # MethodDocumenter overrides import_object to do some sniffing in # addition to just importing. But we do our own sniffing and just want # the import, so we un-override it. ret = ClassLevelDocumenter.import_object(self) # Use 'inspect.getattr_static' to properly detect class or static methods. # This also resolves the MRO entries for subclasses. obj = inspect.getattr_static(self.parent, self.object_name) # autodoc likes to re-use dicts here for some reason (!?!) self.options = Options(self.options) update_with_sniffed_options(obj, self.options) # Replicate the special ordering hacks in # MethodDocumenter.import_object if "classmethod" in self.options or "staticmethod" in self.options: self.member_order -= 1 return ret
def run(self) -> List[Node]: self.bridge = DocumenterBridge(self.env, self.state.document.reporter, Options(), self.lineno, self.state) names = [ x.strip() for x in self.content if x.strip() and re.search(r'^[~a-zA-Z_]', x.strip()[0]) ] items = self.get_items(names) nodes = self.get_table(items) if "caption" in self.options: logger.warning(__( "A captioned autosummary requires :toctree: option. ignored."), location=nodes[-1]) return nodes
def create_directive(self): """ Helper function to create a a "directive" suitable for instantiating the TraitDocumenter with, along with resources to support that directive, and clean up the resources afterwards. Returns ------- contextmanager A context manager that returns a DocumenterBridge instance. """ with self.tmpdir() as tmpdir: # The configuration file must exist, but it's okay if it's empty. conf_file = os.path.join(tmpdir, "conf.py") with io.open(conf_file, "w", encoding="utf-8"): pass app = SphinxTestApp(srcdir=path(tmpdir)) app.builder.env.app = app app.builder.env.temp_data["docname"] = "dummy" yield DocumenterBridge(app.env, LoggingReporter(''), Options(), 1)
def setup_test(): global options, directive global processed_signatures options = Options( inherited_members=False, undoc_members=False, private_members=False, special_members=False, imported_members=False, show_inheritance=False, noindex=False, annotation=None, synopsis='', platform='', deprecated=False, members=[], member_order='alphabetic', exclude_members=set(), ignore_module_all=False, ) directive = Struct( env=app.builder.env, genopt=options, result=ViewList(), filename_set=set(), state=Mock(), ) directive.state.document.settings.tab_width = 8 processed_signatures = [] app._status.truncate(0) app._warning.truncate(0) yield app.registry.autodoc_attrgettrs.clear()
def generate_func_autodoc(app, func): ad = AutoDirective(name='autofunc', arguments=[FULL_NAMES[func]], options={'noindex': True}, content=StringList([], items=[]), lineno=0, content_offset=1, block_text='', state=None, state_machine=None) ad.env = BuildEnvironment(app) ad.genopt = Options(noindex=True) ad.filename_set = set() ad.result = ViewList() documenter = FunctionDocumenter(ad, ad.arguments[0]) documenter.generate(all_members=True) with open(OUTPUT_FILES[func], 'a') as fid: for line in ad.result: fid.write(line + '\n')
def import_object(self): # MethodDocumenter overrides import_object to do some sniffing in # addition to just importing. But we do our own sniffing and just want # the import, so we un-override it. ret = ClassLevelDocumenter.import_object(self) # If you have a classmethod or staticmethod, then # # Class.__dict__["name"] # # returns the classmethod/staticmethod object, but # # getattr(Class, "name") # # returns a regular function. We want to detect # classmethod/staticmethod, so we need to go through __dict__. obj = self.parent.__dict__.get(self.object_name) # autodoc likes to re-use dicts here for some reason (!?!) self.options = Options(self.options) update_with_sniffed_options(obj, self.options) # Replicate the special ordering hacks in # MethodDocumenter.import_object if "classmethod" in self.options or "staticmethod" in self.options: self.member_order -= 1 return ret
def __init__(self, directive: DocumenterBridge, name: str, indent: str = '') -> None: super().__init__(directive, name, indent) self.options = Options(self.options.copy())
class TypedDictDocumenter(ClassDocumenter): r""" Sphinx autodoc :class:`~sphinx.ext.autodoc.Documenter` for documenting :class:`typing.TypedDict`\s. """ # noqa: D400 objtype = "typeddict" directivetype = "typeddict" priority = 20 option_spec: Dict[str, Callable] = { "noindex": flag, "alphabetical": flag, "show-inheritance": flag, } def __init__(self, *args: Any) -> None: super().__init__(*args) self.options = Options(self.options.copy()) alphabetical = self.options.get("alphabetical", False) if alphabetical: self.options["member-order"] = "alphabetical" else: self.options["member-order"] = "bysource" for key in {"inherited-members", "special-members"}: # pragma: no cover if key in self.options: del self.options[key] @classmethod def can_document_member( cls, member: Any, membername: str, isattr: bool, parent: Any, ) -> bool: """ Called to see if a member can be documented by this documenter. :param member: The member being checked. :param membername: The name of the member. :param isattr: :param parent: The parent of the member. """ for attr in {"__optional_keys__", "__required_keys__", "__total__"}: if not hasattr(member, attr): return False return True def format_signature(self, **kwargs: Any) -> str: """ Typed Dicts do not have a signature. """ return '' def add_content(self, more_content: Any, no_docstring: bool = False): """ Add the autodocumenter content. :param more_content: :param no_docstring: """ if self.doc_as_attr: # pragma: no cover (verbatim from Sphinx) classname = safe_getattr(self.object, "__qualname__", None) if not classname: classname = safe_getattr(self.object, "__name__", None) if classname: module = safe_getattr(self.object, "__module__", None) parentmodule = safe_getattr(self.parent, "__module__", None) if module and module != parentmodule: classname = str(module) + '.' + str(classname) more_content = docutils.statemachine.StringList( [_("alias of :class:`%s`") % classname], source='') no_docstring = True # set sourcename and add content from attribute documentation sourcename = self.get_sourcename() if self.analyzer: attr_docs = self.analyzer.find_attr_docs() if self.objpath: key = ('.'.join(self.objpath[:-1]), self.objpath[-1]) if key in attr_docs: no_docstring = True # make a copy of docstring for attributes to avoid cache # the change of autodoc-process-docstring event. docstrings = [list(attr_docs[key])] for i, line in enumerate(self.process_doc(docstrings)): self.add_line(line, sourcename, i) # add content from docstrings if not no_docstring: docstrings = self.get_doc() or [] if not docstrings: # append at least a dummy docstring, so that the event # autodoc-process-docstring is fired and can add some # content if desired docstrings.append([":class:`typing.TypedDict`.", '']) for i, line in enumerate(self.process_doc(docstrings)): self.add_line(line, sourcename, i) # add additional content (e.g. from document), if present if more_content: # pragma: no cover (verbatim from Sphinx) for line, src in zip(more_content.data, more_content.items): self.add_line(line, src[0], src[1]) def document_members(self, all_members: bool = False) -> None: """ Generate reST for member documentation. All members are always documented. """ super().document_members(True) def sort_members( self, documenters: List[Tuple[Documenter, bool]], order: str, ) -> List[Tuple[Documenter, bool]]: """ Sort the TypedDict's members. :param documenters: :param order: """ # The documenters for the keys, in the desired order documenters = super().sort_members(documenters, order) # Mapping of key names to docstrings (as list of strings) docstrings = { k[1]: v for k, v in ModuleAnalyzer.for_module( self.object.__module__).find_attr_docs().items() } required_keys = [] optional_keys = [] types = get_type_hints(self.object) for d in documenters: name = d[0].name.split('.')[-1] if name in self.object.__required_keys__: required_keys.append(name) elif name in self.object.__optional_keys__: optional_keys.append(name) # else: warn user. This shouldn't ever happen, though. sourcename = self.get_sourcename() if required_keys: self.add_line('', sourcename) self.add_line(":Required Keys:", sourcename) self.document_keys(required_keys, types, docstrings) self.add_line('', sourcename) if optional_keys: self.add_line('', sourcename) self.add_line(":Optional Keys:", sourcename) self.document_keys(optional_keys, types, docstrings) self.add_line('', sourcename) return [] def document_keys(self, keys: List[str], types: Dict[str, Type], docstrings: Dict[str, List[str]]): """ Document keys in a :class:`typing.TypedDict`. :param keys: List of key names to document. :param types: Mapping of key names to types. :param docstrings: Mapping of key names to docstrings. """ content = StringList() for key in keys: if key in types: key_type = f"({format_annotation(types[key])}) " else: key_type = '' if key in docstrings: content.append( f" * **{key}** {key_type}-- {' '.join(docstrings.get(key, ''))}" ) else: content.append(f" * **{key}** {key_type}") for line in content: self.add_line(line, self.get_sourcename()) def filter_members( self, members: ObjectMembers, want_all: bool, ) -> List[Tuple[str, Any, bool]]: """ Filter the given member list. :param members: :param want_all: """ ret = [] # process members and determine which to skip for (membername, member) in members: # if isattr is True, the member is documented as an attribute if safe_getattr(member, "__sphinx_mock__", False): # mocked module or object keep = False elif membername.startswith('_'): keep = False else: keep = True # give the user a chance to decide whether this member # should be skipped if self.env.app: # let extensions preprocess docstrings try: skip_user = self.env.app.emit_firstresult( "autodoc-skip-member", self.objtype, membername, member, not keep, self.options, ) if skip_user is not None: keep = not skip_user except Exception as exc: filter_members_warning(member, exc) keep = False if keep: ret.append((membername, member, member is INSTANCEATTR)) return ret
def import_object(self): ret = super().import_object() # autodoc likes to re-use dicts here for some reason (!?!) self.options = Options(self.options) update_with_sniffed_options(self.object, self.options) return ret
class TypedAttributeDocumenter(DocstringStripSignatureMixin, ClassLevelDocumenter): """ Alternative version of :class:`sphinx.ext.autodoc.AttributeDocumenter` with better type hint rendering. Specialized Documenter subclass for attributes. .. versionadded:: 0.7.0 .. versionchanged:: 1.0.0 Now uses the type of the variable if it is not explicitly annotated. """ # noqa: D400 objtype = "attribute" member_order = 60 option_spec = dict(ModuleLevelDocumenter.option_spec) option_spec["annotation"] = annotation_option # must be higher than the MethodDocumenter, else it will recognize # some non-data descriptors as methods priority = 10 def __init__(self, directive: DocumenterBridge, name: str, indent: str = '') -> None: super().__init__(directive=directive, name=name, indent=indent) self.options = Options(self.options.copy()) self._datadescriptor = True @staticmethod def is_function_or_method(obj: Any) -> bool: # noqa: D102 return inspect.isfunction(obj) or inspect.isbuiltin( obj) or inspect.ismethod(obj) @classmethod def can_document_member(cls, member: Any, membername: str, isattr: bool, parent: Any) -> bool: """ Called to see if a member can be documented by this documenter. """ if inspect.isattributedescriptor(member): return True elif (not isinstance(parent, ModuleDocumenter) and not inspect.isroutine(member) and not isinstance(member, type)): return True else: return False def document_members(self, all_members: bool = False) -> None: # noqa: D102 pass def isinstanceattribute(self) -> bool: """ Check the subject is an instance attribute. """ try: analyzer = ModuleAnalyzer.for_module(self.modname) attr_docs = analyzer.find_attr_docs() if self.objpath: key = ('.'.join(self.objpath[:-1]), self.objpath[-1]) if key in attr_docs: return True return False except PycodeError: return False def import_object(self, raiseerror: bool = False) -> bool: """ Import the object given by *self.modname* and *self.objpath* and set it as ``self.object``. :returns: :py:obj:`True` if successful, :py:obj:`False` if an error occurred. """ try: ret = super().import_object(raiseerror=True) if inspect.isenumattribute(self.object): self.object = self.object.value if inspect.isattributedescriptor(self.object): self._datadescriptor = True else: # if it's not a data descriptor self._datadescriptor = False except ImportError as exc: if self.isinstanceattribute(): self.object = INSTANCEATTR self._datadescriptor = False ret = True elif raiseerror: raise else: logger.warning(exc.args[0], type="autodoc", subtype="import_object") self.env.note_reread() ret = False return ret def get_real_modname(self) -> str: """ 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. """ return self.get_attr(self.parent or self.object, "__module__", None) or self.modname def add_directive_header(self, sig: str): """ Add the directive's header. :param sig: """ sourcename = self.get_sourcename() no_value = self.options.get("no-value", False) no_type = self.options.get("no-type", False) if not self.options.get("annotation", ''): ClassLevelDocumenter.add_directive_header(self, sig) # data descriptors do not have useful values if not no_value and not self._datadescriptor: if "value" in self.options: self.add_line(" :value: " + self.options["value"], sourcename) else: with suppress(ValueError): if self.object is not INSTANCEATTR: objrepr = object_description(self.object) self.add_line(" :value: " + objrepr, sourcename) self.add_line('', sourcename) if not no_type: if "type" in self.options: self.add_line(type_template % self.options["type"], sourcename) else: # obtain type annotation for this attribute the_type = get_variable_type(self) if not the_type.strip(): obj_type = type(self.object) if obj_type is object: return try: the_type = format_annotation(obj_type) except Exception: return line = type_template % the_type self.add_line(line, sourcename) else: super().add_directive_header(sig) def get_doc( # type: ignore self, encoding: Optional[str] = None, ignore: Optional[int] = None, ) -> List[List[str]]: """ Decode and return lines of the docstring(s) for the object. :param encoding: :param ignore: """ try: # Disable `autodoc_inherit_docstring` temporarily to avoid to obtain # a docstring from the value which descriptor returns unexpectedly. # ref: https://github.com/sphinx-doc/sphinx/issues/7805 orig = self.env.config.autodoc_inherit_docstrings self.env.config.autodoc_inherit_docstrings = False # type: ignore # Sphinx's signature is wrong wrt Optional if sphinx.version_info >= (4, 0): if encoding is not None: raise TypeError( "The 'encoding' argument to get_doc was removed in Sphinx 4" ) else: return super().get_doc(ignore=cast(int, ignore)) or [] else: return super().get_doc(cast(str, encoding), cast( int, ignore)) or [] # type: ignore finally: self.env.config.autodoc_inherit_docstrings = orig # type: ignore def add_content(self, more_content: Any, no_docstring: bool = False) -> None: """ Add content from docstrings, attribute documentation and user. """ with warnings.catch_warnings(): # TODO: work out what to do about this warnings.simplefilter("ignore", RemovedInSphinx50Warning) if not self._datadescriptor: # if it's not a data descriptor, its docstring is very probably the # wrong thing to display no_docstring = True super().add_content(more_content, no_docstring)
class VariableDocumenter(DataDocumenter): """ Specialized Documenter subclass for data items. """ directivetype = "data" objtype = "variable" priority: float = DataDocumenter.priority + 0.5 # type: ignore # keeps it below TypeVarDocumenter option_spec = { "no-value": flag, "no-type": flag, "type": str, "value": str, **DataDocumenter.option_spec, } def __init__(self, directive: DocumenterBridge, name: str, indent: str = '') -> None: super().__init__(directive=directive, name=name, indent=indent) self.options = Options(self.options.copy()) add_nbsp_substitution(self.env.app.config) def add_directive_header(self, sig: str): """ Add the directive's header. :param sig: """ sourcename = self.get_sourcename() no_value = self.options.get("no-value", False) no_type = self.options.get("no-type", False) if not self.options.get("annotation", ''): ModuleLevelDocumenter.add_directive_header(self, sig) if not no_value: if "value" in self.options: self.add_line(f" :value: {self.options['value']}", sourcename) else: with suppress(ValueError): if self.object is not UNINITIALIZED_ATTR: objrepr = object_description(self.object) self.add_line(f" :value: {objrepr}", sourcename) self.add_line('', sourcename) if not no_type: if "type" in self.options: the_type = self.options["type"] else: # obtain type annotation for this data the_type = get_variable_type(self) if not the_type.strip(): obj_type = type(self.object) if obj_type is object: return try: the_type = format_annotation(obj_type) except Exception: return line = type_template % the_type self.add_line(line, sourcename) else: super().add_directive_header(sig)
class FakeDirective: env = {} genopt = Options()
class FakeDirective(object): env = {} # type: Dict genopt = Options()
class TypedAttributeDocumenter(AttributeDocumenter): """ Alternative version of :class:`sphinx.ext.autodoc.AttributeDocumenter` with better type hint rendering. Specialized Documenter subclass for attributes. .. versionadded:: 0.7.0 .. versionchanged:: 1.0.0 Now uses the type of the variable if it is not explicitly annotated. """ # noqa D400 def __init__(self, directive: DocumenterBridge, name: str, indent: str = '') -> None: super().__init__(directive=directive, name=name, indent=indent) self.options = Options(self.options.copy()) self._datadescriptor = True def add_directive_header(self, sig: str): """ Add the directive's header. :param sig: """ sourcename = self.get_sourcename() no_value = self.options.get("no-value", False) no_type = self.options.get("no-type", False) if not self.options.get("annotation", ''): ClassLevelDocumenter.add_directive_header(self, sig) # data descriptors do not have useful values if not no_value and not self._datadescriptor: if "value" in self.options: self.add_line(" :value: " + self.options["value"], sourcename) else: try: if self.object is not INSTANCEATTR: objrepr = object_description(self.object) self.add_line(" :value: " + objrepr, sourcename) except ValueError: pass self.add_line('', sourcename) if not no_type: if "type" in self.options: self.add_line(type_template % self.options["type"], sourcename) else: # obtain type annotation for this attribute the_type = get_variable_type(self) if not the_type.strip(): try: the_type = format_annotation(type(self.object)) except Exception: return line = type_template % the_type self.add_line(line, sourcename) else: super().add_directive_header(sig)