Пример #1
0
 def format_args(self):
   # type: () -> str
   # We use the original signature from the wrapped _function
   has_retval= isinstance(self.object, FontBakeryCondition)
   sig = Signature(self.object._func, bound_method=False, has_retval=has_retval)
   args = sig.format_args()
   # escape backslashes for reST
   args = args.replace('\\', '\\\\')
   return args
def process_signature(app, what: str, name: str, obj, options, signature,
                      return_annotation):
    if not callable(obj):
        return

    if what in ('class', 'exception'):
        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.signature.parameters.values()
    ]

    if '<locals>' in obj.__qualname__:
        logger.warning(
            'Cannot treat a function defined as a local function: "%s"  (use @functools.wraps)',
            name)
        return

    if parameters:
        if what in ('class', 'exception'):
            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 = signature.signature.replace(
        parameters=parameters, return_annotation=inspect.Signature.empty)

    return signature.format_args().replace('\\', '\\\\'), None
Пример #3
0
def preprocess_function_defaults(
    obj: Callable
) -> Tuple[Optional[inspect.Signature], List[inspect.Parameter]]:
    """
	Pre-processes the default values for the arguments of a function.

	.. versionadded:: 0.8.0

	:param obj: The function.

	:return: The function signature and a list of arguments/parameters.
	"""

    try:
        signature = Signature(inspect.unwrap(obj))
    except ValueError:  # pragma: no cover
        return None, []

    parameters = []

    for param in signature.parameters.values():
        default = param.default

        if default is not inspect.Parameter.empty:
            for check, preprocessor in default_preprocessors:
                if check(default):
                    default = preprocessor(default)
                    break

        parameters.append(
            param.replace(annotation=inspect.Parameter.empty, default=default))

    return signature, parameters
Пример #4
0
def strip_annotations(app, what: str, name: str, obj, options, signature,
                      return_annotation):
    if what not in {'function', 'method', 'class'}:
        return

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

    return new_signature.format_args(), None
Пример #5
0
 def format_args(self):
     # type: () -> str
     # for instances, the relevant signature is the __call__ method's
     callmeth = self.get_attr(self.object, '__call__', None)
     if callmeth:
         return Signature(callmeth, bound_method=True,
                          has_retval=True).format_args()
     return None
Пример #6
0
def get_args(func: Callable, for_sphinx: bool = True) -> List[str]:
    signature = Signature(unwrap_all(func))

    result = []
    for name, param in signature.parameters.items():
        if param.kind == inspect.Parameter.VAR_POSITIONAL:
            name = (r'\*' if for_sphinx else '*') + name
        elif param.kind == inspect.Parameter.VAR_KEYWORD:
            name = (r'\*\*' if for_sphinx else '**') + name
        result.append(name[:-1] +
                      r'\_' if for_sphinx and name.endswith('_') else name)
    return result
Пример #7
0
def get_arguments(obj: Callable) -> Mapping[str, inspect.Parameter]:
    """
	Returns a dictionary mapping argument names to parameters/arguments for a function.

	:param obj: A function (can be the ``__init__`` method of a class).
	"""

    try:
        signature = Signature(inspect.unwrap(obj))
    except ValueError:  # pragma: no cover
        return {}

    return signature.parameters
Пример #8
0
def process_signature(app, what: str, name: str, obj, options, signature,
                      return_annotation):
    if not callable(obj):
        return

    if what in ('class', 'exception'):
        obj = getattr(obj, '__init__')

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

    obj = unwrap(obj)

    return Signature(obj).format_args(), None
Пример #9
0
def preprocess_class_defaults(
    obj: Callable
) -> Tuple[Optional[Callable], Optional[inspect.Signature],
           List[inspect.Parameter]]:
    """
	Pre-processes the default values for the arguments of a class.

	.. versionadded:: 0.8.0

	:param obj: The class.

	:return: The class signature and a list of arguments/parameters.
	"""

    init: Optional[Callable[..., Any]] = getattr(obj, "__init__",
                                                 getattr(obj, "__new__", None))

    if is_namedtuple(obj):
        init = getattr(obj, "__new__")

    try:
        signature = Signature(inspect.unwrap(init))  # type: ignore[arg-type]
    except ValueError:  # pragma: no cover
        return init, None, []

    parameters = []

    for argname, param in signature.parameters.items():
        default = param.default

        if default is not inspect.Parameter.empty:
            for check, preprocessor in default_preprocessors:
                if check(default):
                    default = preprocessor(default)
                    break

            else:
                if hasattr(obj, "__attrs_attrs__") and default is attr.NOTHING:
                    # Special casing for attrs classes
                    for value in obj.__attrs_attrs__:  # type: ignore
                        if value.name == argname and isinstance(
                                value.default, attr.Factory):  # type: ignore
                            default = value.default.factory()

        parameters.append(
            param.replace(annotation=inspect.Parameter.empty, default=default))

    return init, signature, parameters
Пример #10
0
def get_default_args(func: Callable,
                     for_sphinx: bool = True) -> OrderedDictType[str, Any]:
    signature = Signature(func)

    # Backward Compatibility
    #   The built-in Parameter object is guaranteed
    #   an ordered mapping in >= 3.5.
    default_args = OrderedDict()
    for k, v in signature.parameters.items():
        # assume *args, **kwargs does not have default
        if v.default is not inspect.Parameter.empty:
            if for_sphinx and k.endswith('_'):
                k = '{}\\_'.format(k[:-1])
            default_args[k] = (v.default,
                               v.kind == inspect.Parameter.KEYWORD_ONLY)
    return default_args
Пример #11
0
def process_signature(
    app,
    what: str,
    name: str,
    obj,  # pylint: disable=too-many-arguments,unused-argument
    options,
    signature,
    return_annotation,
):  # pylint: disable=unused-argument
    if callable(obj):
        if what in ("class", "exception"):
            obj = getattr(obj, "__init__")

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

        if parameters:
            if what in ("class", "exception"):
                del parameters[0]
            elif what == "method":
                outer = inspect.getmodule(obj)
                if outer is None:
                    return 
                for clsname in obj.__qualname__.split(".")[:-1]:
                    outer = getattr(outer, clsname, outer)

                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 = getattr(outer,'__dict__',{}).get(method_name, None)
                if not isinstance(method_object, (classmethod, staticmethod)):
                    del parameters[0]

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

        return signature.format_args().replace("\\", "\\\\"), None
Пример #12
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__() 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

    if '<locals>' in obj.__qualname__ and not _is_dataclass(name, what, obj.__qualname__):
        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
Пример #13
0
def get_signature_end(function):
    signature_end = Signature(function).format_args()
    if ismethod(function):
        signature_end = signature_end.replace("(self, ", "(")
        signature_end = signature_end.replace("(self)", "()")
    return signature_end
Пример #14
0
def get_signature_end(function):
    signature_end = Signature(function).format_args()
    if utils.ismethod(function):
        signature_end = signature_end.replace('(self, ', '(')
        signature_end = signature_end.replace('(self)', '()')
    return signature_end
Пример #15
0
def process_docstring(app: Sphinx, what: str, name: str, obj: Any,
                      options: Any, lines: List[str]) -> None:
    """Process docstring after Sphinx.

    See `autodoc-process-docstring <https://www.sphinx-doc.org/en/master/
    usage/extensions/autodoc.html#event-autodoc-process-docstring>`_
    """

    # original_obj = obj
    if isinstance(obj, property):
        obj = obj.fget

    if not callable(obj):
        return

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

    obj = inspect.unwrap(obj)

    rm_first_arg = what in ['method', 'property', 'class'
                            ] and not isstaticmethod(obj)
    first_argname = next(iter(Signature(
        unwrap_all(obj)).parameters)) if rm_first_arg else None
    if first_argname and first_argname.endswith('_'):
        first_argname = '{}\\_'.format(first_argname[:-1])

    default_args = get_default_args(obj)
    for argname, (default, is_keyword_only) in default_args.items():

        # what if default has \
        default = ':code:`{}`'.format(object_description(default))

        # TODO
        # should be arguments
        strip = app.config.docstring_default_arg_strip_matching
        docstring_default_arg_parenthesis = False

        # Search for parameters
        # TODO Test case: empty param
        searchfor = [
            ':{} {}:'.format(field, argname) for field in param_fields
        ]
        param_found, param_start, param_end, param_matched, param_text = (
            match_field(lines,
                        searchfor,
                        include_blank=app.config.
                        docstring_default_arg_after_directives))

        if param_found:

            if app.config.docstring_default_arg_substitution not in ' '.join(
                    param_text):

                # Extracts all the flags
                for head, tail in app.config.docstring_default_arg_flags:
                    tail_found, is_end, t_start = rfind_substring_in_paragraph(
                        param_text, tail, strip, app.config.
                        docstring_default_arg_flags_multiline_matching)[:3]
                    if tail_found and is_end:
                        head_found, _, h_start, h_end = (
                            rfind_substring_in_paragraph(
                                param_text, head, strip, app.config.
                                docstring_default_arg_flags_multiline_matching)
                        )
                        if head_found:
                            # what if default has \
                            if h_end[0] == t_start[0]:
                                default = param_text[
                                    h_end[0]][h_end[1]:t_start[1]]
                            else:
                                default = ' '.join(
                                    [param_text[h_end[0]][h_end[1]:]] +
                                    param_text[h_end[0] + 1:t_start[0]] +
                                    [param_text[t_start[0]][:t_start[1]]])
                            if strip:
                                default = default.strip()
                            lines[param_start + h_start[0]] = (
                                lines[param_start +
                                      h_start[0]][:len(param_matched) + 1 +
                                                  h_start[1]])
                            del lines[param_start + h_start[0] + 1:param_end]
                            param_end = param_start + h_start[0] + 1
                            break

                if strip:
                    lines[param_end - 1] = rstrip_min(lines[param_end - 1],
                                                      len(param_matched) + 1)

                if docstring_default_arg_parenthesis:
                    raise NotImplementedError
                else:
                    # To prevent insertion into Note directives or so
                    lines.insert(
                        param_end, ' ' * len(param_matched) + ' {} {}'.format(
                            app.config.docstring_default_arg_substitution,
                            default))
        elif app.config.always_document_default_args and (
                not rm_first_arg or argname != first_argname):

            # Since ``kwargs`` (no default args) might come
            # after ``argname``, it will not be in ``default_args``.
            # Need to generate the full args list.
            next_start, next_type = find_next_arg(lines, get_args(obj),
                                                  argname)

            if docstring_default_arg_parenthesis:
                raise NotImplementedError
            else:
                lines.insert(
                    next_start, ':{} {}: {} {}'.format(
                        'keyword' if is_keyword_only and
                        (next_type is None or next_type in kw_fields) else
                        'param', argname,
                        app.config.docstring_default_arg_substitution,
                        default))

        # Search for type
        type_found, type_start, type_end, type_matched, type_text = (
            match_field(
                lines,
                [':{} {}:'.format(field, argname) for field in type_fields],
                include_blank=False))

        if type_found:
            type_text = ' '.join(type_text)
            if strip:
                type_text = type_text.rstrip()
                lines[type_end - 1] = rstrip_min(lines[type_end - 1],
                                                 len(type_matched) + 1)
            if not type_text.endswith('optional'):
                if not type_text.strip():
                    lines[type_start] = '{} optional'.format(type_matched)
                elif '`' in type_text:
                    # TODO check \` escape
                    lines[type_end - 1] += ', *optional*'
                else:
                    # Do not insert newline to prevent whitespace before ','
                    lines[type_end - 1] += ', optional'
        elif param_found or app.config.always_document_default_args and (
                not rm_first_arg or argname != first_argname):
            # insert type before param
            param_start, param_type = find_curr_arg(lines, get_args(obj),
                                                    argname)
            assert any(lines[param_start].startswith(search)
                       for search in searchfor)
            lines.insert(
                param_start, ':{}type {}: optional'.format(
                    'kw' if param_type in kw_fields else '', argname))