示例#1
0
        def safe_default_value(p: inspect.Parameter):
            if p.default is inspect.Parameter.empty:
                return p

            replacement = None
            if p.default is os.environ:
                replacement = 'os.environ'
            elif inspect.isclass(p.default):
                replacement = p.default.__module__ + '.' + p.default.__qualname__
            elif ' at 0x' in repr(p.default):
                replacement = re.sub(r' at 0x\w+', '', repr(p.default))

            nonlocal link
            if link and ('<' in repr(p.default) or '>' in repr(p.default)):
                import html
                replacement = html.escape(replacement or p.default)

            if replacement:

                class mock:
                    def __repr__(self):
                        return replacement

                return p.replace(default=mock())
            return p
示例#2
0
        def safe_default_value(p: inspect.Parameter):
            value = p.default
            if value is inspect.Parameter.empty:
                return p

            replacement = next((i for i in (
                'os.environ',
                'sys.stdin',
                'sys.stdout',
                'sys.stderr',
            ) if value is eval(i)), None)
            if not replacement:
                if isinstance(value, enum.Enum):
                    replacement = str(value)
                elif inspect.isclass(value):
                    replacement = value.__module__ + '.' + value.__qualname__
                elif ' at 0x' in repr(value):
                    replacement = re.sub(r' at 0x\w+', '', repr(value))

                nonlocal link
                if link and ('<' in repr(value) or '>' in repr(value)):
                    import html
                    replacement = html.escape(replacement or repr(value))

            if replacement:

                class mock:
                    def __repr__(self):
                        return replacement

                return p.replace(default=mock())
            return p
示例#3
0
 def replace_param(sig: inspect.Signature, param: inspect.Parameter,
                   type_: Type[Any]) -> inspect.Signature:
     new_param = param.replace(annotation=type_)
     return sig.replace(parameters=[
         new_param if p is param else p
         for p in sig.parameters.values()
     ])
        def safe_default_value(p: inspect.Parameter):
            if p.default is os.environ:

                class mock:
                    def __repr__(self):
                        return 'os.environ'

                return p.replace(default=mock())
            return p
示例#5
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)
示例#6
0
文件: main.py 项目: jnoortheen/arger
    def create(
        cls,
        param: inspect.Parameter,
        pdoc: tp.Optional[ParamDocTp],
        option_generator: FlagsGenerator,
    ) -> "Argument":
        hlp = pdoc.doc if pdoc else ""

        arg = None
        if isinstance(param.annotation, Argument):
            arg = param.annotation
        elif tp_utils.has_annotated(param.annotation):
            typ, arg = tp_utils.get_annotated_args(param.annotation)
            param = param.replace(annotation=typ)

        if arg is None:
            arg = Argument()

        arg.kwargs.setdefault("help", hlp)
        arg.update(param, option_generator)
        return arg
示例#7
0
def normalize_parameter(parameter: Parameter) -> Parameter:
    if parameter.kind != Parameter.POSITIONAL_OR_KEYWORD:
        raise IllegalFormatException(
            f"Invalid signature: name={parameter.name} kind={parameter.kind}")

    annotation = parameter.annotation

    if annotation == Parameter.empty:
        type_hint = str
    else:
        type_hint = normalize_type_hint(annotation)

    # a: int = None -> a: Union[int, None] = None
    if parameter.default is None and get_origin(type_hint) is not Union:
        type_hint = Union[type_hint, None]

    check_parameter_default_type(type_hint, parameter.default)

    if type_hint == annotation:
        # Nothing to update
        return parameter

    return parameter.replace(annotation=type_hint)
示例#8
0
def generate_signature(func: Callable) -> Signature:
    """Generate a new function signatures with the ``self``, ``invert`` and ``exception`` parameters.

    Default to :data:`BACK_SIGNATURE` if a functions' signature cannot be read.

    Examples
    --------
    .. code:: python

        >>> import inspect

        >>> func = enumerate  # The builtin enumerate function
        >>> Signature = inspect.Signature

        # Print the signature of enumerate
        >>> sgn1: Signature = inspect.signature(func)
        >>> print(sgn1)
        (iterable, start=0)

        # Print the newly create signature
        >>> sgn2: Signature = generate_signatures(func)
        >>> print(sgn2)
        (self, iterable, *args, start=0, invert_: bool = False, exception_: Union[Type[Exception], NoneType] = None, **kwargs) -> None

    Parameters
    ----------
    func : :data:`Callable<typing.Callable>`
        A callable object.

    Returns
    -------
    :class:`Signature<inspect.Signature>`
        The signature of **func** with the ``self`` and ``invert`` parameters.
        Return :data:`BACK_SIGNATURE` if funcs' signature cannot be read.

    """  # noqa
    try:
        sgn = signature(func)
    except ValueError:  # Not all callables have a signature which can be read.
        return BACK_SIGNATURE

    prm_dict: Dict[_ParameterKind, list] = OrderedDict({
        POK: [Parameter(name='self', kind=POK)],
        VP: [],
        KO: [],
        VK: []
    })

    # Fill the parameter dict
    for prm in sgn.parameters.values():
        if prm.name in ('self', 'cls'):
            name, _ = _get_cls_annotation(func, prm.name)
            prm = Parameter(name=name, kind=POK)
        elif prm.kind is PO:  # Positional-only to positional or keyword
            prm = prm.replace(kind=POK)
        elif prm.kind is POK and prm.default is not _empty:  # keyword or positional to keyword only
            prm = prm.replace(kind=KO)
        prm_dict[prm.kind].append(prm)

    # Double check if the invert and exception parameters are already defined by **func**
    invert_name = _sanitize_name('invert', func, prm_dict[KO])
    exception_name = _sanitize_name('exception', func, prm_dict[KO])

    # Ensure the parameter dict contains the following 4 parameters
    prm_dict[KO].append(
        Parameter(name=invert_name, kind=KO, default=False, annotation=bool))
    prm_dict[KO].append(
        Parameter(name=exception_name,
                  kind=KO,
                  default=None,
                  annotation=ExType))
    if not prm_dict[VP]:
        prm_dict[VP].append(Parameter(name='args', kind=VP))
    if not prm_dict[VK]:
        prm_dict[VK].append(Parameter(name='kwargs', kind=VK))

    # Construct and return a new signature
    parameters = chain.from_iterable(prm_dict.values())
    return Signature(parameters=parameters, return_annotation=None)
示例#9
0
# Python sys — System-specific parameters and functions.
# This module provides access to some variables used or maintained by the interpreter and to functions that interact
# strongly with the interpreter.
# inspect — Inspect live objects.
# The inspect module provides several useful functions to help get information about live objects such as modules, classes,
# methods, functions, tracebacks, frame objects, and code objects. 
# replace(*[, name][, kind][, default][, annotation]). 
# Create a new Parameter instance based on the instance replaced was invoked on. To override a Parameter attribute, pass the
# corresponding argument. To remove a default value or/and an annotation from a Parameter, pass Parameter.empty.
 
from inspect import Parameter

    param = Parameter('foo', Parameter.KEYWORD_ONLY, default=42)

    str(param)              # Displays 'foo=42'

    str(param.replace())    # Will create a shallow copy of 'param'

                            # Displays'foo=42'

    str(param.replace(default=Parameter.empty, annotation='spam'))

                            # Displays "foo:'spam'"
示例#10
0
def replace_parameter(
    param: inspect.Parameter,
    converter: Any,
    callback: Callable[..., Any],
    original: Parameter,
    mapping: Dict[str, inspect.Parameter],
) -> inspect.Parameter:
    try:
        # If it's a supported annotation (i.e. a transformer) just let it pass as-is.
        app_commands.transformers.get_supported_annotation(converter)
    except TypeError:
        # Fallback to see if the behaviour needs changing
        origin = getattr(converter, '__origin__', None)
        args = getattr(converter, '__args__', [])
        if isinstance(converter, Range):
            r = converter
            param = param.replace(
                annotation=app_commands.Range[r.annotation, r.min,
                                              r.max])  # type: ignore
        elif isinstance(converter, Greedy):
            # Greedy is "optional" in ext.commands
            # However, in here, it probably makes sense to make it required.
            # I'm unsure how to allow the user to choose right now.
            inner = converter.converter
            if inner is discord.Attachment:
                raise TypeError(
                    'discord.Attachment with Greedy is not supported in hybrid commands'
                )

            param = param.replace(
                annotation=make_greedy_transformer(inner, original))
        elif is_flag(converter):
            callback.__hybrid_command_flag__ = (param.name, converter)
            descriptions = {}
            renames = {}
            for flag in converter.__commands_flags__.values():
                name = flag.attribute
                flag_param = inspect.Parameter(
                    name=name,
                    kind=param.kind,
                    default=flag.default if flag.default is not MISSING else
                    inspect.Parameter.empty,
                    annotation=flag.annotation,
                )
                pseudo = replace_parameter(flag_param, flag.annotation,
                                           callback, original, mapping)
                if name in mapping:
                    raise TypeError(
                        f'{name!r} flag would shadow a pre-existing parameter')
                if flag.description is not MISSING:
                    descriptions[name] = flag.description
                if flag.name != flag.attribute:
                    renames[name] = flag.name

                mapping[name] = pseudo

            # Manually call the decorators
            if descriptions:
                app_commands.describe(**descriptions)(callback)
            if renames:
                app_commands.rename(**renames)(callback)

        elif is_converter(converter) or converter in CONVERTER_MAPPING:
            param = param.replace(
                annotation=make_converter_transformer(converter, original))
        elif origin is Union:
            if len(args) == 2 and args[-1] is _NoneType:
                # Special case Optional[X] where X is a single type that can optionally be a converter
                inner = args[0]
                is_inner_tranformer = is_transformer(inner)
                if is_converter(inner) and not is_inner_tranformer:
                    param = param.replace(
                        annotation=Optional[make_converter_transformer(
                            inner, original)])  # type: ignore
            else:
                raise
        elif origin:
            # Unsupported typing.X annotation e.g. typing.Dict, typing.Tuple, typing.List, etc.
            raise
        elif callable(converter) and not inspect.isclass(converter):
            param_count = required_pos_arguments(converter)
            if param_count != 1:
                raise
            param = param.replace(
                annotation=make_callable_transformer(converter))

    return param
示例#11
0
def normalize_parameter(p: inspect.Parameter):
    """Instantiate any ConcreteType classes found in this parameter annotation"""
    return p.replace(annotation=normalize_type(p.annotation))