Exemplo n.º 1
0
def test_signature_annotations_py38(app):
    from target.pep570 import foo, bar

    # case: separator in the middle
    sig = inspect.signature(foo)
    assert stringify_signature(sig) == '(a, b, /, c, d)'

    # case: separator at tail
    sig = inspect.signature(bar)
    assert stringify_signature(sig) == '(a, b, /)'
Exemplo n.º 2
0
def test_signature_partial():
    def fun(a, b, c=1, d=2):
        pass
    p = functools.partial(fun, 10, c=11)

    sig = inspect.signature(p)
    assert stringify_signature(sig) == '(b, *, c=11, d=2)'
Exemplo n.º 3
0
    def format_args(self, **kwargs) -> str:
        """Formats the arguments from the function object"""

        if self.config.autodoc_typehints in ("none", "description"):
            kwargs.setdefault("show_annotation", False)

        try:
            self.env.app.emit("autodoc-before-process-signature", self.object,
                              False)

            sig = self.object.get_signature(
                type_aliases=self.config.autodoc_type_aliases)

            args = stringify_signature(sig, **kwargs)

        except TypeError as exc:
            logger.warning(__("Failed to get a function signature for %s: %s"),
                           self.fullname, exc)
            return None

        except ValueError:
            args = ""

        if self.config.strip_signature_backslash:
            args = args.replace("\\", "\\\\")

        return args
Exemplo n.º 4
0
def test_signature_annotations_py38(app):
    from target.pep570 import bar, baz, foo, qux

    # case: separator at head
    sig = inspect.signature(foo)
    assert stringify_signature(sig) == '(*, a, b)'

    # case: separator in the middle
    sig = inspect.signature(bar)
    assert stringify_signature(sig) == '(a, b, /, c, d)'

    sig = inspect.signature(baz)
    assert stringify_signature(sig) == '(a, /, *, b)'

    # case: separator at tail
    sig = inspect.signature(qux)
    assert stringify_signature(sig) == '(a, b, /)'
Exemplo n.º 5
0
def process_signature(app, what: str, name: str, obj, options, signature,
                      return_annotation):
    if not callable(obj):
        return

    original_obj = obj
    if inspect.isclass(obj):
        obj = getattr(obj, '__init__', getattr(obj, '__new__', None))

    if not getattr(obj, '__annotations__', None):
        return

    obj = inspect.unwrap(obj)
    signature = Signature(obj)
    parameters = [
        param.replace(annotation=inspect.Parameter.empty)
        for param in signature.parameters.values()
    ]

    # The generated dataclass __init__() is weird and needs the second condition
    if '<locals>' in obj.__qualname__ and not (what == 'method'
                                               and name.endswith('.__init__')):
        logger.warning(
            'Cannot treat a function defined as a local function: "%s"  (use @functools.wraps)',
            name)
        return

    if parameters:
        if inspect.isclass(original_obj) or (what == 'method'
                                             and name.endswith('.__init__')):
            del parameters[0]
        elif what == 'method':
            outer = inspect.getmodule(obj)
            for clsname in obj.__qualname__.split('.')[:-1]:
                outer = getattr(outer, clsname)

            method_name = obj.__name__
            if method_name.startswith("__") and not method_name.endswith("__"):
                # If the method starts with double underscore (dunder)
                # Python applies mangling so we need to prepend the class name.
                # This doesn't happen if it always ends with double underscore.
                class_name = obj.__qualname__.split('.')[-2]
                method_name = "_{c}{m}".format(c=class_name, m=method_name)

            method_object = outer.__dict__[method_name] if outer else obj
            if not isinstance(method_object, (classmethod, staticmethod)):
                del parameters[0]

    signature = signature.replace(parameters=parameters,
                                  return_annotation=inspect.Signature.empty)

    return stringify_signature(signature).replace('\\', '\\\\'), None
Exemplo n.º 6
0
def test_signature():
    # literals
    with pytest.raises(TypeError):
        inspect.signature(1)

    with pytest.raises(TypeError):
        inspect.signature('')

    # builtins are supported on a case-by-case basis, depending on whether
    # they define __text_signature__
    if getattr(list, '__text_signature__', None):
        sig = inspect.stringify_signature(inspect.signature(list))
        assert sig == '(iterable=(), /)'
    else:
        with pytest.raises(ValueError):
            inspect.signature(list)

    # normal function
    def func(a, b, c=1, d=2, *e, **f):
        pass

    sig = inspect.stringify_signature(inspect.signature(func))
    assert sig == '(a, b, c=1, d=2, *e, **f)'
Exemplo n.º 7
0
def test_signature_partialmethod():
    from functools import partialmethod

    class Foo:
        def meth1(self, arg1, arg2, arg3=None, arg4=None):
            pass

        def meth2(self, arg1, arg2):
            pass

        foo = partialmethod(meth1, 1, 2)
        bar = partialmethod(meth1, 1, arg3=3)
        baz = partialmethod(meth2, 1, 2)

    subject = Foo()
    sig = inspect.signature(subject.foo)
    assert stringify_signature(sig) == '(arg3=None, arg4=None)'

    sig = inspect.signature(subject.bar)
    assert stringify_signature(sig) == '(arg2, *, arg3=3, arg4=None)'

    sig = inspect.signature(subject.baz)
    assert stringify_signature(sig) == '()'
Exemplo n.º 8
0
def test_signature_methods():
    class Foo:
        def meth1(self, arg1, **kwargs):
            pass

        @classmethod
        def meth2(cls, arg1, *args, **kwargs):
            pass

        @staticmethod
        def meth3(arg1, *args, **kwargs):
            pass

    @functools.wraps(Foo().meth1)
    def wrapped_bound_method(*args, **kwargs):
        pass

    # unbound method
    sig = inspect.signature(Foo.meth1)
    assert stringify_signature(sig) == '(self, arg1, **kwargs)'

    sig = inspect.signature(Foo.meth1, bound_method=True)
    assert stringify_signature(sig) == '(arg1, **kwargs)'

    # bound method
    sig = inspect.signature(Foo().meth1)
    assert stringify_signature(sig) == '(arg1, **kwargs)'

    # class method
    sig = inspect.signature(Foo.meth2)
    assert stringify_signature(sig) == '(arg1, *args, **kwargs)'

    sig = inspect.signature(Foo().meth2)
    assert stringify_signature(sig) == '(arg1, *args, **kwargs)'

    # static method
    sig = inspect.signature(Foo.meth3)
    assert stringify_signature(sig) == '(arg1, *args, **kwargs)'

    sig = inspect.signature(Foo().meth3)
    assert stringify_signature(sig) == '(arg1, *args, **kwargs)'

    # wrapped bound method
    sig = inspect.signature(wrapped_bound_method)
    assert stringify_signature(sig) == '(arg1, **kwargs)'
Exemplo n.º 9
0
def strip_annotations(app, what: str, name: str, obj, options, signature,
                      return_annotation):
    if what not in {'function', 'method', 'class'}:
        return

    original_signature = inspect.signature(obj)
    new_signature = original_signature.replace(
        return_annotation=inspect.Signature.empty,
        parameters=[
            param.replace(annotation=inspect.Parameter.empty)
            for param in original_signature.parameters.values()
            if param.name != 'self'
        ],
    )

    return stringify_signature(new_signature), None
Exemplo n.º 10
0
    def format_signature(self, **kwargs: Any) -> str:
        """
		Format the method's signature, including those for any overloaded implementations.

		:param kwargs:

		:return: The signature(s), as a multi-line string.
		"""

        sigs = []

        if self.analyzer and '.'.join(self.objpath) in self.analyzer.overloads:
            overloaded = True
        else:
            overloaded = False
            sig = super(autodoc.MethodDocumenter,
                        self).format_signature(**kwargs)
            sigs.append(sig)

        meth = self.parent.__dict__.get(self.objpath[-1])
        if inspect.is_singledispatch_method(meth):
            # append signature of singledispatch'ed functions
            for typ, func in meth.dispatcher.registry.items():
                if typ is object:
                    pass  # default implementation. skipped.
                else:
                    self.annotate_to_first_argument(func, typ)

                    documenter = MethodDocumenter(self.directive, '')
                    documenter.parent = self.parent
                    documenter.object = func
                    documenter.objpath = [None]  # type: ignore
                    sigs.append(documenter.format_signature())

        if overloaded:
            if self.env.config.overloads_location == "signature":
                for overload in self.analyzer.overloads.get('.'.join(
                        self.objpath)):  # type: ignore
                    sig = stringify_signature(
                        self.process_overload_signature(overload), **kwargs)
                    sigs.append(sig)

            sig = super(autodoc.MethodDocumenter,
                        self).format_signature(**kwargs)
            sigs.append(sig)

        return '\n'.join(sigs)
Exemplo n.º 11
0
def test_signature():
    # literals
    with pytest.raises(TypeError):
        inspect.signature(1)

    with pytest.raises(TypeError):
        inspect.signature('')

    # builitin classes
    with pytest.raises(TypeError):
        inspect.signature(int)

    with pytest.raises(TypeError):
        inspect.signature(str)

    # normal function
    def func(a, b, c=1, d=2, *e, **f):
        pass

    sig = inspect.stringify_signature(inspect.signature(func))
    assert sig == '(a, b, c=1, d=2, *e, **f)'
Exemplo n.º 12
0
def test_signature_annotations():
    from .typing_test_data import (Node, f0, f1, f2, f3, f4, f5, f6, f7, f8,
                                   f9, f10, f11, f12, f13, f14, f15, f16, f17,
                                   f18, f19, f20, f21)

    # Class annotations
    sig = inspect.signature(f0)
    assert stringify_signature(sig) == '(x: int, y: numbers.Integral) -> None'

    # Generic types with concrete parameters
    sig = inspect.signature(f1)
    assert stringify_signature(
        sig) == '(x: typing.List[int]) -> typing.List[int]'

    # TypeVars and generic types with TypeVars
    sig = inspect.signature(f2)
    if sys.version_info < (3, 7):
        assert stringify_signature(sig) == (
            '(x: typing.List[typing.T],'
            ' y: typing.List[typing.T_co],'
            ' z: typing.T'
            ') -> typing.List[typing.T_contra]')
    else:
        assert stringify_signature(sig) == (
            '(x: typing.List[tests.typing_test_data.T],'
            ' y: typing.List[tests.typing_test_data.T_co],'
            ' z: tests.typing_test_data.T'
            ') -> typing.List[tests.typing_test_data.T_contra]')

    # Union types
    sig = inspect.signature(f3)
    assert stringify_signature(
        sig) == '(x: typing.Union[str, numbers.Integral]) -> None'

    # Quoted annotations
    sig = inspect.signature(f4)
    assert stringify_signature(sig) == '(x: str, y: str) -> None'

    # Keyword-only arguments
    sig = inspect.signature(f5)
    assert stringify_signature(sig) == '(x: int, *, y: str, z: str) -> None'

    # Keyword-only arguments with varargs
    sig = inspect.signature(f6)
    assert stringify_signature(
        sig) == '(x: int, *args, y: str, z: str) -> None'

    # Space around '=' for defaults
    sig = inspect.signature(f7)
    if sys.version_info < (3, 11):
        assert stringify_signature(
            sig) == '(x: typing.Optional[int] = None, y: dict = {}) -> None'
    else:
        assert stringify_signature(
            sig) == '(x: int = None, y: dict = {}) -> None'

    # Callable types
    sig = inspect.signature(f8)
    assert stringify_signature(
        sig) == '(x: typing.Callable[[int, str], int]) -> None'

    sig = inspect.signature(f9)
    assert stringify_signature(sig) == '(x: typing.Callable) -> None'

    # Tuple types
    sig = inspect.signature(f10)
    assert stringify_signature(
        sig
    ) == '(x: typing.Tuple[int, str], y: typing.Tuple[int, ...]) -> None'

    # Instance annotations
    sig = inspect.signature(f11)
    assert stringify_signature(sig) == '(x: CustomAnnotation, y: 123) -> None'

    # tuple with more than two items
    sig = inspect.signature(f12)
    assert stringify_signature(sig) == '() -> typing.Tuple[int, str, int]'

    # optional
    sig = inspect.signature(f13)
    assert stringify_signature(sig) == '() -> typing.Optional[str]'

    # optional union
    sig = inspect.signature(f20)
    assert stringify_signature(sig) in (
        '() -> typing.Optional[typing.Union[int, str]]',
        '() -> typing.Optional[typing.Union[str, int]]')

    # Any
    sig = inspect.signature(f14)
    assert stringify_signature(sig) == '() -> typing.Any'

    # ForwardRef
    sig = inspect.signature(f15)
    assert stringify_signature(sig) == '(x: Unknown, y: int) -> typing.Any'

    # keyword only arguments (1)
    sig = inspect.signature(f16)
    assert stringify_signature(sig) == '(arg1, arg2, *, arg3=None, arg4=None)'

    # keyword only arguments (2)
    sig = inspect.signature(f17)
    assert stringify_signature(sig) == '(*, arg3, arg4)'

    sig = inspect.signature(f18)
    assert stringify_signature(sig) == (
        '(self, arg1: typing.Union[int, typing.Tuple] = 10) -> '
        'typing.List[typing.Dict]')

    # annotations for variadic and keyword parameters
    sig = inspect.signature(f19)
    assert stringify_signature(sig) == '(*args: int, **kwargs: str)'

    # default value is inspect.Signature.empty
    sig = inspect.signature(f21)
    assert stringify_signature(sig) == "(arg1='whatever', arg2)"

    # type hints by string
    sig = inspect.signature(Node.children)
    assert stringify_signature(
        sig) == '(self) -> typing.List[tests.typing_test_data.Node]'

    sig = inspect.signature(Node.__init__)
    assert stringify_signature(
        sig
    ) == '(self, parent: typing.Optional[tests.typing_test_data.Node]) -> None'

    # show_annotation is False
    sig = inspect.signature(f7)
    assert stringify_signature(sig, show_annotation=False) == '(x=None, y={})'

    # show_return_annotation is False
    sig = inspect.signature(f7)
    if sys.version_info < (3, 11):
        assert stringify_signature(
            sig, show_return_annotation=False
        ) == '(x: typing.Optional[int] = None, y: dict = {})'
    else:
        assert stringify_signature(
            sig,
            show_return_annotation=False) == '(x: int = None, y: dict = {})'

    # unqualified_typehints is True
    sig = inspect.signature(f7)
    if sys.version_info < (3, 11):
        assert stringify_signature(
            sig, unqualified_typehints=True
        ) == '(x: ~typing.Optional[int] = None, y: dict = {}) -> None'
    else:
        assert stringify_signature(sig, unqualified_typehints=True
                                   ) == '(x: int = None, y: dict = {}) -> None'
Exemplo n.º 13
0
def test_signature_annotations():
    from typing_test_data import (f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10,
                                  f11, f12, f13, f14, f15, f16, f17, f18, f19, Node)

    # Class annotations
    sig = inspect.signature(f0)
    assert stringify_signature(sig) == '(x: int, y: numbers.Integral) -> None'

    # Generic types with concrete parameters
    sig = inspect.signature(f1)
    assert stringify_signature(sig) == '(x: List[int]) -> List[int]'

    # TypeVars and generic types with TypeVars
    sig = inspect.signature(f2)
    assert stringify_signature(sig) == '(x: List[T], y: List[T_co], z: T) -> List[T_contra]'

    # Union types
    sig = inspect.signature(f3)
    assert stringify_signature(sig) == '(x: Union[str, numbers.Integral]) -> None'

    # Quoted annotations
    sig = inspect.signature(f4)
    assert stringify_signature(sig) == '(x: str, y: str) -> None'

    # Keyword-only arguments
    sig = inspect.signature(f5)
    assert stringify_signature(sig) == '(x: int, *, y: str, z: str) -> None'

    # Keyword-only arguments with varargs
    sig = inspect.signature(f6)
    assert stringify_signature(sig) == '(x: int, *args, y: str, z: str) -> None'

    # Space around '=' for defaults
    sig = inspect.signature(f7)
    assert stringify_signature(sig) == '(x: int = None, y: dict = {}) -> None'

    # Callable types
    sig = inspect.signature(f8)
    assert stringify_signature(sig) == '(x: Callable[[int, str], int]) -> None'

    sig = inspect.signature(f9)
    assert stringify_signature(sig) == '(x: Callable) -> None'

    # Tuple types
    sig = inspect.signature(f10)
    assert stringify_signature(sig) == '(x: Tuple[int, str], y: Tuple[int, ...]) -> None'

    # Instance annotations
    sig = inspect.signature(f11)
    assert stringify_signature(sig) == '(x: CustomAnnotation, y: 123) -> None'

    # tuple with more than two items
    sig = inspect.signature(f12)
    assert stringify_signature(sig) == '() -> Tuple[int, str, int]'

    # optional
    sig = inspect.signature(f13)
    assert stringify_signature(sig) == '() -> Optional[str]'

    # Any
    sig = inspect.signature(f14)
    assert stringify_signature(sig) == '() -> Any'

    # ForwardRef
    sig = inspect.signature(f15)
    assert stringify_signature(sig) == '(x: Unknown, y: int) -> Any'

    # keyword only arguments (1)
    sig = inspect.signature(f16)
    assert stringify_signature(sig) == '(arg1, arg2, *, arg3=None, arg4=None)'

    # keyword only arguments (2)
    sig = inspect.signature(f17)
    assert stringify_signature(sig) == '(*, arg3, arg4)'

    sig = inspect.signature(f18)
    assert stringify_signature(sig) == '(self, arg1: Union[int, Tuple] = 10) -> List[Dict]'

    # annotations for variadic and keyword parameters
    sig = inspect.signature(f19)
    assert stringify_signature(sig) == '(*args: int, **kwargs: str)'

    # type hints by string
    sig = inspect.signature(Node.children)
    if (3, 5, 0) <= sys.version_info < (3, 5, 3):
        assert stringify_signature(sig) == '(self) -> List[Node]'
    else:
        assert stringify_signature(sig) == '(self) -> List[typing_test_data.Node]'

    sig = inspect.signature(Node.__init__)
    assert stringify_signature(sig) == '(self, parent: Optional[Node]) -> None'

    # show_annotation is False
    sig = inspect.signature(f7)
    assert stringify_signature(sig, show_annotation=False) == '(x=None, y={})'

    # show_return_annotation is False
    sig = inspect.signature(f7)
    assert stringify_signature(sig, show_return_annotation=False) == '(x: int = None, y: dict = {})'
Exemplo n.º 14
0
 def process_signature(obj):
     sig = signature(obj)
     return stringify_signature(sig)
Exemplo n.º 15
0
def process_signature(
    app: Sphinx,
    what: str,
    name: str,
    obj,
    options,
    signature,
    return_annotation: Any,
) -> Optional[Tuple[str, None]]:
    """
	Process the signature for a function/method.

	:param app: The Sphinx application.
	:param what:
	:param name: The name of the object being documented.
	:param obj: The object being documented.
	:param options: Mapping of autodoc options to values.
	:param signature:
	:param return_annotation:

	:rtype:

	.. versionchanged:: 0.8.0

		Added support for factory function default values in attrs classes.
	"""

    if not callable(obj):
        return None

    original_obj = obj

    if inspect.isclass(obj):
        obj, signature, parameters = preprocess_class_defaults(obj)
    else:
        signature, parameters = preprocess_function_defaults(obj)

    obj = inspect.unwrap(obj)

    if not getattr(obj, "__annotations__", None):
        return None

    # The generated dataclass __init__() and class are weird and need extra checks
    # This helper function operates on the generated class and methods
    # of a dataclass, not an instantiated dataclass object. As such,
    # it cannot be replaced by a call to `dataclasses.is_dataclass()`.
    def _is_dataclass(name: str, what: str, qualname: str) -> bool:
        if what == "method" and name.endswith(".__init__"):
            # generated __init__()
            return True
        if what == "class" and qualname.endswith(".__init__"):
            # generated class
            return True
        return False

    # The generated dataclass __init__() is weird and needs the second condition
    if (hasattr(obj, "__qualname__") and "<locals>" in obj.__qualname__
            and not _is_dataclass(name, what, obj.__qualname__)):
        sat_logger.warning(
            "Cannot treat a function defined as a local function: '%s'  (use @functools.wraps)",
            name)
        return None

    if parameters:
        if inspect.isclass(original_obj) or (what == "method"
                                             and name.endswith(".__init__")):
            del parameters[0]
        elif what == "method":

            try:
                outer = inspect.getmodule(obj)
                if outer is not None:
                    for clsname in obj.__qualname__.split('.')[:-1]:
                        outer = getattr(outer, clsname)
            except AttributeError:
                outer = None

            method_name = obj.__name__
            if method_name.startswith("__") and not method_name.endswith("__"):
                # If the method starts with double underscore (dunder)
                # Python applies mangling so we need to prepend the class name.
                # This doesn't happen if it always ends with double underscore.
                class_name = obj.__qualname__.split('.')[-2]
                method_name = f"_{class_name}{method_name}"

            if outer is not None:
                method_object = outer.__dict__[method_name] if outer else obj
                if not isinstance(method_object, (classmethod, staticmethod)):
                    del parameters[0]

            else:
                if not inspect.ismethod(obj) and parameters[0].name in {
                        "self", "cls", "_cls"
                }:
                    del parameters[0]

    signature = signature.replace(parameters=parameters,
                                  return_annotation=inspect.Signature.empty)

    return stringify_signature(signature), None  # .replace('\\', '\\\\')