Example #1
0
def test_userdefn_inheritance_multilevel(draw=False):
    src = """
    class A:
        pass

    class B(A):
        pass

    class C(B):
        pass

    a = A()
    b = B()
    c = C()
    """
    ast_mod, ti = cs._parse_text(src, reset=True)
    tc = ti.type_constraints
    a, b, c = [
        ti.lookup_typevar(node, node.name)
        for node in ast_mod.nodes_of_class(nodes.AssignName)
    ]

    assert tc.unify(b, a).getValue() == ForwardRef("B")
    assert tc.unify(c, b).getValue() == ForwardRef("C")
    assert tc.unify(c, a).getValue() == ForwardRef("C")
    assert isinstance(ti.type_constraints.unify(b, c), TypeFail)

    if draw:
        gen_graph_from_nodes(tc._nodes)
Example #2
0
def resolve_annotations(raw_annotations: Dict[str, AnyType],
                        module_name: Optional[str]) -> Dict[str, AnyType]:
    """
    Partially taken from typing.get_type_hints.

    Resolve string or ForwardRef annotations into type objects if possible.
    """
    if module_name:
        base_globals: Optional[Dict[str,
                                    Any]] = sys.modules[module_name].__dict__
    else:
        base_globals = None
    annotations = {}
    for name, value in raw_annotations.items():
        if isinstance(value, str):
            if sys.version_info >= (3, 7):
                value = ForwardRef(value, is_argument=False)
            else:
                value = ForwardRef(value)
        try:
            value = _eval_type(value, base_globals, None)
        except NameError:
            # this is ok, it can be fixed with update_forward_refs
            pass
        annotations[name] = value
    return annotations
Example #3
0
 def test_fields(self):
     """Test fields()."""
     self.assertEqual(fields(self.e),
                      dict(g=Tuple[self.NT], h=List[ForwardRef('Epsilon')]))
     self.assertEqual(
         fields(self.e, True),
         dict(g=Tuple[self.NT], h=List[ForwardRef('Epsilon')], _i=int))
Example #4
0
def resolve_annotations(raw_annotations: Dict[str, Type[Any]],
                        module_name: Optional[str]) -> Dict[str, Type[Any]]:
    """
    Partially taken from typing.get_type_hints.

    Resolve string or ForwardRef annotations into type objects if possible.
    """
    base_globals: Optional[Dict[str, Any]] = None
    if module_name:
        try:
            module = sys.modules[module_name]
        except KeyError:
            # happens occasionally, see https://github.com/samuelcolvin/pydantic/issues/2363
            pass
        else:
            base_globals = module.__dict__

    annotations = {}
    for name, value in raw_annotations.items():
        if isinstance(value, str):
            if sys.version_info >= (3, 7):
                value = ForwardRef(value, is_argument=False)
            else:
                value = ForwardRef(value)
        try:
            value = _eval_type(value, base_globals, None)
        except NameError:
            # this is ok, it can be fixed with update_forward_refs
            pass
        annotations[name] = value
    return annotations
    def visit_functiondef(self, node: astroid.FunctionDef) -> None:
        node.inf_type = NoType()

        # Get the inferred type of the function arguments
        inferred_args = [
            self.lookup_inf_type(node, arg) for arg in node.argnames()
        ]

        if isinstance(node.parent, astroid.ClassDef) and inferred_args:
            # first argument is special in these cases
            if node.type == 'method':
                self.type_constraints.unify(inferred_args[0],
                                            ForwardRef(node.parent.name), node)
            elif node.type == 'classmethod':
                self.type_constraints.unify(inferred_args[0],
                                            Type[ForwardRef(node.parent.name)],
                                            node)

        # Get inferred return type
        if any(node.nodes_of_class(astroid.Return)):
            return_node = list(node.nodes_of_class(astroid.Return))[-1]
            if isinstance(return_node.inf_type, TypeFail):
                inferred_return = return_node.inf_type
            else:
                inferred_return = self.lookup_inf_type(node, 'return')
        elif node.name == '__init__' and inferred_args:
            inferred_return = inferred_args[0]
        else:
            inferred_return = TypeInfo(type(None))

        # Update the environment storing the function's type.
        polymorphic_tvars = set()
        for arg in inferred_args + [inferred_return]:
            arg >> (lambda a: polymorphic_tvars.add(a.__name__)
                    if isinstance(a, TypeVar) else None)

        # Create function signature
        func_type = create_Callable_TypeResult(failable_collect(inferred_args),
                                               inferred_return,
                                               polymorphic_tvars)

        # Check for optional arguments, create a Union of function signatures if necessary
        num_defaults = len(node.args.defaults)
        if num_defaults > 0 and not isinstance(func_type, TypeFail):
            for i in range(num_defaults):
                opt_args = inferred_args[:-1 - i]
                opt_func_type = create_Callable_TypeResult(
                    failable_collect(opt_args), inferred_return,
                    polymorphic_tvars)
                func_type = func_type >> (
                    lambda f: opt_func_type >>
                    (lambda opt_f: TypeInfo(Union[f, opt_f])))

        # Final type signature unify
        func_name = self.lookup_inf_type(node.parent, node.name)
        result = self.type_constraints.unify(func_name, func_type, node)
        if isinstance(result, TypeFail):
            node.inf_type = result
Example #6
0
def test_forward_ref(draw=False):
    tc.reset()
    t0 = tc.fresh_tvar()
    assert isinstance(tc.unify(ForwardRef("A"), ForwardRef("B")), TypeFail)
    assert tc.unify(ForwardRef("A"),
                    ForwardRef("A")).getValue() == ForwardRef("A")
    assert tc.unify(t0, ForwardRef("A")).getValue() == ForwardRef("A")
    actual_set = tc_to_disjoint(tc)
    expected_set = [{"~_TV0", ForwardRef("A")}, {ForwardRef("B")}]
    compare_list_sets(actual_set, expected_set)
    if draw:
        gen_graph_from_nodes(tc._nodes)
Example #7
0
def GetValueTypeImpl(type_: Hashable, parentClass: Type[Any]) -> Type[Any]:
    """Returns the actual type if type_ is a string."""

    if isinstance(type_, type):
        return type_

    if not isinstance(type_, str):
        raise ValueError("Bad type argument: {}".format(type_))

    forwardRef = ForwardRef(type_, is_argument=False)

    # pylint: disable=protected-access
    evaluated = forwardRef._evaluate(GetClassNamespace_(parentClass), None)

    if evaluated is None:
        raise RuntimeError("Unable to resolve type {}".format(type_))

    if isinstance(evaluated, typing._GenericAlias):  # type: ignore
        if isinstance(evaluated.__args__[0],
                      typing._GenericAlias):  # type: ignore
            # Now use the origin to retrieve the default value type.
            return evaluated.__args__[0].__origin__

        return evaluated.__args__[0]

    return evaluated
Example #8
0
def get_class_type_hints_strict(
        cls: type,
        globalns: Mapping[str, Any] = None,
        localns: Mapping[str, Any] = None) -> Dict[str, type]:
    if not inspect.isclass(cls):
        raise TypeError(
            "cls needs to be a class. Use typing.get_type_hints for other types"
        )

    if globalns is None:
        globalns = sys.modules[cls.__module__].__dict__

    ann = cls.__dict__.get("__annotations__", {})

    hints = {}

    for name, value in ann.items():
        if value is None:
            value = type(None)
        if isinstance(value, str):
            value = ForwardRef(value, is_argument=False)

        value = _eval_type(value, globalns, localns)
        hints[name] = value

    return hints
Example #9
0
        def cache_decorator(field: ForwardRef('DiktField'),
                            instance: SupportsItemAssignment,
                            objtype: MutableMapping = None) -> _T:
            if field.cached_value is not UNSET:
                # print('DiktField returning cached')
                return field.cached_value
            try:
                rv = __get__(field, instance, objtype)
            except UnsetFieldError as uf:
                try:
                    rv = instance[field.name]
                except (KeyError, TypeError) as key_or_typeerror:
                    if isinstance(
                            key_or_typeerror, TypeError
                    ) and 'does not support item assignment' not in str(
                            key_or_typeerror):
                        import logging
                        logging.warning(
                            f"TypeError not because item assignment: {key_or_typeerror}"
                        )
                    raise uf from None

            field.cached_value = rv
            instance[field.name] = rv
            return rv
Example #10
0
def add_variable_subtype(T: type):
    """
    Libraries can add types (e.g. PyMC random vars)
    which should also be recognized as Theano variables.
    Subtypes added later have higher precedence, and all sutypes have precedence
    over the default TheanoVariable.

    All subtypes must be added is forward refs (i.e. strings).
    Once they are defined, call `update_forward_refs` with the types themselves.
    """
    # global theano_variable_subtypes
    global subtype_namespace
    global TheanoApplyData
    assert isinstance(T, type)
    Tname = T.__name__
    # Update the forward ref in TheanoApplydata
    oldt = TheanoApplyData.__fields__['inputs'].type_
    if not isinstance(oldt, ForwardRef):
        raise RuntimeError("Theano types have already been frozen: cannot "
                           "add new subtypes.")
    oldt_str = oldt.__forward_arg__
    assert oldt_str.startswith('Union[') and oldt_str.endswith(']')
    newt = ForwardRef(f"{oldt_str[:6]}{Tname},{oldt_str[6:]}")
    TheanoApplyData.__fields__['inputs'].type_ = newt
    # Add type to the namespace, so it can be found when forward refs are replaced by types
    subtype_namespace[Tname] = T
Example #11
0
    def _init_obj(self) -> None:
        annotation_dict: Dict[str, Tuple[Any, ...]] = {}
        for key in self.__annotations__:
            if key != key.upper():
                class_name: str = self.__class__.__name__
                raise KeyError(f"key: {class_name}.{key} must like {class_name}.{key.upper()}")

            default_value: Any = getattr(self, key, ...)
            annotation: Union[str, Type] = self.__annotations__[key]
            if isinstance(annotation, str):
                value: ForwardRef = ForwardRef(annotation, is_argument=False)
                annotation = value._evaluate(sys.modules[self.__module__].__dict__, None)  # type: ignore

            if isinstance(default_value, Json) and key in self._config_dict:
                self._config_dict[key] = json.loads(self._config_dict[key])

            if key not in self._config_dict:
                self._config_dict[key] = default_value

            annotation_dict[key] = (annotation, ... if not isinstance(default_value, FieldInfo) else default_value)

        dynamic_model: Type[BaseModel] = create_model(
            "DynamicModel",
            __config__=None,
            __base__=None,
            __module__="pydantic.main",
            __validators__=None,
            **annotation_dict,
        )
        self._model = dynamic_model(**self._config_dict)
        self.__dict__.update(self._model.dict())
Example #12
0
def literal_substitute(t: type, type_map: Dict[str, type]) -> type:
    """Make substitutions in t according to type_map, returning resulting type."""
    if isinstance(t, TypeVar) and t.__name__ in type_map:
        return type_map[t.__name__]
    elif isinstance(t, TypeVar):
        return TypeVar(t.__name__)
    elif isinstance(t, ForwardRef):
        return ForwardRef(literal_substitute(t.__forward_arg__, type_map))
    elif isinstance(t, TuplePlus):
        subbed_args = [
            literal_substitute(t1, type_map) for t1 in t.__constraints__
        ]
        return TuplePlus("tup+", *subbed_args)
    elif is_callable(t):
        args = list(literal_substitute(t1, type_map) for t1 in t.__args__[:-1])
        res = literal_substitute(t.__args__[-1], type_map)
        new_t = Callable[args, res]
        if hasattr(t, "__polymorphic_tvars__"):
            new_t.__polymorphic_tvars__ = t.__polymorphic_tvars__.copy()
        return new_t
    elif isinstance(t, _GenericAlias) and t.__args__ is not None:
        return t.copy_with(
            tuple(literal_substitute(t1, type_map) for t1 in t.__args__))
    else:
        return t
Example #13
0
def _evaluate_forwardref(type_: Any) -> Any:
    """Convert typing.ForwardRef into an actual object."""
    if isinstance(type_, str):
        type_ = ForwardRef(type_)

    if not isinstance(type_, ForwardRef):
        return type_

    from importlib import import_module

    try:
        _module = type_.__forward_arg__.split(".", maxsplit=1)[0]
        globalns = globals().copy()
        globalns.update({_module: import_module(_module)})
    except ImportError as e:
        raise ImportError(
            "Could not resolve the magicgui forward reference annotation: "
            f"{type_.__forward_arg__!r}."
        ) from e

    if sys.version_info < (3, 9):
        return type_._evaluate(globalns, {})
    # Even though it is the right signature for python 3.9, mypy complains with
    # `error: Too many arguments for "_evaluate" of "ForwardRef"` hence the cast...
    return cast(Any, type_)._evaluate(globalns, {}, set())
Example #14
0
    def __getitem__(self, param):
        if param is None:
            raise TypeError('{}[t]: t can not be None'.format(self.__name__))
        if isinstance(param, str):
            param = ForwardRef(param)
        if isinstance(param, tuple):
            param = Tuple[param]
        _type_check(param, msg="{}[t]: t must be a type".format(self.__name__))
        t = _DataPipeType(param)

        if not t.issubtype(self.type):
            raise TypeError(
                'Can not subclass a DataPipe[{}] from DataPipe[{}]'.format(
                    t, self.type))

        # Types are equal, fast path for inheritance
        if self.type.issubtype(t):
            if _mro_subclass_init(self):
                return self

        name = self.__name__ + '[' + str(t) + ']'
        bases = (self, ) + self.__bases__

        return self.__class__(
            name, bases, {
                '__init_subclass__': _dp_init_subclass,
                '__type_class__': True,
                'type': t
            })
Example #15
0
def _fields(annotations: Dict[str, type], result: Dict[str, type]):
    for key, value in annotations.items():
        if key.startswith('_') or get_origin(value) is ClassVar:
            continue
        if isinstance(value, str):
            value = ForwardRef(value)
        result[key] = value
Example #16
0
def _replace_models_with_forward_references(
        type_: Type, naming: ModelNameMakerFunction) -> Type:
    """ Walk the arguments of `type_` and replace every possible reference to any SqlAlchemy model """
    # SqlAlchemy model
    if is_sa_mapped_class(type_):
        return ForwardRef(naming(type_))
    # typing.Optional[], typing.Union[], and other subscriptable types
    elif isinstance(type_, typing._GenericAlias):
        # type_: List[models.User]
        # original_type: list
        # original_args: (models.User,)
        original_type, type_args = get_origin(type_), get_args(type_)

        # try to normalize it:
        # convert type_=list to type_=typing.List
        try:
            original_type = getattr(
                typing, typing._normalize_alias[original_type.__name__])
        except (KeyError, AttributeError) as e:
            pass

        # Recurse: convert every argument
        arghs = tuple(
            _replace_models_with_forward_references(t, naming)
            for t in type_args)

        # Reconstruct
        return original_type[arghs]
    else:
        return type_
def get_class_type_hints(klass: Type, localns=None) -> Dict[str, Any]:
    """Return type hints for a class. Adapted from `typing.get_type_hints`, adds support for PEP 585 & PEP 604"""
    hints = {}
    for base in reversed(klass.__mro__):
        base_globals = sys.modules[base.__module__].__dict__
        base_globals['_Union'] = Union
        if sys.version_info < (3, 9):
            base_globals['_List'] = List
            base_globals['_Set'] = Set
            base_globals['_Type'] = Type
            base_globals['_Tuple'] = Tuple
            base_globals['_Dict'] = Dict
        ann = base.__dict__.get('__annotations__', {})
        for name, value in ann.items():
            if value is None:
                value = type(None)
            if isinstance(value, str):
                t = ast.parse(value, '<unknown>', 'eval')
                union_transformer = RewriteUnionTypes()
                t = union_transformer.visit(t)
                builtin_generics_transformer = RewriteBuiltinGenerics()
                if sys.version_info < (3, 9):
                    t = builtin_generics_transformer.visit(t)
                if builtin_generics_transformer.rewritten or union_transformer.rewritten:
                    # Note: ForwardRef raises a TypeError when given anything that isn't a string, so we need
                    # to compile & eval the ast here
                    code = compile(t, '<unknown>', 'eval')
                    hints[name] = eval(code, base_globals, localns)
                    continue
                else:
                    value = ForwardRef(value, is_argument=False)
            value = _eval_type(value, base_globals, localns)
            hints[name] = value
    return hints
 def test_is_forwardref(self):
     try:
         # Since 3.7
         from typing import ForwardRef  # type: ignore
     except ImportError:
         from typing import _ForwardRef as ForwardRef  # type: ignore
     assert typechecks.is_forwardref(ForwardRef('SomeType'))
Example #19
0
def get_typed_annotation(param: inspect.Parameter,
                         globalns: t.Dict[str, t.Any]) -> t.Any:
    annotation = param.annotation
    if isinstance(annotation, str):
        annotation = ForwardRef(annotation)
        annotation = evaluate_forwardref(annotation, globalns, globalns)
    return annotation
Example #20
0
 def init_many(*msgs: dict) -> List[ForwardRef('Message')]:
     constructed = []
     for i, m in enumerate(msgs):
         if 'preceding_message_time' not in m:
             if i != 0:
                 m.update(preceding_message_time=msgs[i - 1]['time'])
         constructed.append(Message.init(**m))
     return constructed
Example #21
0
 def cache_decorator(field: ForwardRef('Field'),
                     instance: Instance,
                     objtype: Type[Instance] = None) -> _T:
     if field.cached_value is not UNSET:
         return field.cached_value
     rv = __get__(field, instance, objtype)
     field.cached_value = rv
     return rv
 def _get_typed_annotation(self, param: inspect.Parameter,
                           globalns: Dict[str, Any]) -> Any:
     try:
         if isinstance(param.annotation, str):
             return _eval_type(ForwardRef(param.annotation), globalns,
                               globalns)
         else:
             return param.annotation
     except Exception:
         return param.annotation
Example #23
0
    def _maybe_bind_forward(self, cls: Binding, binding: Any) -> None:
        """Bind a string forward reference."""
        if not _NEW_TYPING:
            return
        if not isinstance(cls, str):
            return

        ref = ForwardRef(cls)
        self._bindings[ref] = binding
        logger.debug('Bound forward ref "%s"', cls)
class BattleStationConfig:
    @dataclass
    class Processor:
        core_count: int
        manufacturer: str

    processor: ForwardRef("Processor")
    memory_gb: int
    led_color: Optional["Color"] = field(default=None,
                                         metadata={"by_value": True})
Example #25
0
 def __init__(self,
              parent: ForwardRef('RabbitmqPlugins'),
              plugin: str = ''):
     super(EnablePlugin, self).__init__('enable', parent)
     if plugin:
         self._plugins = {
             plugin,
         }
     else:
         self._plugins = set()
Example #26
0
def _eval_type(type: Any, globals: Dict[str, Any]) -> Any:
    """Evaluate all forward reverences in the given type."""
    if isinstance(type, str):
        type = ForwardRef(type)
    if isinstance(type, ForwardRef):
        return type._evaluate(globals, {})
    if isinstance(type, _GenericAlias):
        args = tuple(_eval_type(arg, globals) for arg in get_args(type))
        return get_origin(type)[args]
    return type
Example #27
0
def _clean_annotations(annotated):
    if annotated.__annotations__ == {}:
        for varname in annotated.__code__.co_varnames:
            if varname != "self":
                yield varname, Any
    else:
        for name, value in annotated.__annotations__.items():
            if isinstance(value, str):
                yield name, ForwardRef(value)
            else:
                yield name, value
Example #28
0
    def _check_class(self, cls: Binding) -> None:
        if cls is None:
            raise InjectorException('Binding key cannot be None')

        if cls in self._bindings:
            raise InjectorException('Duplicate binding, key=%s' % cls)

        if self._is_forward_str(cls):
            ref = ForwardRef(cls)
            if ref in self._bindings:
                raise InjectorException('Duplicate forward binding, i.e. "int" and int, key=%s', cls)
def test_functiondef_method():
    program = \
        '''
        class A:

            def method(self, x):
                return x + 1
        '''
    module, inferer = cs._parse_text(program)
    for func_def in module.nodes_of_class(astroid.FunctionDef):
        assert lookup_type(inferer, func_def, func_def.argnames()[0]) == ForwardRef('A')
 def _set_function_def_environment(self, node: astroid.FunctionDef) -> None:
     """Method to set environment of a FunctionDef node."""
     node.type_environment = Environment()
     # self is a special case
     if node.args.args and node.args.args[0].name == 'self' and isinstance(
             node.parent, astroid.ClassDef):
         node.type_environment.locals['self'] = ForwardRef(node.parent.name)
     self._populate_local_env(node)
     self._populate_local_env_attrs(node)
     node.type_environment.locals[
         'return'] = self.type_constraints.fresh_tvar(node)