예제 #1
0
def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None:
    """Update defvalue info of *obj* using type_comments."""
    if not app.config.autodoc_preserve_defaults:
        return

    try:
        function = get_function_def(obj)
        if function.args.defaults or function.args.kw_defaults:
            sig = inspect.signature(obj)
            defaults = list(function.args.defaults)
            kw_defaults = list(function.args.kw_defaults)
            parameters = list(sig.parameters.values())
            for i, param in enumerate(parameters):
                if param.default is not param.empty:
                    if param.kind in (param.POSITIONAL_ONLY,
                                      param.POSITIONAL_OR_KEYWORD):
                        value = DefaultValue(ast_unparse(
                            defaults.pop(0)))  # type: ignore
                        parameters[i] = param.replace(default=value)
                    else:
                        value = DefaultValue(ast_unparse(
                            kw_defaults.pop(0)))  # type: ignore
                        parameters[i] = param.replace(default=value)
            sig = sig.replace(parameters=parameters)
            obj.__signature__ = sig
    except (AttributeError, TypeError):
        # failed to update signature (ex. built-in or extension types)
        pass
    except NotImplementedError as exc:  # failed to ast.unparse()
        logger.warning(
            __("Failed to parse a default argument value for %r: %s"), obj,
            exc)
예제 #2
0
def update_defvalue(app: Sphinx, obj: Any, bound_method: bool) -> None:
    """Update defvalue info of *obj* using type_comments."""
    if not app.config.autodoc_preserve_defaults:
        return

    try:
        lines = inspect.getsource(obj).splitlines()
        if lines[0].startswith((' ', r'\t')):
            lines.insert(0, '')  # insert a dummy line to follow what get_function_def() does.
    except (OSError, TypeError):
        lines = []

    try:
        function = get_function_def(obj)
        if function.args.defaults or function.args.kw_defaults:
            sig = inspect.signature(obj)
            defaults = list(function.args.defaults)
            kw_defaults = list(function.args.kw_defaults)
            parameters = list(sig.parameters.values())
            for i, param in enumerate(parameters):
                if param.default is param.empty:
                    if param.kind == param.KEYWORD_ONLY:
                        # Consume kw_defaults for kwonly args
                        kw_defaults.pop(0)
                else:
                    if param.kind in (param.POSITIONAL_ONLY, param.POSITIONAL_OR_KEYWORD):
                        default = defaults.pop(0)
                        value = get_default_value(lines, default)
                        if value is None:
                            value = ast_unparse(default)  # type: ignore
                        parameters[i] = param.replace(default=DefaultValue(value))
                    else:
                        default = kw_defaults.pop(0)
                        value = get_default_value(lines, default)
                        if value is None:
                            value = ast_unparse(default)  # type: ignore
                        parameters[i] = param.replace(default=DefaultValue(value))

            if bound_method and inspect.ismethod(obj):
                # classmethods
                cls = inspect.Parameter('cls', Parameter.POSITIONAL_OR_KEYWORD)
                parameters.insert(0, cls)

            sig = sig.replace(parameters=parameters)
            if bound_method and inspect.ismethod(obj):
                # classmethods can't be assigned __signature__ attribute.
                obj.__dict__['__signature__'] = sig
            else:
                obj.__signature__ = sig
    except (AttributeError, TypeError):
        # failed to update signature (ex. built-in or extension types)
        pass
    except NotImplementedError as exc:  # failed to ast.unparse()
        logger.warning(__("Failed to parse a default argument value for %r: %s"), obj, exc)
예제 #3
0
파일: inspect.py 프로젝트: zooba/sphinx
def signature_from_str(signature: str) -> inspect.Signature:
    """Create a Signature object from string."""
    module = ast.parse('def func' + signature + ': pass')
    definition = cast(ast.FunctionDef, module.body[0])  # type: ignore

    # parameters
    args = definition.args
    defaults = list(args.defaults)
    params = []
    if hasattr(args, "posonlyargs"):
        posonlyargs = len(args.posonlyargs)  # type: ignore
        positionals = posonlyargs + len(args.args)
    else:
        posonlyargs = 0
        positionals = len(args.args)

    for _ in range(len(defaults), positionals):
        defaults.insert(0, Parameter.empty)

    if hasattr(args, "posonlyargs"):
        for i, arg in enumerate(args.posonlyargs):  # type: ignore
            if defaults[i] is Parameter.empty:
                default = Parameter.empty
            else:
                default = ast_unparse(defaults[i])

            annotation = ast_unparse(arg.annotation) or Parameter.empty
            params.append(Parameter(arg.arg, Parameter.POSITIONAL_ONLY,
                                    default=default, annotation=annotation))

    for i, arg in enumerate(args.args):
        if defaults[i + posonlyargs] is Parameter.empty:
            default = Parameter.empty
        else:
            default = ast_unparse(defaults[i + posonlyargs])

        annotation = ast_unparse(arg.annotation) or Parameter.empty
        params.append(Parameter(arg.arg, Parameter.POSITIONAL_OR_KEYWORD,
                                default=default, annotation=annotation))

    if args.vararg:
        annotation = ast_unparse(args.vararg.annotation) or Parameter.empty
        params.append(Parameter(args.vararg.arg, Parameter.VAR_POSITIONAL,
                                annotation=annotation))

    for i, arg in enumerate(args.kwonlyargs):
        default = ast_unparse(args.kw_defaults[i]) or Parameter.empty
        annotation = ast_unparse(arg.annotation) or Parameter.empty
        params.append(Parameter(arg.arg, Parameter.KEYWORD_ONLY, default=default,
                                annotation=annotation))

    if args.kwarg:
        annotation = ast_unparse(args.kwarg.annotation) or Parameter.empty
        params.append(Parameter(args.kwarg.arg, Parameter.VAR_KEYWORD,
                                annotation=annotation))

    return_annotation = ast_unparse(definition.returns) or Parameter.empty

    return inspect.Signature(params, return_annotation=return_annotation)
예제 #4
0
파일: inspect.py 프로젝트: varphone/sphinx
def signature_from_ast(node: ast.FunctionDef, code: str = '') -> inspect.Signature:
    """Create a Signature object from AST *node*."""
    args = node.args
    defaults = list(args.defaults)
    params = []
    if hasattr(args, "posonlyargs"):
        posonlyargs = len(args.posonlyargs)  # type: ignore
        positionals = posonlyargs + len(args.args)
    else:
        posonlyargs = 0
        positionals = len(args.args)

    for _ in range(len(defaults), positionals):
        defaults.insert(0, Parameter.empty)  # type: ignore

    if hasattr(args, "posonlyargs"):
        for i, arg in enumerate(args.posonlyargs):  # type: ignore
            if defaults[i] is Parameter.empty:
                default = Parameter.empty
            else:
                default = DefaultValue(ast_unparse(defaults[i], code))  # type: ignore

            annotation = ast_unparse(arg.annotation, code) or Parameter.empty
            params.append(Parameter(arg.arg, Parameter.POSITIONAL_ONLY,
                                    default=default, annotation=annotation))

    for i, arg in enumerate(args.args):
        if defaults[i + posonlyargs] is Parameter.empty:
            default = Parameter.empty
        else:
            default = DefaultValue(ast_unparse(defaults[i + posonlyargs], code))  # type: ignore  # NOQA

        annotation = ast_unparse(arg.annotation, code) or Parameter.empty
        params.append(Parameter(arg.arg, Parameter.POSITIONAL_OR_KEYWORD,
                                default=default, annotation=annotation))

    if args.vararg:
        annotation = ast_unparse(args.vararg.annotation, code) or Parameter.empty
        params.append(Parameter(args.vararg.arg, Parameter.VAR_POSITIONAL,
                                annotation=annotation))

    for i, arg in enumerate(args.kwonlyargs):
        if args.kw_defaults[i] is None:
            default = Parameter.empty
        else:
            default = DefaultValue(ast_unparse(args.kw_defaults[i], code))  # type: ignore  # NOQA
        annotation = ast_unparse(arg.annotation, code) or Parameter.empty
        params.append(Parameter(arg.arg, Parameter.KEYWORD_ONLY, default=default,
                                annotation=annotation))

    if args.kwarg:
        annotation = ast_unparse(args.kwarg.annotation, code) or Parameter.empty
        params.append(Parameter(args.kwarg.arg, Parameter.VAR_KEYWORD,
                                annotation=annotation))

    return_annotation = ast_unparse(node.returns, code) or Parameter.empty

    return inspect.Signature(params, return_annotation=return_annotation)
예제 #5
0
def update_annotations_using_type_comments(app: Sphinx, obj: Any, bound_method: bool) -> None:
    """Update annotations info of *obj* using type_comments."""
    try:
        function = get_type_comment(obj)
        if function and hasattr(function, 'argtypes'):
            if function.argtypes != [ast.Ellipsis]:  # type: ignore
                sig = inspect.signature(obj, bound_method)
                for i, param in enumerate(sig.parameters.values()):
                    if param.name not in obj.__annotations__:
                        annotation = ast_unparse(function.argtypes[i])  # type: ignore
                        obj.__annotations__[param.name] = annotation

            if 'return' not in obj.__annotations__:
                obj.__annotations__['return'] = ast_unparse(function.returns)  # type: ignore
    except NotImplementedError as exc:  # failed to ast.unparse()
        logger.warning("Failed to parse type_comment for %r: %s", obj, exc)
예제 #6
0
파일: inspect.py 프로젝트: vallsv/sphinx
def signature_from_str(signature: str) -> inspect.Signature:
    """Create a Signature object from string."""
    module = ast.parse('def func' + signature + ': pass')
    definition = cast(ast.FunctionDef, module.body[0])  # type: ignore

    # parameters
    args = definition.args
    params = []

    if hasattr(args, "posonlyargs"):
        for arg in args.posonlyargs:  # type: ignore
            annotation = ast_unparse(arg.annotation) or Parameter.empty
            params.append(
                Parameter(arg.arg,
                          Parameter.POSITIONAL_ONLY,
                          annotation=annotation))

    for i, arg in enumerate(args.args):
        if len(args.args) - i <= len(args.defaults):
            default = ast_unparse(args.defaults[-len(args.args) + i])
        else:
            default = Parameter.empty

        annotation = ast_unparse(arg.annotation) or Parameter.empty
        params.append(
            Parameter(arg.arg,
                      Parameter.POSITIONAL_OR_KEYWORD,
                      default=default,
                      annotation=annotation))

    if args.vararg:
        annotation = ast_unparse(args.vararg.annotation) or Parameter.empty
        params.append(
            Parameter(args.vararg.arg,
                      Parameter.VAR_POSITIONAL,
                      annotation=annotation))

    for i, arg in enumerate(args.kwonlyargs):
        default = ast_unparse(args.kw_defaults[i]) or Parameter.empty
        annotation = ast_unparse(arg.annotation) or Parameter.empty
        params.append(
            Parameter(arg.arg,
                      Parameter.KEYWORD_ONLY,
                      default=default,
                      annotation=annotation))

    if args.kwarg:
        annotation = ast_unparse(args.kwarg.annotation) or Parameter.empty
        params.append(
            Parameter(args.kwarg.arg,
                      Parameter.VAR_KEYWORD,
                      annotation=annotation))

    return_annotation = ast_unparse(definition.returns) or Parameter.empty

    return inspect.Signature(params, return_annotation=return_annotation)
예제 #7
0
def signature_from_ast(node: ast.FunctionDef, bound_method: bool,
                       type_comment: ast.FunctionDef) -> Signature:
    """Return a Signature object for the given *node*.

    :param bound_method: Specify *node* is a bound method or not
    """
    params = []
    if hasattr(node.args, "posonlyargs"):  # for py38+
        for arg in node.args.posonlyargs:  # type: ignore
            param = Parameter(arg.arg,
                              Parameter.POSITIONAL_ONLY,
                              annotation=arg.type_comment)
            params.append(param)

    for arg in node.args.args:
        param = Parameter(arg.arg,
                          Parameter.POSITIONAL_OR_KEYWORD,
                          annotation=arg.type_comment or Parameter.empty)
        params.append(param)

    if node.args.vararg:
        param = Parameter(node.args.vararg.arg,
                          Parameter.VAR_POSITIONAL,
                          annotation=node.args.vararg.type_comment
                          or Parameter.empty)
        params.append(param)

    for arg in node.args.kwonlyargs:
        param = Parameter(arg.arg,
                          Parameter.KEYWORD_ONLY,
                          annotation=arg.type_comment or Parameter.empty)
        params.append(param)

    if node.args.kwarg:
        param = Parameter(node.args.kwarg.arg,
                          Parameter.VAR_KEYWORD,
                          annotation=node.args.kwarg.type_comment
                          or Parameter.empty)
        params.append(param)

    # Remove first parameter when *obj* is bound_method
    if bound_method and params:
        params.pop(0)

    # merge type_comment into signature
    if not_suppressed(type_comment.argtypes):  # type: ignore
        for i, param in enumerate(params):
            params[i] = param.replace(
                annotation=type_comment.argtypes[i])  # type: ignore

    if node.returns:
        return Signature(params, return_annotation=node.returns)
    elif type_comment.returns:
        return Signature(params,
                         return_annotation=ast_unparse(type_comment.returns))
    else:
        return Signature(params)
예제 #8
0
def not_suppressed(argtypes: List[ast.AST] = []) -> bool:
    """Check given *argtypes* is suppressed type_comment or not."""
    if len(argtypes) == 0:  # no argtypees
        return False
    elif len(argtypes) == 1 and ast_unparse(argtypes[0]) == "...":  # suppressed
        # Note: To support multiple versions of python, this uses ``ast_unparse()`` for
        # comparison with Ellipsis.  Since 3.8, ast.Constant has been used to represent
        # Ellipsis node instead of ast.Ellipsis.
        return False
    else:  # not suppressed
        return True
예제 #9
0
def update_annotations_using_type_comments(app: Sphinx, obj: Any,
                                           bound_method: bool) -> None:
    """Update annotations info of *obj* using type_comments."""
    try:
        type_sig = get_type_comment(obj, bound_method)
        if type_sig:
            sig = inspect.signature(obj, bound_method)
            for param in sig.parameters.values():
                if param.name not in obj.__annotations__:
                    annotation = type_sig.parameters[param.name].annotation
                    if annotation is not Parameter.empty:
                        obj.__annotations__[param.name] = ast_unparse(
                            annotation)

            if 'return' not in obj.__annotations__:
                obj.__annotations__['return'] = type_sig.return_annotation
    except NotImplementedError as exc:  # failed to ast.unparse()
        logger.warning("Failed to parse type_comment for %r: %s", obj, exc)