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)
Example #3
0
 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]
Example #5
0
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 = []
Example #6
0
    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
Example #7
0
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))
Example #8
0
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))
Example #10
0
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)
Example #12
0
 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)
Example #14
0
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)
Example #16
0
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))
Example #17
0
 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)
Example #20
0
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()
Example #21
0
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')
Example #22
0
 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
Example #23
0
 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
Example #25
0
 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)
Example #28
0
class FakeDirective:
    env = {}
    genopt = Options()
Example #29
0
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)