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)
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
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))
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
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)
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
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
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
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
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())
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
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())
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 })
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
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'))
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
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
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
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})
def __init__(self, parent: ForwardRef('RabbitmqPlugins'), plugin: str = ''): super(EnablePlugin, self).__init__('enable', parent) if plugin: self._plugins = { plugin, } else: self._plugins = set()
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
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
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)