def _node_to_type(node, locals=None): """Return a type represented by the input node.""" locals = locals or _TYPESHED_TVARS if node is None: return Any elif isinstance(node, str): try: return eval(node, globals(), locals) except: return _ForwardRef(node) elif isinstance(node, astroid.Name): try: return eval(node.name, globals(), locals) except: return _ForwardRef(node.name) elif isinstance(node, astroid.Subscript): v = _node_to_type(node.value) s = _node_to_type(node.slice) return v[s] elif isinstance(node, astroid.Index): return _node_to_type(node.value) elif isinstance(node, astroid.Tuple): return tuple(_node_to_type(t) for t in node.elts if not isinstance(t, astroid.Ellipsis)) elif isinstance(node, astroid.List): return [_node_to_type(t) for t in node.elts if not isinstance(t, astroid.Ellipsis)] elif isinstance(node, astroid.Const) and node.value is None: return None else: return node
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(astroid.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 visit_call(self, node): if isinstance(node.func, astroid.Attribute): func_t = node.func.type_constraints.type arg_types = [self.lookup_type(node.func.expr, node.func.expr.name)] arg_types += [arg.type_constraints.type for arg in node.args] ret_type = self.type_constraints.unify_call(func_t, *arg_types, node=node) node.type_constraints = TypeInfo(ret_type) else: func_name = node.func.name if isinstance(node.frame().locals.get(func_name)[0], astroid.ClassDef): func_t = self.type_constraints \ .lookup_concrete(node.frame().locals[func_name][0].type_environment.locals['__init__']) arg_types = [_ForwardRef(func_name)] + [ arg.type_constraints.type for arg in node.args ] self.type_constraints.unify_call(func_t, *arg_types) node.type_constraints = TypeInfo(_ForwardRef(func_name)) else: func_t = self.lookup_type(node, func_name) arg_types = [arg.type_constraints.type for arg in node.args] ret_type = self.type_constraints.unify_call(func_t, *arg_types, node=node) node.type_constraints = TypeInfo(ret_type)
def _node_to_type(node, locals=None): """Return a type represented by the input node.""" locals = locals or _TYPESHED_TVARS if node is None: return Any elif isinstance(node, str): try: return eval(node, globals(), locals) except: return _ForwardRef(node) elif isinstance(node, astroid.Name): try: return eval(node.name, globals(), locals) except: return _ForwardRef(node.name) elif isinstance(node, astroid.Subscript): v = _node_to_type(node.value) s = _node_to_type(node.slice) return v[s] elif isinstance(node, astroid.Index): return _node_to_type(node.value) elif isinstance(node, astroid.Tuple): return tuple( _node_to_type(t) for t in node.elts if not isinstance(t, astroid.Ellipsis)) elif isinstance(node, astroid.List): return [ _node_to_type(t) for t in node.elts if not isinstance(t, astroid.Ellipsis) ] elif isinstance(node, astroid.Const) and node.value is None: return None else: return node
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 = [] for arg in inferred_args + [inferred_return]: arg >> (lambda a: polymorphic_tvars.append(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 visit_functiondef(self, node): arg_types = [self.lookup_type(node, arg) for arg in node.argnames()] if any(annotation is not None for annotation in node.args.annotations): func_type = parse_annotations(node) for arg_type, annotation in zip(arg_types, func_type.__args__[:-1]): self.type_constraints.unify(arg_type, annotation) self.type_constraints.unify( self.lookup_type(node.parent, node.name), func_type) else: # Check whether this is a method in a class if isinstance(node.parent, astroid.ClassDef) and isinstance( arg_types[0], TypeVar): self.type_constraints.unify(arg_types[0], _ForwardRef(node.parent.name), node) # check if return nodes exist; there is a return statement in function body. polymorphic_tvars = [ arg for arg in arg_types if isinstance(arg, TypeVar) ] if len(list(node.nodes_of_class(astroid.Return))) == 0: func_type = create_Callable(arg_types, None, polymorphic_tvars) else: rtype = self.type_constraints.lookup_concrete( node.type_environment.lookup_in_env('return')) func_type = create_Callable(arg_types, rtype, polymorphic_tvars) self.type_constraints.unify( self.lookup_type(node.parent, node.name), func_type) node.type_constraints = TypeInfo(NoType)
def visit_functiondef(self, node): arg_types = [ self.type_constraints.lookup_concrete( node.type_environment.lookup_in_env(arg)) for arg in node.argnames() ] # Check whether this is a method in a class if isinstance(node.parent, astroid.ClassDef) and isinstance( arg_types[0], TypeVar): self.type_constraints.unify(arg_types[0], _ForwardRef(node.parent.name)) # check if return nodes exist; there is a return statement in function body. if len(list(node.nodes_of_class(astroid.Return))) == 0: func_type = Callable[arg_types, None] else: rtype = self.type_constraints.lookup_concrete( node.type_environment.lookup_in_env('return')) func_type = Callable[arg_types, rtype] func_type.polymorphic_tvars = [ arg for arg in arg_types if isinstance(arg, TypeVar) ] self.type_constraints.unify( node.parent.frame().type_environment.lookup_in_env(node.name), func_type) node.type_constraints = TypeInfo(NoType)
def test_ptype_typing_mapping(): class A: pass # `Union`: assert ptype(typing.Union[typing.Union[int], list]) == Union[Union[int], list] assert ptype(typing.Union) == Union[object] # `Optional`: assert ptype(typing.Optional[int]) == Union[int, type(None)] assert ptype(typing.Optional) == Union[object] # `List`: assert ptype(typing.List[typing.List[int]]) == List[List[int]] assert ptype(typing.List) == Type(list) # `Tuple`: assert ptype(typing.Tuple[typing.Tuple[int], list]) == Tuple[Tuple[int], list] assert ptype(typing.Tuple) == Type(tuple) # `Dict`: assert ptype(typing.Dict[typing.List[int], list]) == Dict[List[int], list] assert ptype(typing.Dict) == Type(dict) # `Iterable`: assert ptype(typing.Iterable[typing.List[int]]) == Iterable[List[int]] assert ptype(typing.Iterable) == Iterable() # `Sequence`: assert ptype(typing.Sequence[typing.List[int]]) == Sequence[List[int]] assert ptype(typing.Sequence) == Sequence() # `ForwardRef`: if hasattr(typing, "ForwardRef"): t = ptype(typing.ForwardRef("A")) else: # The `typing` package is different for Python 3.6. t = ptype(typing._ForwardRef("A")) deliver_forward_reference(A) assert t == Type(A) # `Any`: assert ptype(typing.Any) == ptype(object) # `Callable`: assert ptype(typing.Callable) == Type(typing.Callable) # Check propagation of conversion of strings. t = ptype(typing.Union["A"]) deliver_forward_reference(A) assert t == ptype(Union[A]) t = ptype(typing.List["A"]) deliver_forward_reference(A) assert t == ptype(List[A]) t = ptype(typing.Tuple["A"]) deliver_forward_reference(A) assert t == ptype(Tuple[A])
def _set_function_def_environment(self, node): """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) node.type_environment.locals['return'] = self.type_constraints.fresh_tvar(node)
def visit_call(self, node): func_name = node.func.name if isinstance(node.frame().locals.get(func_name)[0], astroid.ClassDef): # This is the constructor of a class func_t = self.type_constraints.lookup_concrete( node.frame().locals[func_name] [0].type_environment.locals['__init__']) arg_types = [_ForwardRef(func_name) ] + [arg.type_constraints.type for arg in node.args] self.type_constraints.unify_call(func_t, *arg_types) node.type_constraints = TypeInfo(_ForwardRef(func_name)) else: func_t = self.type_constraints.lookup_concrete( node.frame().type_environment.locals[func_name]) arg_types = [arg.type_constraints.type for arg in node.args] ret_type = self.type_constraints.unify_call(func_t, *arg_types) node.type_constraints = TypeInfo(ret_type)
def visit_call(self, node): if isinstance(node.func, astroid.Attribute): func_t = node.func.type_constraints.type arg_types = [self.lookup_type(node.func.expr, node.func.expr.name)] arg_types += [arg.type_constraints.type for arg in node.args] ret_type = self.type_constraints.unify_call(func_t, *arg_types, node=node) node.type_constraints = TypeInfo(ret_type) else: func_name = node.func.name if isinstance(node.frame().locals.get(func_name)[0], astroid.ClassDef): func_t = self.type_constraints \ .lookup_concrete(node.frame().locals[func_name][0].type_environment.locals['__init__']) arg_types = [_ForwardRef(func_name)] + [arg.type_constraints.type for arg in node.args] self.type_constraints.unify_call(func_t, *arg_types) node.type_constraints = TypeInfo(_ForwardRef(func_name)) else: func_t = self.lookup_type(node, func_name) arg_types = [arg.type_constraints.type for arg in node.args] ret_type = self.type_constraints.unify_call(func_t, *arg_types, node=node) node.type_constraints = TypeInfo(ret_type)
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 test_class_without_init(): program = """ class Foo: def fee(self): return 1 foo = Foo() """ ast_mod, ti = cs._parse_text(program) for call_node in ast_mod.nodes_of_class(astroid.Call): assert isinstance(call_node.inf_type.getValue(), _ForwardRef) eq_(call_node.inf_type.getValue(), _ForwardRef('Foo'))
def visit_classdef(self, node: astroid.ClassDef) -> None: node.inf_type = TypeInfo(NoType) self.type_constraints.unify(self.lookup_type(node.parent, node.name), _ForwardRef(node.name), node) # Update type_store for this class. # TODO: include node.instance_attrs as well? for attr in node.locals: attr_type = self.type_constraints.resolve( node.type_environment.lookup_in_env(attr)).getValue() self.type_store.classes[node.name][attr].append(attr_type) if isinstance(attr_type, CallableMeta): self.type_store.methods[attr].append(attr_type)
def visit_classdef(self, node: astroid.ClassDef) -> None: node.inf_type = NoType() self.type_constraints.unify(self.lookup_inf_type(node.parent, node.name), Type[_ForwardRef(node.name)], node) # Update type_store for this class. # TODO: include node.instance_attrs as well? for attr in node.locals: attr_inf_type = self.type_constraints.resolve(node.type_environment.lookup_in_env(attr)) attr_inf_type >> ( lambda a: self.type_store.methods[attr].append((a, node.locals[attr][0].type)) if isinstance(a, CallableMeta) else None) attr_inf_type >> ( lambda a: self.type_store.classes[node.name][attr].append((a, node.locals[attr][0].type if isinstance(a, CallableMeta) else 'attribute')))
def test_class_dot_method(): program = \ ''' class A: def foo(self, x): return x + 1 A.foo(A(), 0) ''' module, _ = cs._parse_text(program, reset=True) for attribute_node in module.nodes_of_class(astroid.Attribute): assert attribute_node.inf_type.getValue() == Callable[ [_ForwardRef('A'), int], int]
def _set_module_environment(self, node: astroid.Module) -> None: """Method to set environment of a Module node.""" node.type_environment = Environment() for name in node.globals: if not any( isinstance(elt, (astroid.ImportFrom, astroid.Import)) for elt in node.globals[name]): new_tvar = self.type_constraints.fresh_tvar( node.globals[name][0]) if any( isinstance(elt, astroid.ClassDef) for elt in node.globals[name]): self.type_constraints.unify(new_tvar, Type[_ForwardRef(name)], node) node.type_environment.globals[name] = new_tvar self._populate_local_env(node)
def test_userdefn_inheritance_simple(draw=False): src = """ class A: pass class B: pass class C(A, 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(astroid.AssignName) ] assert isinstance(tc.unify(a, b), TypeFail) assert tc.unify(c, a).getValue() == _ForwardRef('C') assert isinstance(tc.unify(a, c), TypeFail) # note that order matters! assert tc.unify(c, b).getValue() == _ForwardRef('C') assert isinstance(tc.unify(b, c), TypeFail) actual_set = tc_to_disjoint(tc) expected_set = [{'~_T0', Type[_ForwardRef('A')]}, {'~_T1', Type[_ForwardRef('B')]}, {'~_T2', Type[_ForwardRef('C')]}, {'~_T3', _ForwardRef('A')}, {'~_T4', _ForwardRef('B')}, {'~_T5', _ForwardRef('C')}] # _TNodes should be unchanged after unification compare_list_sets(actual_set, expected_set) if draw: gen_graph_from_nodes(tc._nodes)
def visit_functiondef(self, node): arg_types = [self.lookup_type(node, arg) for arg in node.argnames()] if any(annotation is not None for annotation in node.args.annotations): func_type = parse_annotations(node) for arg_type, annotation in zip(arg_types, func_type.__args__[:-1]): self.type_constraints.unify(arg_type, annotation) self.type_constraints.unify(self.lookup_type(node.parent, node.name), func_type) else: # Check whether this is a method in a class if isinstance(node.parent, astroid.ClassDef) and isinstance(arg_types[0], TypeVar): self.type_constraints.unify(arg_types[0], _ForwardRef(node.parent.name), node) # check if return nodes exist; there is a return statement in function body. polymorphic_tvars = [arg for arg in arg_types if isinstance(arg, TypeVar)] if len(list(node.nodes_of_class(astroid.Return))) == 0: func_type = create_Callable(arg_types, None, polymorphic_tvars) else: rtype = self.type_constraints.lookup_concrete(node.type_environment.lookup_in_env('return')) func_type = create_Callable(arg_types, rtype, polymorphic_tvars) self.type_constraints.unify(self.lookup_type(node.parent, node.name), func_type) node.type_constraints = TypeInfo(NoType)
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 isinstance(t, CallableMeta): 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 return new_t elif isinstance(t, GenericMeta) and t.__args__ is not None: return _gorg(t)[tuple(literal_substitute(t1, type_map) for t1 in t.__args__)] else: return t
def _evaluate(self, globalns: Dict, localns: Dict) -> Any: ref = _ForwardRef(self.arg) return ref._eval_type(globalns, localns)
def visit_functiondef(self, node: astroid.FunctionDef) -> None: node.inf_type = TypeInfo(NoType) # Get the inferred type of the function. inferred_args = [ self.lookup_type(node, arg) for arg in node.argnames() ] if isinstance(node.parent, astroid.ClassDef) and isinstance( inferred_args[0], TypeVar): # 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) if any(node.nodes_of_class(astroid.Return)): inferred_return = self.type_constraints.resolve( node.type_environment.lookup_in_env('return')).getValue() else: inferred_return = type(None) # Get any function type annotations. if any(annotation is not None for annotation in node.args.annotations): annotated_type = parse_annotations(node) else: annotated_type = None # Combine inferred and annotated types. if annotated_type: combined_args = [] for inferred, annotated in zip(inferred_args, annotated_type.__args__[:-1]): if annotated is None: annotated = type(None) t = self.type_constraints.unify(inferred, annotated, node).getValue() combined_args.append(t) annotated_rtype = annotated_type.__args__[-1] if annotated_rtype is None: annotated_rtype = type(None) combined_return = self.type_constraints.unify( inferred_return, annotated_rtype, node).getValue() else: combined_args, combined_return = inferred_args, inferred_return # Update the environment storing the function's type. polymorphic_tvars = [ arg for arg in combined_args if isinstance(arg, TypeVar) ] func_type = create_Callable(combined_args, combined_return, polymorphic_tvars) num_defaults = len(node.args.defaults) if num_defaults > 0: for i in range(num_defaults): opt_args = inferred_args[:-1 - i] opt_func_type = create_Callable(opt_args, combined_return, polymorphic_tvars) func_type = Union[func_type, opt_func_type] self.type_constraints.unify(self.lookup_type(node.parent, node.name), func_type, node)
def test_forwardref_instance_type_error(self): fr = typing._ForwardRef('int') with self.assertRaises(TypeError): isinstance(42, fr)
def ForwardRef(arg, is_argument): return _ForwardRef(arg)
# You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ============================================================================== """Haiku types.""" import typing from typing import Any, Callable, Mapping, Sequence import jax.numpy as jnp # pytype: disable=module-attr try: # Using PyType's experimental support for forward references. Module = typing._ForwardRef("haiku.Module") # pylint: disable=protected-access except AttributeError: Module = Any # pytype: enable=module-attr Initializer = Callable[[Sequence[int], Any], jnp.ndarray] Params = Mapping[str, Mapping[str, jnp.ndarray]] State = Mapping[str, Mapping[str, jnp.ndarray]] # Missing JAX types. PRNGKey = jnp.ndarray # pylint: disable=invalid-name
class STRING(JSGString): pattern = JSGPattern(r'.*') class STAR(JSGString): pattern = JSGPattern(r'\*') RDFLiteral = Union[SIMPLE_LITERAL, DATATYPE_LITERAL, LANG_LITERAL] numericLiteral = Union[INTEGER, DECIMAL, DOUBLE] shapeLabel = Union[IRI, BNODE] objectValue = Union[IRI, RDFLiteral] shapeExprT = _ForwardRef('shapeExpr') tripleExprT = _ForwardRef('tripleExpr') class Inclusion(JSGObject): def __init__(self, include: shapeLabel, **_: Dict[str, object]): JSGObject.__init__(self) self.include = include class stringFacet(JSGObject): def __init__(self, length: Optional[INTEGER] = None, minlength: Optional[INTEGER] = None, maxlength: Optional[INTEGER] = None, pattern: Optional[STRING] = None,
def make_forward_ref(s: str) -> type: return _ForwardRef(s)
# pyre-strict from __future__ import absolute_import, division, print_function, unicode_literals import os import signal from types import FrameType from typing import BinaryIO, Callable, Iterable, Mapping, Union, _ForwardRef JsonObject = Mapping[str, _ForwardRef("Json")] JsonArray = Iterable[_ForwardRef("Json")] JsonScalar = Union[str, int, float, bool, None] Json = Union[JsonObject, JsonArray, JsonScalar] VariableMap = Mapping[str, str] def touch(fn: str) -> None: with open(fn, "a"): os.utime(fn, None) def write_files(files: Mapping[str, str], dir_path: str) -> None: """ Write a bunch of files into the directory at dir_path. files: dict of file name => file contents """ for fn, content in files.items(): path = os.path.join(dir_path, fn)
def test_same_forward_ref(): fr1 = _ForwardRef('a') fr2 = _ForwardRef('a') unify_helper(fr1, fr2, fr1) unify_helper(fr1, fr2, fr2)
def test_one_forward_ref(): fr = _ForwardRef('a') unify_helper(fr, str, TypeFail("Attempted to unify forwardref with non-ref"))
def test_diff_forward_ref(): raise SkipTest('The existing error msg does not apply to this situation') fr1 = _ForwardRef('a') fr2 = _ForwardRef('b') unify_helper(fr1, fr2, TypeFail("Attempted to unify forwardref with non-ref"))