예제 #1
0
def _extract_signature(obj_sig):
    try:
        signature = inspect.signature(obj_sig)
        parameters = signature.parameters
    except TypeError as e:
        mes = "[docfx] unable to get signature of '{0}' - {1}.".format(
            object_name,
            str(e).replace("\n", "\\n"))
        logger.warning(mes)
        signature = None
        parameters = None
    except ValueError as e:
        # Backup plan, no __text_signature__, this happen
        # when a function was created with pybind11.
        doc = obj_sig.__doc__
        sigs = set(enumerate_cleaned_signature(doc))
        if len(sigs) == 0:
            mes = "[docfx] unable to get signature of '{0}' - {1}.".format(
                object_name,
                str(e).replace("\n", "\\n"))
            logger.warning(mes)
            signature = None
            parameters = None
        elif len(sigs) > 1:
            mes = "[docfx] too many signatures for '{0}' - {1} - {2}.".format(
                object_name,
                str(e).replace("\n", "\\n"), " *** ".join(sigs))
            logger.warning(mes)
            signature = None
            parameters = None
        else:
            try:
                signature = inspect._signature_fromstr(inspect.Signature,
                                                       obj_sig,
                                                       list(sigs)[0])
                parameters = signature.parameters
            except TypeError as e:
                mes = "[docfx] unable to get signature of '{0}' - {1}.".format(
                    object_name,
                    str(e).replace("\n", "\\n"))
                logger.warning(mes)
                signature = None
                parameters = None
    return signature, parameters
예제 #2
0
파일: python.py 프로젝트: timkpaine/arrow
def inspect_signature(obj):
    """
    Custom signature inspection primarily for cython generated callables.

    Cython puts the signatures to the first line of the docstrings, which we
    can reuse to parse the python signature from, but some gymnastics are
    required, like removing the cython typehints.

    It converts the cython signature:
        array(obj, type=None, mask=None, size=None, from_pandas=None,
              bool safe=True, MemoryPool memory_pool=None)
    To:
        <Signature (obj, type=None, mask=None, size=None, from_pandas=None,
                    safe=True, memory_pool=None)>
    """
    cython_signature = obj.__doc__.splitlines()[0]
    cython_tokens = _tokenize_signature(cython_signature)
    python_tokens = _convert_typehint(cython_tokens)
    python_signature = tokenize.untokenize(python_tokens)
    return inspect._signature_fromstr(inspect.Signature, obj, python_signature)
예제 #3
0
def getfullargspec(func):
    if func in (_np.empty_like, _np.ones_like, _np.zeros_like):
        if func is _np.empty_like:
            sig = inspect._signature_fromstr(
                inspect.Signature, func,
                func.__doc__.strip().split('\n', maxsplit=1)[0])
        else:
            sig = inspect.signature(func)
        return inspect.FullArgSpec(
            list(sig.parameters.keys()),  # args
            None,  # varargs
            None,  # varkw
            tuple(v.default for v in sig.parameters.values()
                  if v.default is not inspect._empty),  # defaults
            [],  # knwonlyargs
            {},  # kwonlydefaults
            {},  # annotations
        )
    else:
        return _inspect_getfullargspec(func)
예제 #4
0
파일: inspect3.py 프로젝트: rocky/x-python
def _signature_from_callable(
    obj, follow_wrapper_chains=True, skip_bound_arg=True, sigcls=None
):

    """Private helper function to get signature for arbitrary
    callable objects.
    """

    # We don't want to import pyobj, since that imports us
    if not xCallable(obj):
        raise TypeError("%r is not a callable object" % obj)

    if isinstance(obj, types.MethodType):
        # In this case we skip the first parameter of the underlying
        # function (usually `self` or `cls`).
        sig = _signature_from_callable(
            obj.__func__,
            follow_wrapper_chains=follow_wrapper_chains,
            skip_bound_arg=skip_bound_arg,
            sigcls=sigcls,
        )

        if skip_bound_arg:
            return _signature_bound_method(sig)
        else:
            return sig

    # Was this function wrapped by a decorator?
    if follow_wrapper_chains:
        obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__")))
        if isinstance(obj, types.MethodType):
            # If the unwrapped object is a *method*, we might want to
            # skip its first parameter (self).
            # See test_signature_wrapped_bound_method for details.
            return _signature_from_callable(
                obj,
                follow_wrapper_chains=follow_wrapper_chains,
                skip_bound_arg=skip_bound_arg,
                sigcls=sigcls,
            )

    try:
        sig = obj.__signature__
    except AttributeError:
        pass
    else:
        if sig is not None:
            if not isinstance(sig, Signature):
                raise TypeError(
                    "unexpected object %r in __signature__ " "attribute" % sig
                )
            return sig

    try:
        partialmethod = obj._partialmethod
    except AttributeError:
        pass
    else:
        if isinstance(partialmethod, functools.partialmethod):
            # Unbound partialmethod (see functools.partialmethod)
            # This means, that we need to calculate the signature
            # as if it's a regular partial object, but taking into
            # account that the first positional argument
            # (usually `self`, or `cls`) will not be passed
            # automatically (as for boundmethods)

            wrapped_sig = _signature_from_callable(
                partialmethod.func,
                follow_wrapper_chains=follow_wrapper_chains,
                skip_bound_arg=skip_bound_arg,
                sigcls=sigcls,
            )

            sig = _signature_get_partial(wrapped_sig, partialmethod, (None,))
            first_wrapped_param = tuple(wrapped_sig.parameters.values())[0]
            if first_wrapped_param.kind is Parameter.VAR_POSITIONAL:
                # First argument of the wrapped callable is `*args`, as in
                # `partialmethod(lambda *args)`.
                return sig
            else:
                sig_params = tuple(sig.parameters.values())
                assert not sig_params or first_wrapped_param is not sig_params[0]
                new_params = (first_wrapped_param,) + sig_params
                return sig.replace(parameters=new_params)

    if isfunction(obj) or _signature_is_functionlike(obj):
        # If it's a pure Python function, or an object that is duck type
        # of a Python function (Cython functions, for instance), then:
        return _signature_from_function(sigcls, obj)

    if _signature_is_builtin(obj):
        return _signature_from_builtin(sigcls, obj, skip_bound_arg=skip_bound_arg)

    if isinstance(obj, functools.partial):
        wrapped_sig = _signature_from_callable(
            obj.func,
            follow_wrapper_chains=follow_wrapper_chains,
            skip_bound_arg=skip_bound_arg,
            sigcls=sigcls,
        )
        return _signature_get_partial(wrapped_sig, obj)

    sig = None
    if isinstance(obj, type):
        # obj is a class or a metaclass

        # First, let's see if it has an overloaded __call__ defined
        # in its metaclass
        call = _signature_get_user_defined_method(type(obj), "__call__")
        if call is not None:
            sig = _signature_from_callable(
                call,
                follow_wrapper_chains=follow_wrapper_chains,
                skip_bound_arg=skip_bound_arg,
                sigcls=sigcls,
            )
        else:
            # Now we check if the 'obj' class has a '__new__' method
            new = _signature_get_user_defined_method(obj, "__new__")
            if new is not None:
                sig = _signature_from_callable(
                    new,
                    follow_wrapper_chains=follow_wrapper_chains,
                    skip_bound_arg=skip_bound_arg,
                    sigcls=sigcls,
                )
            else:
                # Finally, we should have at least __init__ implemented
                init = _signature_get_user_defined_method(obj, "__init__")
                if init is not None:
                    sig = _signature_from_callable(
                        init,
                        follow_wrapper_chains=follow_wrapper_chains,
                        skip_bound_arg=skip_bound_arg,
                        sigcls=sigcls,
                    )

        if sig is None:
            # At this point we know, that `obj` is a class, with no user-
            # defined '__init__', '__new__', or class-level '__call__'

            for base in obj.__mro__[:-1]:
                # Since '__text_signature__' is implemented as a
                # descriptor that extracts text signature from the
                # class docstring, if 'obj' is derived from a builtin
                # class, its own '__text_signature__' may be 'None'.
                # Therefore, we go through the MRO (except the last
                # class in there, which is 'object') to find the first
                # class with non-empty text signature.
                try:
                    text_sig = base.__text_signature__
                except AttributeError:
                    pass
                else:
                    if text_sig:
                        # If 'obj' class has a __text_signature__ attribute:
                        # return a signature based on it
                        return _signature_fromstr(sigcls, obj, text_sig)

            # No '__text_signature__' was found for the 'obj' class.
            # Last option is to check if its '__init__' is
            # object.__init__ or type.__init__.
            if type not in obj.__mro__:
                # We have a class (not metaclass), but no user-defined
                # __init__ or __new__ for it
                if obj.__init__ is object.__init__ and obj.__new__ is object.__new__:
                    # Return a signature of 'object' builtin.
                    return signature(object)
                else:
                    raise ValueError(
                        "no signature found for builtin type %r" % obj
                    )

    elif not isinstance(obj, _NonUserDefinedCallables):
        # An object with __call__
        # We also check that the 'obj' is not an instance of
        # _WrapperDescriptor or _MethodWrapper to avoid
        # infinite recursion (and even potential segfault)
        call = _signature_get_user_defined_method(type(obj), "__call__")
        if call is not None:
            try:
                sig = _signature_from_callable(
                    call,
                    follow_wrapper_chains=follow_wrapper_chains,
                    skip_bound_arg=skip_bound_arg,
                    sigcls=sigcls,
                )
            except ValueError:
                msg = "no signature found for %r" % obj
                raise ValueError(msg) # from ex

    if sig is not None:
        # For classes and objects we skip the first parameter of their
        # __call__, __new__, or __init__ methods
        if skip_bound_arg:
            return _signature_bound_method(sig)
        else:
            return sig

    if isinstance(obj, types.BuiltinFunctionType):
        # Raise a nicer error message for builtins
        msg = "no signature found for builtin function %r" % obj
        raise ValueError(msg)

    raise ValueError("callable %r is not supported by signature" % obj)
    def run(self):
        self.filename_set = set()
        # a set of dependent filenames
        self.reporter = self.state.document.reporter
        self.env = self.state.document.settings.env

        opt_summary = 'nosummary' not in self.options
        opt_annotation = 'annotation' in self.options
        opt_link = 'nolink' not in self.options
        opt_members = self.options.get('members', None)
        opt_debug = 'debug' in self.options
        if opt_members in (None, '') and 'members' in self.options:
            opt_members = "all"
        opt_path = self.options.get('path', 'import')
        opt_syspath = self.options.get('syspath', None)

        if opt_debug:
            keep_logged = []

            def keep_logging(*els):
                keep_logged.append(" ".join(str(_) for _ in els))

            logging_function = keep_logging
        else:
            logging_function = None

        try:
            source, lineno = self.reporter.get_source_and_line(self.lineno)
        except AttributeError:  # pragma: no cover
            source = lineno = None

        # object name
        object_name = " ".join(_.strip("\n\r\t ") for _ in self.content)
        if opt_syspath:
            syslength = len(sys.path)
            sys.path.extend(opt_syspath.split(';'))
        try:
            obj, _, kind = import_any_object(object_name,
                                             use_init=False,
                                             fLOG=logging_function)
        except ImportError as e:
            mes = "[autosignature] unable to import '{0}' due to '{1}'".format(
                object_name, e)
            logger = logging.getLogger("autosignature")
            logger.warning(mes)
            if logging_function:
                logging_function(mes)  # pragma: no cover
            if lineno is not None:
                logger.warning('   File "{0}", line {1}'.format(
                    source, lineno))
            obj = None
            kind = None
        if opt_syspath:
            del sys.path[syslength:]

        if opt_members is not None and kind != "class":  # pragma: no cover
            logger = logging.getLogger("autosignature")
            logger.warning(
                "[autosignature] option members is specified but '{0}' "
                "is not a class (kind='{1}').".format(object_name, kind))
            obj = None

        # build node
        node = self.__class__.autosignature_class(rawsource=object_name,
                                                  source=source,
                                                  lineno=lineno,
                                                  objectname=object_name)

        if opt_path == 'import':
            if obj is None:
                logger = logging.getLogger("autosignature")
                logger.warning(
                    "[autosignature] object '{0}' cannot be imported.".format(
                        object_name))
                anchor = object_name
            elif kind == "staticmethod":
                cl, fu = object_name.split(".")[-2:]
                pimp = import_path(obj, class_name=cl, fLOG=logging_function)
                anchor = '{0}.{1}.{2}'.format(pimp, cl, fu)
            else:
                pimp = import_path(
                    obj, err_msg="object name: '{0}'".format(object_name))
                anchor = '{0}.{1}'.format(
                    pimp,
                    object_name.rsplit('.', maxsplit=1)[-1])
        elif opt_path == 'full':
            anchor = object_name
        elif opt_path == 'name':
            anchor = object_name.rsplit('.', maxsplit=1)[-1]
        else:  # pragma: no cover
            logger = logging.getLogger("autosignature")
            logger.warning(
                "[autosignature] options path is '{0}', it should be in "
                "(import, name, full) for object '{1}'.".format(
                    opt_path, object_name))
            anchor = object_name

        if obj is None:
            if opt_link:
                text = "\n:py:func:`{0} <{1}>`\n\n".format(anchor, object_name)
            else:
                text = "\n``{0}``\n\n".format(anchor)  # pragma: no cover
        else:
            obj_sig = obj.__init__ if kind == "class" else obj
            try:
                signature = inspect.signature(obj_sig)
                parameters = signature.parameters
            except TypeError as e:  # pragma: no cover
                mes = "[autosignature](1) unable to get signature of '{0}' - {1}.".format(
                    object_name,
                    str(e).replace("\n", "\\n"))
                logger = logging.getLogger("autosignature")
                logger.warning(mes)
                if logging_function:
                    logging_function(mes)
                signature = None
                parameters = None
            except ValueError as e:  # pragma: no cover
                # Backup plan, no __text_signature__, this happen
                # when a function was created with pybind11.
                doc = obj_sig.__doc__
                sigs = set(enumerate_cleaned_signature(doc))
                if len(sigs) == 0:
                    mes = "[autosignature](2) unable to get signature of '{0}' - {1}.".format(
                        object_name,
                        str(e).replace("\n", "\\n"))
                    logger = logging.getLogger("autosignature")
                    logger.warning(mes)
                    if logging_function:
                        logging_function(mes)
                    signature = None
                    parameters = None
                elif len(sigs) > 1:
                    mes = "[autosignature](2) too many signatures for '{0}' - {1} - {2}.".format(
                        object_name,
                        str(e).replace("\n", "\\n"), " *** ".join(sigs))
                    logger = logging.getLogger("autosignature")
                    logger.warning(mes)
                    if logging_function:
                        logging_function(mes)
                    signature = None
                    parameters = None
                else:
                    try:
                        signature = inspect._signature_fromstr(
                            inspect.Signature, obj_sig,
                            list(sigs)[0])
                        parameters = signature.parameters
                    except TypeError as e:
                        mes = "[autosignature](3) unable to get signature of '{0}' - {1}.".format(
                            object_name,
                            str(e).replace("\n", "\\n"))
                        logger = logging.getLogger("autosignature")
                        logger.warning(mes)
                        if logging_function:
                            logging_function(mes)
                        signature = None
                        parameters = None

            domkind = {
                'meth': 'func',
                'function': 'func',
                'method': 'meth',
                'class': 'class',
                'staticmethod': 'meth',
                'property': 'meth'
            }[kind]
            if signature is None:
                if opt_link:  # pragma: no cover
                    text = "\n:py:{2}:`{0} <{1}>`\n\n".format(
                        anchor, object_name, domkind)
                else:  # pragma: no cover
                    text = "\n``{0} {1}``\n\n".format(kind, object_name)
            else:
                signature = self.build_parameters_list(parameters,
                                                       opt_annotation)
                text = "\n:py:{3}:`{0} <{1}>` ({2})\n\n".format(
                    anchor, object_name, signature, domkind)

        if obj is not None and opt_summary:
            # Documentation.
            doc = obj.__doc__  # if kind != "class" else obj.__class__.__doc__
            if doc is None:  # pragma: no cover
                mes = "[autosignature] docstring empty for '{0}'.".format(
                    object_name)
                logger = logging.getLogger("autosignature")
                logger.warning(mes)
                if logging_function:
                    logging_function(mes)
            else:
                if "type(object_or_name, bases, dict)" in doc:
                    raise TypeError(  # pragma: no cover
                        "issue with {0}\n{1}".format(obj, doc))
                docstring = self.build_summary(doc)
                text += docstring + "\n\n"

        if opt_members is not None and kind == "class":
            docstring = self.build_members(obj, opt_members, object_name,
                                           opt_annotation, opt_summary)
            docstring = "\n".join(
                map(lambda s: "    " + s, docstring.split("\n")))
            text += docstring + "\n\n"

        text_lines = text.split("\n")
        if logging_function:
            text_lines.extend(['    ::', '', '        [debug]', ''])
            text_lines.extend('        ' + li for li in keep_logged)
            text_lines.append('')
        st = StringList(text_lines)
        nested_parse_with_titles(self.state, st, node)
        return [node]