def testVerifyContainers(self): ast1 = self.ParseWithBuiltins(""" from typing import SupportsInt, TypeVar T = TypeVar("T") class Foo(SupportsInt[T]): pass """) ast2 = self.ParseWithBuiltins(""" from typing import SupportsInt class Foo(SupportsInt[int]): pass """) ast3 = self.ParseWithBuiltins(""" from typing import Generic class Foo(Generic[int]): pass """) ast4 = self.ParseWithBuiltins(""" from typing import List class Foo(List[int, str]): pass """) self.assertRaises(visitors.ContainerError, lambda: ast1.Visit(visitors.VerifyContainers())) self.assertRaises(visitors.ContainerError, lambda: ast2.Visit(visitors.VerifyContainers())) self.assertRaises(visitors.ContainerError, lambda: ast3.Visit(visitors.VerifyContainers())) self.assertRaises(visitors.ContainerError, lambda: ast4.Visit(visitors.VerifyContainers()))
def testVerifyContainers(self): ast1 = self.ParseWithBuiltins(""" T = TypeVar("T") class Foo(SupportsInt[T]): pass """) ast2 = self.ParseWithBuiltins(""" class Foo(SupportsInt[int]): pass """) ast3 = self.ParseWithBuiltins(""" class Foo(Generic[int]): pass """) self.assertRaises(visitors.ContainerError, lambda: ast1.Visit(visitors.VerifyContainers())) self.assertRaises(visitors.ContainerError, lambda: ast2.Visit(visitors.VerifyContainers())) self.assertRaises(visitors.ContainerError, lambda: ast3.Visit(visitors.VerifyContainers()))
def testVerifyContainerWithMROError(self): # Make sure we don't crash. ast = self.ParseWithBuiltins(""" from typing import List class A(List[str]): ... class B(List[str], A): ... """) ast.Visit(visitors.VerifyContainers())
def testTypeVarValueNoConflict(self): # Not an error if the containers are unrelated, even if they use the same # type parameter name. ast = self.ParseWithBuiltins(""" from typing import ContextManager, SupportsAbs class Foo(SupportsAbs[float], ContextManager[Foo]): ... """) ast.Visit(visitors.VerifyContainers())
def testTypeVarValueConflictRelatedContainers(self): # List inherits from Sequence, so they share a type parameter. ast = self.ParseWithBuiltins(""" from typing import List, Sequence class A(List[int], Sequence[str]): ... """) self.assertRaises(visitors.ContainerError, lambda: ast.Visit(visitors.VerifyContainers()))
def testTypeVarValueConflict(self): # Conflicting values for _T. ast = self.ParseWithBuiltins(""" from typing import List class A(List[int], List[str]): ... """) self.assertRaises(visitors.ContainerError, lambda: ast.Visit(visitors.VerifyContainers()))
def testTypeVarAliasAndValueConflict(self): ast = self.ParseWithBuiltins(""" from typing import Generic, TypeVar T = TypeVar("T") class A(Generic[T]): ... class B(A[T], A[int]): ... """) self.assertRaises(visitors.ContainerError, lambda: ast.Visit(visitors.VerifyContainers()))
def GetBuiltinsAndTyping(python_version): """Get __builtin__.pytd and typing.pytd.""" assert python_version global _cached_builtins_pytd if _cached_builtins_pytd.cache: assert _cached_builtins_pytd.version == python_version else: t = parser.parse_string(_FindBuiltinFile("typing", python_version), name="typing", python_version=python_version) b = parser.parse_string(_FindBuiltinFile("__builtin__", python_version), name="__builtin__", python_version=python_version) b = b.Visit( visitors.LookupExternalTypes({"typing": t}, full_names=True, self_name="__builtin__")) t = t.Visit(visitors.LookupBuiltins(b)) b = b.Visit(visitors.NamedTypeToClassType()) t = t.Visit(visitors.NamedTypeToClassType()) b = b.Visit(visitors.AdjustTypeParameters()) t = t.Visit(visitors.AdjustTypeParameters()) b = b.Visit(visitors.CanonicalOrderingVisitor()) t = t.Visit(visitors.CanonicalOrderingVisitor()) b.Visit( visitors.FillInLocalPointers({ "": b, "typing": t, "__builtin__": b })) t.Visit( visitors.FillInLocalPointers({ "": t, "typing": t, "__builtin__": b })) b.Visit(visitors.VerifyLookup()) t.Visit(visitors.VerifyLookup()) b.Visit(visitors.VerifyContainers()) t.Visit(visitors.VerifyContainers()) _cached_builtins_pytd = Cache(python_version, (b, t)) return _cached_builtins_pytd.cache
def testVerifyHeterogeneousTuple(self): # Error: does not inherit from Generic base = pytd.ClassType("tuple") base.cls = pytd.Class("tuple", None, (), (), (), ()) t1 = pytd.TupleType(base, (pytd.NamedType("str"), pytd.NamedType("float"))) self.assertRaises(visitors.ContainerError, lambda: t1.Visit(visitors.VerifyContainers())) # Error: Generic[str, float] gen = pytd.ClassType("typing.Generic") gen.cls = pytd.Class("typing.Generic", None, (), (), (), ()) t2 = pytd.TupleType(gen, (pytd.NamedType("str"), pytd.NamedType("float"))) self.assertRaises(visitors.ContainerError, lambda: t2.Visit(visitors.VerifyContainers())) # Okay param = pytd.TypeParameter("T", None) parent = pytd.GenericType(gen, (param,)) base.cls = pytd.Class( "tuple", None, (parent,), (), (), (pytd.TemplateItem(param),)) t3 = pytd.TupleType(base, (pytd.NamedType("str"), pytd.NamedType("float"))) t3.Visit(visitors.VerifyContainers())
def GetBuiltinsAndTyping(): """Get __builtin__.pytd and typing.pytd.""" global _cached_builtins_pytd if not _cached_builtins_pytd: t = parser.TypeDeclParser().Parse(_FindBuiltinFile("typing"), name="typing") t = t.Visit(visitors.AddNamePrefix()) b = parser.TypeDeclParser().Parse(_FindBuiltinFile("__builtin__"), name="__builtin__") b = b.Visit(visitors.AddNamePrefix()) b = b.Visit(visitors.NamedTypeToClassType()) b = b.Visit( visitors.LookupExternalTypes({"typing": t}, full_names=True, self_name="__builtin__")) t = t.Visit(visitors.LookupBuiltins(b)) t = t.Visit(visitors.NamedTypeToClassType()) b = visitors.AdjustTypeParameters(b) t = visitors.AdjustTypeParameters(t) b.Visit( visitors.FillInModuleClasses({ "": b, "typing": t, "__builtin__": b })) t.Visit( visitors.FillInModuleClasses({ "": t, "typing": t, "__builtin__": b })) b.Visit(visitors.VerifyLookup()) t.Visit(visitors.VerifyLookup()) b.Visit(visitors.VerifyContainers()) t.Visit(visitors.VerifyContainers()) _cached_builtins_pytd = b, t return _cached_builtins_pytd
def GetBuiltinsAndTyping(): """Get __builtin__.pytd and typing.pytd.""" global _cached_builtins_pytd if not _cached_builtins_pytd: t = parser.parse_string(_FindBuiltinFile("typing"), name="typing") b = parser.parse_string(_FindBuiltinFile("__builtin__"), name="__builtin__") b = b.Visit( visitors.LookupExternalTypes({"typing": t}, full_names=True, self_name="__builtin__")) t = t.Visit(visitors.LookupBuiltins(b)) b = b.Visit(visitors.NamedTypeToClassType()) t = t.Visit(visitors.NamedTypeToClassType()) b = b.Visit(visitors.AdjustTypeParameters()) t = t.Visit(visitors.AdjustTypeParameters()) b = b.Visit(visitors.CanonicalOrderingVisitor()) t = t.Visit(visitors.CanonicalOrderingVisitor()) b.Visit( visitors.FillInLocalPointers({ "": b, "typing": t, "__builtin__": b })) t.Visit( visitors.FillInLocalPointers({ "": t, "typing": t, "__builtin__": b })) b.Visit(visitors.VerifyLookup()) t.Visit(visitors.VerifyLookup()) b.Visit(visitors.VerifyContainers()) t.Visit(visitors.VerifyContainers()) _cached_builtins_pytd = b, t return _cached_builtins_pytd
def testTypeVarValueNoConflictAmbiguousAlias(self): # No conflict due to T1 being aliased to two different type parameters. ast = self.ParseWithBuiltins(""" from typing import Generic, TypeVar T1 = TypeVar("T1") T2 = TypeVar("T2") T3 = TypeVar("T3") T4 = TypeVar("T4") T5 = TypeVar("T5") class A(Generic[T1]): ... class B1(A[T2]): ... class B2(A[T3]): ... class C(B1[T4], B2[T5]): ... class D(C[int, str], A[str]): ... """) ast.Visit(visitors.VerifyContainers())
def _load_file(self, module_name, filename, ast=None): """Load (or retrieve from cache) a module and resolve its dependencies.""" self._concatenated = None # invalidate existing = self._modules.get(module_name) if existing: if existing.filename != filename: raise AssertionError( "%s exists as both %s and %s" % (module_name, filename, existing.filename)) return existing.ast if not ast: ast = builtins.ParsePyTD( filename=filename, module=module_name, python_version=self.options.python_version) ast = self._postprocess_pyi(ast) module = Module(module_name, filename, ast) self._modules[module_name] = module try: module.ast = self._load_and_resolve_ast_dependencies( module.ast, module_name) # Now that any imported TypeVar instances have been resolved, adjust type # parameters in classes and functions. module.ast = visitors.AdjustTypeParameters(module.ast) # Now we can fill in internal cls pointers to ClassType nodes in the # module. This code executes when the module is first loaded, which # happens before any others use it to resolve dependencies, so there are # no external pointers into the module at this point. module.ast.Visit( visitors.FillInModuleClasses({ "": module.ast, module_name: module.ast })) # TODO(rechen): Once generics are supported in inline type annotations, a # VerifyContainers check should also be done on the final ast. module.ast.Visit(visitors.VerifyContainers()) except: del self._modules[ module_name] # don't leave half-resolved modules around raise return module.ast
def _verify_ast(self, ast): try: ast.Visit(visitors.VerifyLookup()) except ValueError as e: raise BadDependencyError(e.message) ast.Visit(visitors.VerifyContainers())