def test_resolve_alias(self): with file_utils.Tempdir() as d: d.create_file( "module1.pyi", """ from typing import List x = List[int] """) d.create_file("module2.pyi", """ def f() -> module1.x: ... """) loader = load_pytd.Loader("base", self.python_version, pythonpath=[d.path]) module2 = loader.import_name("module2") f, = module2.Lookup("module2.f").signatures self.assertEqual("List[int]", pytd_utils.Print(f.return_type))
def testRelative(self): with utils.Tempdir() as d: d.create_file("__init__.pyi", "base = ... # type: ?") d.create_file("path/__init__.pyi", "path = ... # type: ?") d.create_file("path/to/__init__.pyi", "to = ... # type: ?") d.create_file("path/to/some/__init__.pyi", "some = ... # type: ?") d.create_file("path/to/some/module.pyi", "") self.options.tweak(pythonpath=[d.path]) loader = load_pytd.Loader("path.to.some.module", self.options) some = loader.import_relative(1) to = loader.import_relative(2) path = loader.import_relative(3) # Python doesn't allow "...." here, so don't test import_relative(4). self.assertTrue(some.Lookup("path.to.some.some")) self.assertTrue(to.Lookup("path.to.to")) self.assertTrue(path.Lookup("path.path"))
def test_prefer_typeshed(self): with file_utils.Tempdir() as d: # Override two modules from typeshed d.create_file("typing_extensions/__init__.pyi", "foo: str = ...") d.create_file("crypt/__init__.pyi", "foo: str = ...") loader = load_pytd.Loader("x", self.python_version, pythonpath=[d.path]) # typing_extensions should ignore the override, crypt should not. ast1 = loader.import_name("typing_extensions") ast2 = loader.import_name("crypt") self.assertTrue(ast1.Lookup("typing_extensions.Literal")) self.assertTrue(ast2.Lookup("crypt.foo")) with self.assertRaises(KeyError): ast1.Lookup("typing_extensions.foo") with self.assertRaises(KeyError): ast2.Lookup("crypt.crypt")
def test_reuse_builtin_name(self): with file_utils.Tempdir() as d: d.create_file("foo.pyi", """ class Ellipsis: ... """) d.create_file( "bar.pyi", """ from foo import * def f(x: Ellipsis): ... """) loader = load_pytd.Loader(None, self.python_version, pythonpath=[d.path]) loader.import_name("foo") bar = loader.import_name("bar") self.assertEqual(pytd_utils.Print(bar.Lookup("bar.f")), "def bar.f(x: foo.Ellipsis) -> Any: ...")
def test_circular_import(self): with file_utils.Tempdir() as d: d.create_file("os2/__init__.pyi", """ from . import path as path _PathType = path._PathType def utime(path: _PathType) -> None: ... class stat_result(object): ... """) d.create_file("os2/path.pyi", """ import os2 _PathType = bytes def samestat(stat1: os2.stat_result) -> bool: ... """) loader = load_pytd.Loader(None, self.python_version, pythonpath=[d.path]) ast = loader.import_name("os2.path") self.assertEqual(ast.Lookup("os2.path._PathType").type.name, "builtins.bytes")
def test_directory_import(self): with file_utils.Tempdir() as d: d.create_file( "pkg/sub/__init__.pyi", """ from .foo import * from .bar import *""") d.create_file("pkg/sub/foo.pyi", """ class X: pass""") d.create_file( "pkg/sub/bar.pyi", """ from .foo import X y = ... # type: X""") loader = load_pytd.Loader("pkg", self.python_version, pythonpath=[d.path]) ast = loader.import_name("pkg.sub") self.assertTrue(ast.Lookup("pkg.sub.X"))
def test_diamond_import(self): """Should not fail on importing a module via two paths.""" with file_utils.Tempdir() as d: d.create_file( "pkg/sub/__init__.pyi", """ from .foo import * from .bar import *""") d.create_file("pkg/sub/foo.pyi", """ from .baz import X""") d.create_file("pkg/sub/bar.pyi", """ from .baz import X""") d.create_file("pkg/sub/baz.pyi", """ class X: ...""") loader = load_pytd.Loader("pkg", self.python_version, pythonpath=[d.path]) ast = loader.import_name("pkg.sub") self.assertTrue(ast.Lookup("pkg.sub.X"))
def _InferAndVerify(self, src, pythonpath=(), module_name=None, imports_map=None, report_errors=False, quick=False, **kwargs): """Infer types for the source code treating it as a module. Used by Infer(). Args: src: The source code of a module. Treat it as "__main__". pythonpath: --pythonpath as list/tuple of string module_name: Name of the module we're analyzing. E.g. "foo.bar.mymodule". imports_map: --imports_info data report_errors: Whether to fail if the type inferencer reports any errors in the program. quick: Try to run faster, by avoiding costly computations. **kwargs: Keyword paramters to pass through to the type inferencer. Raises: AssertionError: If report_errors is True and we found errors. Returns: A pytd.TypeDeclUnit """ self.options.tweak(pythonpath=pythonpath, module_name=module_name, imports_map=imports_map, quick=quick) errorlog = errors.ErrorLog() loader = load_pytd.Loader(self.options.module_name, self.options) unit, builtins_pytd = infer.infer_types(src, errorlog, self.options, loader=loader, **kwargs) unit.Visit(visitors.VerifyVisitor()) unit = pytd_utils.CanonicalOrdering(unit) if report_errors and len(errorlog): errorlog.print_to_stderr() self.fail("Inferencer found %d errors" % len(errorlog)) return unit, builtins_pytd
def test_circular_import_with_external_type(self): with file_utils.Tempdir() as d: d.create_file("os2/__init__.pyi", """ from posix2 import stat_result as stat_result from . import path as path _PathType = path._PathType def utime(path: _PathType) -> None: ... """) d.create_file("os2/path.pyi", """ import os2 _PathType = bytes def samestate(stat1: os2.stat_result) -> bool: ... """) d.create_file("posix2.pyi", "class stat_result: ...") loader = load_pytd.Loader(None, self.python_version, pythonpath=[d.path]) # Make sure all three modules were resolved properly. loader.import_name("os2") loader.import_name("os2.path") loader.import_name("posix2")
def test_relative(self): with file_utils.Tempdir() as d: d.create_file("__init__.pyi", "base = ... # type: str") d.create_file("path/__init__.pyi", "path = ... # type: str") d.create_file("path/to/__init__.pyi", "to = ... # type: str") d.create_file("path/to/some/__init__.pyi", "some = ... # type: str") d.create_file("path/to/some/module.pyi", "") loader = load_pytd.Loader( config.Options.create(module_name="path.to.some.module", python_version=self.python_version, pythonpath=d.path)) some = loader.import_relative(1) to = loader.import_relative(2) path = loader.import_relative(3) # Python doesn't allow "...." here, so don't test import_relative(4). self.assertTrue(some.Lookup("path.to.some.some")) self.assertTrue(to.Lookup("path.to.to")) self.assertTrue(path.Lookup("path.path"))
def testCircularDependency(self): with utils.Tempdir() as d: d.create_file("foo.pyi", """ def get_bar() -> bar.Bar class Foo: pass """) d.create_file("bar.pyi", """ def get_foo() -> foo.Foo class Bar: pass """) self.options.tweak(pythonpath=[d.path]) loader = load_pytd.Loader("base", self.options) foo = loader.import_name("foo") bar = loader.import_name("bar") f1, = foo.Lookup("foo.get_bar").signatures f2, = bar.Lookup("bar.get_foo").signatures self.assertEquals("bar.Bar", f1.return_type.cls.name) self.assertEquals("foo.Foo", f2.return_type.cls.name)
def test_typing_reexport(self): with file_utils.Tempdir() as d: d.create_file("foo.pyi", """ from typing import List as List """) d.create_file("bar.pyi", """ from foo import * def f() -> List[int]: ... """) loader = load_pytd.Loader(None, self.python_version, pythonpath=[d.path]) foo = loader.import_name("foo") bar = loader.import_name("bar") self.assertEqual(pytd_utils.Print(foo), "foo.List = list") self.assertEqual(pytd_utils.Print(bar), textwrap.dedent(""" from typing import List bar.List = list def bar.f() -> List[int]: ... """).strip())
def test_circular_dependency(self): with file_utils.Tempdir() as d: d.create_file("foo.pyi", """ def get_bar() -> bar.Bar: ... class Foo: pass """) d.create_file("bar.pyi", """ def get_foo() -> foo.Foo: ... class Bar: pass """) loader = load_pytd.Loader( "base", self.python_version, pythonpath=[d.path]) foo = loader.import_name("foo") bar = loader.import_name("bar") f1, = foo.Lookup("foo.get_bar").signatures f2, = bar.Lookup("bar.get_foo").signatures self.assertEqual("bar.Bar", f1.return_type.cls.name) self.assertEqual("foo.Foo", f2.return_type.cls.name)
def testPickledBuiltins(self): with utils.Tempdir() as d: filename = d.create_file("builtins.pickle") foo_path = d.create_file("foo.pickle", """ import datetime tz = ... # type: datetime.tzinfo """) # save builtins load_pytd.Loader("base", self.PYTHON_VERSION).save_to_pickle(filename) # load builtins loader = load_pytd.PickledPyiLoader.load_from_pickle( filename, "base", python_version=self.PYTHON_VERSION, imports_map={"foo": foo_path}, pythonpath=[""]) # test import self.assertTrue(loader.import_name("sys")) self.assertTrue(loader.import_name("__future__")) self.assertTrue(loader.import_name("datetime")) self.assertTrue(loader.import_name("foo")) self.assertTrue(loader.import_name("ctypes"))
def InferAndCheck(self, code, deep=True, pythonpath=(), **kwargs): self.options.tweak(pythonpath=pythonpath) code = textwrap.dedent(code) errorlog = errors.ErrorLog() loader = load_pytd.Loader(self.options.module_name, self.options) unit, builtins_pytd = infer.infer_types(code, errorlog, self.options, loader=loader, deep=deep, analyze_annotated=True, cache_unknowns=True, **kwargs) unit.Visit(visitors.VerifyVisitor()) unit = optimize.Optimize(unit, builtins_pytd, lossy=False, use_abcs=False, max_union=7, remove_mutable=False) return pytd_utils.CanonicalOrdering(unit), errorlog
def testSmokePyTD(self): """Smoke test to ensure all *.pytd files load properly.""" loader = load_pytd.Loader("base", python_version=self.PYTHON_VERSION) pytd_dir = os.path.join(os.path.dirname(load_pytd.__file__), "pytd") for builtins_subdir in ("builtins", "stdlib"): subdir_path = os.path.join(pytd_dir, builtins_subdir) for dirpath, _, files in os.walk(subdir_path): # We don't need to know the directory we're in because these are builtin # .pytd files and load_pytd.import_name takes care of looking in # multiple directories. But because there can be subdirectories, we need # to construct an appropriate module name. rel_dirpath = os.path.relpath(dirpath, start=subdir_path) module_prefix = rel_dirpath.replace(os.sep, ".") + ( "." if rel_dirpath else "") for name in files: module_name, ext = os.path.splitext(module_prefix + name) if ext == ".pytd": # We could do something fancier with try/except, but for # now, just print out each module as we load it. print >>sys.stderr, "***Loading", module_name self.assertTrue(loader.import_name(module_name), msg="Failed loading " + module_name)
def assertNoErrors(self, code, raises=None, pythonpath=(), skip_repeat_calls=True, report_errors=True): """Run an inference smoke test for the given code.""" if raises is not None: # TODO(kramm): support this log.warning("Ignoring 'raises' parameter to assertNoErrors") self.options.tweak(pythonpath=pythonpath, skip_repeat_calls=skip_repeat_calls) errorlog = errors.ErrorLog() loader = load_pytd.Loader(self.options.module_name, self.options) infer.check_types(textwrap.dedent(code), None, loader=loader, errorlog=errorlog, options=self.options, cache_unknowns=True) if report_errors and len(errorlog): errorlog.print_to_stderr() self.fail("Inferencer found %d errors" % len(errorlog))
def _get_ast(self, temp_dir, module_name, src=None): src = src or (""" import module2 from module2 import f from typing import List constant = True x = List[int] b = List[int] class SomeClass(object): def __init__(self, a: module2.ObjectMod2): pass def ModuleFunction(): pass """) pyi_filename = temp_dir.create_file("module1.pyi", src) temp_dir.create_file( "module2.pyi", """ import queue def f() -> queue.Queue: ... class ObjectMod2(object): def __init__(self): pass """) loader = load_pytd.Loader(base_module=None, python_version=self.python_version, pythonpath=[temp_dir.path]) ast = loader.load_file(module_name, pyi_filename) # serialize_ast.StoreAst sorts the ast for determinism, so we should do the # same to the original ast to do pre- and post-pickling comparisons. loader._modules[module_name].ast = ast = ast.Visit( visitors.CanonicalOrderingVisitor()) return ast, loader
def test_import_map_congruence(self): with file_utils.Tempdir() as d: foo_path = d.create_file("foo.pyi", "class X: ...") bar_path = d.create_file("bar.pyi", "X = ... # type: another.foo.X") # Map the same pyi file under two module paths. imports_map = { "foo": foo_path, "another/foo": foo_path, "bar": bar_path, "empty1": "/dev/null", "empty2": "/dev/null", } # We cannot use tweak(imports_info=...) because that doesn't trigger # post-processing and we need an imports_map for the loader. loader = load_pytd.Loader("base", self.python_version, imports_map=imports_map, pythonpath=[""]) normal = loader.import_name("foo") self.assertEqual("foo", normal.name) loader.import_name( "bar") # check that we can resolve against another.foo another = loader.import_name("another.foo") # We do *not* treat foo.X and another.foo.X the same, because Python # doesn't, either: self.assertIsNot(normal, another) self.assertTrue([c.name.startswith("foo") for c in normal.classes]) self.assertTrue( [c.name.startswith("another.foo") for c in another.classes]) # Make sure that multiple modules using /dev/null are not treated as # congruent. empty1 = loader.import_name("empty1") empty2 = loader.import_name("empty2") self.assertIsNot(empty1, empty2) self.assertEqual("empty1", empty1.name) self.assertEqual("empty2", empty2.name)
def setUp(self): super().setUp() options = config.Options.create(python_version=self.python_version) self._vm = vm.VirtualMachine( errors.ErrorLog(), options, load_pytd.Loader(None, self.python_version))
def setUp(self): super(TestTypeshedParsing, self).setUp() self.loader = load_pytd.Loader("base", self.PYTHON_VERSION)
def setUp(self): options = config.Options.create() self._vm = vm.VirtualMachine(errors.ErrorLog(), options, load_pytd.Loader(None, options)) self._program = cfg.Program() self._node = self._vm.root_cfg_node.ConnectNew("test_node")
def testStdlib(self): loader = load_pytd.Loader("base", self.options) ast = loader.import_name("StringIO") self.assertTrue(ast.Lookup("StringIO.StringIO"))
def testNoInit(self): with utils.Tempdir() as d: d.create_directory("baz") self.options.tweak(pythonpath=[d.path]) loader = load_pytd.Loader("base", self.options) self.assertTrue(loader.import_name("baz"))
def testInit(self): with utils.Tempdir() as d1: d1.create_file("baz/__init__.pyi", "x = ... # type: int") self.options.tweak(pythonpath=[d1.path]) loader = load_pytd.Loader("base", self.options) self.assertTrue(loader.import_name("baz").Lookup("baz.x"))
def testBuiltinSys(self): loader = load_pytd.Loader("base", self.options) ast = loader.import_name("sys") self.assertTrue(ast.Lookup("sys.exit"))
def testTypeShed(self): loader = load_pytd.Loader("base", self.options) self.assertTrue(loader.import_name("UserDict"))
def setUp(self): options = config.Options.create() self.vm = vm.VirtualMachine( errors.ErrorLog(), options, load_pytd.Loader(None, self.PYTHON_VERSION)) self.type_type = self.vm.convert.type_type
def setUp(self): super(TestTypeshedParsing, self).setUp() self.loader = load_pytd.Loader("base", self.options)
def setUp(self): super(GetViewsTest, self).setUp() self._vm = vm.VirtualMachine( errors.ErrorLog(), config.Options.create(python_version=self.python_version), load_pytd.Loader(None, self.python_version))