blob: 2a29d7257009c0c8578d0da3d08495d27684e31e [file] [edit]
-- These test cases compile two or more modules at a time.
-- Any file prefixed with "other" is compiled.
--
-- Note that these are run in three compilation modes: regular,
-- multi-file and separate. See the docstrings of
-- mypyc.test.test_run.TestRunMultiFile and
-- mypyc.test.test_run.TestRunSeparate for more information.
--
-- Some of these files perform multiple incremental runs. See
-- test-data/unit/check-incremental.test for more information
-- about how this is specified (e.g. .2 file name suffixes).
[case testMultiModulePackage]
from p.other import g, _i as i
def f(x: int) -> int:
from p.other import h
return i(h(g(x + 1)))
[file p/__init__.py]
[file p/other.py]
def g(x: int) -> int:
return x + 2
def h(x: int) -> int:
return x + 1
def _i(x: int) -> int:
return x + 3
[file driver.py]
import native
from native import f
from p.other import g
assert f(3) == 10
assert g(2) == 4
try:
f(1.1)
except TypeError:
pass
else:
assert False
try:
g(1.1)
except TypeError:
pass
else:
assert False
[case testImportNonNativeSubmoduleFrom]
# separate: [(["native.py", "other_pkg/__init__.py"], "testgroup")]
import types
from other_pkg import helper
def f() -> int:
return helper.func()
def g() -> types.ModuleType:
return helper
[file other_pkg/__init__.py]
[file other_pkg/helper.py]
def func() -> int:
return 42
[file driver.py]
from native import f, g
import other_pkg.helper
assert f() == 42
assert g() is other_pkg.helper
[case testNativeSubmoduleOfNonNativePackageFrom]
# separate: [(["native.py", "pkg/other_mod.py"], "testgroup")]
from pkg import other_mod
def f() -> int:
return other_mod.func()
[file pkg/__init__.py]
[file pkg/other_mod.py]
def func() -> int:
return 42
[file driver.py]
import importlib.machinery
import os
import native
import pkg.other_mod
assert native.f() == 42
# other_mod should be in native's namespace and be the same object as pkg.other_mod
assert native.other_mod is pkg.other_mod
# native-to-native import should preserve module metadata such as __file__
ext_suffixes = importlib.machinery.EXTENSION_SUFFIXES
assert any(native.other_mod.__file__.endswith(s) for s in ext_suffixes), native.other_mod.__file__
# The directory of __file__ should reflect the package structure relative to the root
root_dir = os.path.dirname(native.__file__)
assert os.path.dirname(native.other_mod.__file__) == os.path.join(root_dir, "pkg"), \
native.other_mod.__file__
[case testNativeSubmoduleOfNativePackageFrom]
# separate: [(["native.py", "other_pkg/__init__.py", "other_pkg/other_sub.py"], "testgroup")]
from other_pkg import other_sub
def f() -> int:
return other_sub.func()
[file other_pkg/__init__.py]
[file other_pkg/other_sub.py]
def func() -> int:
return 42
[file driver.py]
import importlib.machinery
import os
import native
import other_pkg.other_sub
assert native.f() == 42
assert native.other_sub is other_pkg.other_sub
# Fast path import should preserve __file__ as a proper extension path
ext_suffixes = importlib.machinery.EXTENSION_SUFFIXES
assert any(native.other_sub.__file__.endswith(s) for s in ext_suffixes), native.other_sub.__file__
# The directory of __file__ should reflect the package structure relative to the root
root_dir = os.path.dirname(native.__file__)
assert os.path.dirname(native.other_sub.__file__) == os.path.join(root_dir, "other_pkg"), \
native.other_sub.__file__
[case testImportFromBucketingEndToEnd]
# separate: [(["native.py", "other_pkg/__init__.py", "other_pkg/other_sub.py"], "testgroup")]
from other_pkg import other_sub as sub_alias, other_attr as attr_alias, py_sub as py_alias
[file other_pkg/__init__.py]
other_attr = 41
[file other_pkg/other_sub.py]
def func() -> int:
return 10
[file other_pkg/py_sub.py]
def func() -> int:
return 20
[file driver.py]
import importlib
import native
other_sub = importlib.import_module("other_pkg.other_sub")
py_sub = importlib.import_module("other_pkg.py_sub")
assert native.sub_alias is other_sub
assert native.attr_alias == 41
assert native.py_alias is py_sub
assert native.sub_alias.func() == 10
assert native.py_alias.func() == 20
[case testNativeTopLevelModuleFileDir]
# separate: [(["native.py", "other_top.py"], "testgroup")]
import other_top
def f() -> int:
return other_top.func()
[file other_top.py]
def func() -> int:
return 99
[file driver.py]
import importlib.machinery
import os
import native
import other_top
assert native.f() == 99
# Top-level native module __file__ directory should match the shared lib's directory
ext_suffixes = importlib.machinery.EXTENSION_SUFFIXES
assert any(other_top.__file__.endswith(s) for s in ext_suffixes), other_top.__file__
root_dir = os.path.dirname(native.__file__)
assert os.path.dirname(other_top.__file__) == root_dir, other_top.__file__
[case testNativeDeeplyNestedSubmoduleFileDir]
# separate: [(["native.py", "other_a/__init__.py", "other_a/other_b/__init__.py", "other_a/other_b/other_c.py"], "testgroup")]
from other_a.other_b import other_c
def f() -> int:
return other_c.func()
[file other_a/__init__.py]
[file other_a/other_b/__init__.py]
[file other_a/other_b/other_c.py]
def func() -> int:
return 77
[file driver.py]
import importlib.machinery
import os
import native
import other_a.other_b.other_c
assert native.f() == 77
assert native.other_c is other_a.other_b.other_c
# Deeply nested module __file__ should have correct extension suffix
ext_suffixes = importlib.machinery.EXTENSION_SUFFIXES
assert any(native.other_c.__file__.endswith(s) for s in ext_suffixes), native.other_c.__file__
# The directory should reflect the full package hierarchy
root_dir = os.path.dirname(native.__file__)
expected_dir = os.path.join(root_dir, "other_a", "other_b")
assert os.path.dirname(native.other_c.__file__) == expected_dir, native.other_c.__file__
[case testNativeImportPackageAttribute]
# separate: [(["native.py", "other_top.py", "other_pkg/__init__.py", "other_pkg/other_sub.py"], "testgroup")]
import other_top
from other_pkg import other_sub
import other_pkg
def get_top() -> str:
p = other_top.__package__
assert p is not None
return p
def get_sub() -> str:
p = other_sub.__package__
assert p is not None
return p
def get_pkg() -> str:
p = other_pkg.__package__
assert p is not None
return p
[file other_top.py]
def func() -> int:
return 1
[file other_pkg/__init__.py]
[file other_pkg/other_sub.py]
def func() -> int:
return 2
[file driver.py]
from native import get_top, get_sub, get_pkg
# Top-level module: __package__ should be "" (empty string)
assert get_top() == "", repr(get_top())
# Submodule: __package__ should be the parent package name
assert get_sub() == "other_pkg", repr(get_sub())
# Package __init__: __package__ should be the package name itself
assert get_pkg() == "other_pkg", repr(get_pkg())
[case testNativeImportFileAvailableAtInitTime]
# separate: [(["native.py", "other_pkg/__init__.py", "other_pkg/other_sub.py"], "testgroup")]
from other_pkg import other_sub
def f() -> int:
return other_sub.func()
[file other_pkg/__init__.py]
[file other_pkg/other_sub.py]
# __file__ should be available during module initialization
_file: str = __file__
def func() -> int:
return 42
[file driver.py]
import importlib.machinery
import native
assert native.f() == 42
# Verify that __file__ captured at init time has a valid extension suffix
ext_suffixes = importlib.machinery.EXTENSION_SUFFIXES
assert any(native.other_sub._file.endswith(s) for s in ext_suffixes), native.other_sub._file
[case testNativeImportPathAttribute]
# separate: [(["native.py", "other_pkg/__init__.py", "other_pkg/other_sub.py"], "testgroup")]
import other_pkg
from other_pkg import other_sub
def get_pkg_path() -> str:
return other_pkg.__path__[0]
def get_sub_has_path() -> bool:
return hasattr(other_sub, '__path__')
[file other_pkg/__init__.py]
# __path__ should be available during package initialization
_path: list[str] = __path__
[file other_pkg/other_sub.py]
def func() -> int:
return 1
[file driver.py]
import os
import native
# Package should have __path__ set to [dirname(__file__)]
expected = os.path.dirname(native.other_pkg.__file__)
assert native.get_pkg_path() == expected, (native.get_pkg_path(), expected)
# __path__ should have been accessible at init time
assert native.other_pkg._path == [expected], native.other_pkg._path
# Non-package submodule should NOT have __path__
assert not native.get_sub_has_path()
[case testNativeImportPackageFileDirMatchesPath]
# separate: [(["native.py", "other_pkg/__init__.py", "other_pkg/other_sub.py"], "testgroup")]
import other_pkg
from other_pkg import other_sub
def get_pkg_file() -> str:
return other_pkg.__file__
def get_pkg_path() -> str:
return other_pkg.__path__[0]
def get_sub_file() -> str:
return other_sub.__file__
[file other_pkg/__init__.py]
x = 1
[file other_pkg/other_sub.py]
def func() -> int:
return 1
[file driver.py]
import os
import native
pkg_file = native.get_pkg_file()
pkg_path = native.get_pkg_path()
sub_file = native.get_sub_file()
# Package __file__ should contain __init__ (e.g. other_pkg/__init__.cpython-312-x86_64-linux-gnu.so)
assert "__init__" in os.path.basename(pkg_file), \
f"Package __file__ should contain __init__, got: {pkg_file}"
# Package __path__ should be the directory containing the package's __init__ file
assert pkg_path == os.path.dirname(pkg_file), \
f"__path__ ({pkg_path}) should equal dirname(__file__) ({os.path.dirname(pkg_file)})"
# __path__ should end with the package name
assert os.path.basename(pkg_path) == "other_pkg", \
f"__path__ should end with package name, got: {pkg_path}"
# Submodule __file__ should be inside the package directory (i.e. inside __path__)
assert os.path.dirname(sub_file) == pkg_path, \
f"Submodule dir ({os.path.dirname(sub_file)}) should equal package __path__ ({pkg_path})"
[case testNativeImportSpecAttribute]
# separate: [(["native.py", "other_top.py", "other_pkg/__init__.py", "other_pkg/other_sub.py"], "testgroup")]
from typing import Any
import other_top
from other_pkg import other_sub
import other_pkg
def get_top_spec() -> Any:
return other_top.__spec__
def get_sub_spec() -> Any:
return other_sub.__spec__
def get_pkg_spec() -> Any:
return other_pkg.__spec__
[file other_top.py]
from typing import Any
# __spec__ should be available during module initialization
_spec: Any = __spec__ # type: ignore[name-defined]
def func() -> int:
return 1
[file other_pkg/__init__.py]
[file other_pkg/other_sub.py]
def func() -> int:
return 2
[file driver.py]
import importlib.machinery
import native
top_spec = native.get_top_spec()
sub_spec = native.get_sub_spec()
pkg_spec = native.get_pkg_spec()
# __spec__.name should match the module name
assert top_spec.name == "other_top"
assert sub_spec.name == "other_pkg.other_sub"
assert pkg_spec.name == "other_pkg"
# __spec__ should have correct origin (same as __file__)
assert top_spec.origin == native.other_top.__file__
assert sub_spec.origin == native.other_sub.__file__
# __spec__.loader should be an ExtensionFileLoader and also be set as __loader__
assert isinstance(top_spec.loader, importlib.machinery.ExtensionFileLoader)
assert native.other_top.__loader__ is top_spec.loader
# Package spec should have submodule_search_locations
assert pkg_spec.submodule_search_locations is not None
# Non-package spec should not have submodule_search_locations
assert top_spec.submodule_search_locations is None
# __spec__ should be available at init time
assert native.other_top._spec.name == "other_top"
[case testNativeSubmoduleFailureDoesNotBindParentEarly]
# separate: [(["native.py", "other_pkg/__init__.py", "other_pkg/other_sub.py"], "testgroup")]
from other_pkg import other_sub
[file other_pkg/__init__.py]
x = 1
[file other_pkg/other_sub.py]
import other_pkg
if hasattr(other_pkg, "other_sub"):
raise RuntimeError("parent attr visible too early")
raise RuntimeError("boom from other_sub")
[file driver.py]
import sys
import other_pkg
try:
import native
except RuntimeError as e:
assert str(e) == "boom from other_sub"
else:
assert False, "import native should fail"
assert not hasattr(other_pkg, "other_sub")
assert "other_pkg.other_sub" not in sys.modules
[case testNativeImportUsesExistingNativeSysModulesObject]
# separate: [(["native.py", "other_top.py"], "testgroup")]
import other_top
def f() -> int:
return other_top.value
[file other_top.py]
value = 42
[file driver.py]
import native
import other_top
assert native.other_top is other_top
assert native.f() == 42
[case testNativeImportRejectsForeignSysModulesObject]
# separate: [(["native.py", "other_top.py"], "testgroup")]
import other_top
def f() -> int:
return other_top.value
[file other_top.py]
value = 42
[file driver.py]
import sys
import types
import other_top
fake = types.ModuleType("other_top")
fake.value = -1
sys.modules["other_top"] = fake
try:
import native
except ImportError as e:
assert "other_top" in str(e)
assert "replaced after initialization" in str(e)
else:
assert False, "import native should fail"
assert sys.modules["other_top"] is fake
[case testMultiModuleFastpaths]
[file other_main.py]
[file other_main.py.2]
from other_b import A, func
class B(A):
pass
def test() -> None:
a = A()
assert func() == 12
assert a.method() == "test"
test()
[file other_b.py]
class A:
def method(self) -> str:
return "test"
def func() -> int:
return 12
# Remove all the methods and functions from globals to ensure that
# they get called via the fastpaths even when doing incremental
# compilation.
setattr(A, 'method', None)
setattr(A, '__init__', None)
globals()['func'] = None
globals()['A'] = None
[file driver.py]
import other_main
[case testNonNativeImportInPackageFile]
# The import is really non-native only in separate compilation mode where __init__.py and
# other_cache.py are in different libraries and the import uses the standard Python procedure.
# Python imports are resolved using __path__ and __spec__ from the package file so this checks
# that they are set up correctly.
[file other/__init__.py]
from other.other_cache import Cache
x = 1
[file other/other_cache.py]
class Cache:
pass
[file driver.py]
import other
[case testRelativeImportInPackageFile]
# Relative imports from a compiled package __init__ depend on package metadata being
# available while the package module body is executing.
[file other/__init__.py]
assert __package__ == "other"
from .other_cache import Cache
x = 1
[file other/other_cache.py]
class Cache:
pass
[file driver.py]
import other
assert other.Cache.__name__ == "Cache"
[case testMultiModuleSameNames]
# Use same names in both modules
import other
def f() -> int:
return 0
class C:
x: int
def __init__(self) -> None:
self.x = 1
def f(self, x: int) -> int:
return self.x + x
class D(C): pass
def g(x: 'other.C') -> None:
pass
[file other.py]
def f(x: int) -> int:
return x + 1
class C:
x: int
def __init__(self) -> None:
self.x = 2
def f(self, x: int) -> int:
return self.x + x + 1
class D(C): pass
[file driver.py]
import native, other
assert native.f() == 0
assert other.f(3) == 4
c1 = native.C()
c1.x += 3
c2 = other.C()
c2.x += 6
assert c1.f(9) == 1 + 3 + 9
assert c2.f(7) == 2 + 6 + 7 + 1
assert isinstance(native.D(), native.C)
assert isinstance(other.D(), other.C)
assert not isinstance(native.D(), other.C)
assert not isinstance(other.D(), native.C)
[case testMultiModuleInitializeImportedModules]
from other import f
def g() -> int:
return f(1)
[file other.py]
def f(x: int) -> int:
return x + 4
[file driver.py]
import sys
assert 'other' not in sys.modules
from native import g
assert 'other' in sys.modules
assert g() == 5
f = sys.modules['other'].f
assert f(1) == 5
try:
f(1.1)
except TypeError:
pass
else:
assert False
[case testMultiModuleImportClass]
from typing import cast
from other import C, a_global
class D(C):
def __init__(self, x: int) -> None:
self.x = x
def f(c: C) -> int:
d = D(3)
o: object = c
c = cast(C, o)
return a_global + c.x + c.f() + d.x + d.f() + 1
[file other.py]
from typing import Final
a_global: Final = int('5')
class C:
x: int
def __init__(self, x: int) -> None:
self.x = x
def __hash__(self) -> int:
return self.x
def __str__(self) -> str:
return str(self.x)
def f(self) -> int:
return 2
def check(self) -> None:
assert isinstance(self, C)
[file driver.py]
from native import f, D
from other import C
c = C(4)
assert f(c) == 5 + 4 + 2 + 3 + 2 + 1
assert str(D(10)) == '10'
assert hash(10) == 10
try:
f(1)
except TypeError:
pass
else:
assert False
assert isinstance(D(10), C)
c.check()
D(10).check()
[case testMultiModuleSpecialize]
from other import A
class B(A):
def foo(self, x: object) -> int:
print(2)
return id(x)
[file other.py]
class A:
def foo(self, x: int) -> object:
print(1)
return str(x)
def use_a(x: A, y: int) -> object:
return x.foo(y)
[file driver.py]
from native import B
from other import A, use_a
a = A()
b = B()
o = object()
i = 10
assert a.foo(10) == '10'
assert b.foo(o) == id(o)
assert use_a(a, 10) == '10'
assert use_a(b, i) == id(i)
[out]
1
2
1
2
[case testMultiModuleLiterals]
from other import gs, gi, gf
def fs() -> str:
return 'f' + gs()
def fi() -> int:
return 10001000100010001000 + gi()
def ff() -> float:
return 2.0 + gf()
[file other.py]
def gi() -> int:
return 20001000100010001000
def gs() -> str:
return 'g'
def gf() -> float:
return 3.0
[file driver.py]
from native import fs, fi, ff
assert fs() == 'fg'
assert fi() == 30002000200020002000
assert ff() == 5.0
[case testMultiModuleTraceback]
from other import fail2
def fail() -> None:
fail2()
[file other.py]
def fail2() -> None:
x = [1]
x[2] = 2
[file driver.py]
import traceback
import sys
import native
import other
try:
other.fail2()
except IndexError:
tb = sys.exc_info()[2]
assert tb.tb_next.tb_frame.f_globals is other.__dict__
traceback.print_exc()
try:
native.fail()
except IndexError:
tb = sys.exc_info()[2]
assert tb.tb_next.tb_frame.f_globals is native.__dict__
traceback.print_exc()
[out]
Traceback (most recent call last):
File "driver.py", line 6, in <module>
other.fail2()
File "other.py", line 3, in fail2
x[2] = 2
IndexError: list assignment index out of range
Traceback (most recent call last):
File "driver.py", line 12, in <module>
native.fail()
File "native.py", line 4, in fail
fail2()
File "other.py", line 3, in fail2
x[2] = 2
IndexError: list assignment index out of range
[out version>=3.13]
Traceback (most recent call last):
File "driver.py", line 6, in <module>
other.fail2()
~~~~~~~~~~~^^
File "other.py", line 3, in fail2
x[2] = 2
IndexError: list assignment index out of range
Traceback (most recent call last):
File "driver.py", line 12, in <module>
native.fail()
~~~~~~~~~~~^^
File "native.py", line 4, in fail
fail2()
File "other.py", line 3, in fail2
x[2] = 2
IndexError: list assignment index out of range
[case testMultiModuleCycle]
if False:
from typing import Final
import other
x = int('0') # type: Final
def f1() -> int:
return other.f2() + other.x
def f3() -> int:
return 5
[file other.py]
if False:
from typing import Final
import native
x = int('0') # type: Final
def f2() -> int:
return native.f3() + native.x
[file driver.py]
from native import f1
assert f1() == 5
[case testMultiModuleCycleWithClasses]
import other
class D: pass
def f() -> other.C:
return other.C()
def g(c: other.C) -> D:
return c.d
[file other.py]
import native
class C:
def __init__(self) -> None:
self.d = native.D()
def h(d: native.D) -> None:
pass
[file driver.py]
from native import f, g
from other import C, h
c = f()
assert isinstance(c, C)
assert g(c) is c.d
h(c.d)
try:
g(1)
except TypeError:
pass
else:
assert False
try:
h(1)
except TypeError:
pass
else:
assert False
[case testMultiModuleCycleWithInheritance]
import other
class Deriv1(other.Base1):
def __init__(self) -> None:
super().__init__()
class Base2:
y: int
def __init__(self) -> None:
self.y = 2
[file other.py]
from typing import Tuple
import native
class Base1:
a: Tuple[int, int]
x: int
def __init__(self) -> None:
self.x = 1
def make_2() -> native.Base2:
return native.Base2()
[file driver.py]
from native import Deriv1
from other import make_2
a = Deriv1()
assert a.x == 1
b = make_2()
assert b.y == 2
[case testMultiModuleTraitInheritance]
from other import Base1, Base2
class Deriv1(Base1, Base2):
pass
[file other.py]
from mypy_extensions import trait
@trait
class Base1:
def foo(self) -> int: return 10
@trait
class Base2:
def bar(self) -> int: return 12
[file driver.py]
from native import Deriv1
a = Deriv1()
assert a.foo() == 10 and a.bar() == 12
[case testImportCycleWithNonCompiledModule]
import m
class C: pass
def f1() -> int:
m.D()
return m.f2()
def f3() -> int:
return 2
[file m.py]
# This module is NOT compiled
import native
class D: pass
def f2() -> int:
native.C()
return native.f3()
[file driver.py]
from native import f1
assert f1() == 2
[case testImportCycleWithTopLevelStatements]
import other
x = 1
print(x)
[file other.py]
import native
x = 2
print(x)
[file driver.py]
import other
print('-')
import native
print('>', native.x)
print('>', other.x)
[out]
1
2
-
> 1
> 2
[case testMultiModuleCycleIfMypy1]
from other import foo, bar
class Foo:
def foo(self) -> None:
foo(self)
class Bar:
def bar(self) -> None:
bar(self)
[file other.py]
from typing import TYPE_CHECKING
MYPY = False
if MYPY:
from native import Foo
if TYPE_CHECKING:
from native import Bar
def foo(x: 'Foo') -> None:
pass
def bar(x: 'Bar') -> None:
pass
[file driver.py]
from native import Foo, Bar
Foo().foo()
Bar().bar()
[case testMultiModuleCycleIfMypy2]
MYPY = False
if MYPY:
from other import C
class D:
def __init__(self) -> None:
self.y = 1
def f(c: 'C') -> int:
return c.x
[file other.py]
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from native import D
class C:
def __init__(self) -> None:
self.x = 2
def g(d: 'D') -> int:
return d.y
[file driver.py]
from native import f, D
from other import g, C
assert f(C()) == 2
assert g(D()) == 1
try:
f(D())
except TypeError:
pass
else:
assert False
try:
g(C())
except TypeError:
pass
else:
assert False
[case testMultiModuleRelative]
from package.a import f
[file package/__init__.py]
[file package/a.py]
from . import b
from .c import c3
def f() -> None:
print("Hello " + b.b2())
print("Hello " + c3())
[file package/b.py]
def b2() -> str:
return "moon!"
[file package/c.py]
def c3() -> str:
return "sun!"
[file driver.py]
from native import f
f()
[out]
Hello moon!
Hello sun!
[case testMultiModuleCrash]
b = False
if b:
import other
def foo() -> None:
try:
other.x
except:
pass
else:
assert False
[file other.py]
x = 10
[file driver.py]
from native import foo
foo()
[case testTrivialIncremental]
# separate: [(["other.py", "other_b.py"], "stuff")]
from other import x
from other_b import z
y = x + z
[file other.py]
x = 1
[file other.py.2]
x = 2
[file other_b.py]
z = 1
[file driver.py]
from native import y
print(y)
[out]
2
[out2]
3
[rechecked other, other_b]
[case testIncrementalCompilation1]
import non_native
from other_a import A
from other_b import z
a = A()
assert a.y == z
assert non_native.foo() == 0
[file other_a.py]
from other_b import z
from typing import Iterable
class A:
def __init__(self) -> None:
self.y = z
[file other_a.py.2]
from other_b import z
from typing import Iterable
class A:
def __init__(self) -> None:
self.x = 'test'
self.y = z
[file other_b.py]
import other_a
z = 10
def foo() -> 'other_a.A':
return other_a.A()
[file other_b.py.3]
import other_a
z = 20
def foo() -> 'other_a.A':
return other_a.A()
[file non_native.py]
import other_a
def foo() -> int:
return 0
[file non_native.py.4]
import other_a
def foo() -> float:
return 0
[file driver.py]
from native import a
print(a.y, getattr(a, 'x', None))
[out]
10 None
[out2]
10 test
[out3]
20 test
[out4]
20 test
[rechecked other_a, other_b, native, non_native]
[rechecked2 other_a, other_b]
[rechecked3 native, non_native]
-- This one tests a group that is not an SCC.
[case testIncrementalCompilation2]
# separate: [(["other_a.py", "other_b.py"], "stuff")]
from other_a import A
from other_b import z
a = A()
assert a.y == z
[file other_a.py]
from other_b import z
class A:
def __init__(self) -> None:
self.y = z
[file other_a.py.2]
from other_b import z
class A:
def __init__(self) -> None:
self.x = 'test'
self.y = z
[file other_b.py]
z = 10
[file driver.py]
from native import a
print(a.y, getattr(a, 'x', None))
[out]
10 None
[out2]
10 test
[rechecked other_a, other_b, native]
[case testIncrementalCompilation3]
from other import X
Y = X
def foo() -> int:
return X
[file other.py]
from typing import Final
X: Final = 10
[file other.py.2]
from typing import Final
X: Final = 20
[file driver.py]
import native
import other
assert native.Y == other.X
assert native.foo() == other.X
[rechecked native, other]
-- This one tests a group changing
[case testIncrementalCompilation4]
# separate: [(["other_a.py", "other_b.py"], "stuff")]
# separate2: []
from other_a import A
from other_b import z
a = A()
assert a.y == z
[file other_a.py]
from other_b import z
class A:
def __init__(self) -> None:
self.y = z
[file other_b.py]
z = 10
[file wtvr.py.2]
[file driver.py]
from native import a
print(a.y, getattr(a, 'x', None))
[out]
10 None
[out2]
10 None
[rechecked other_a, other_b, native]
-- This one tests cases where other modules *do not* need rechecked
[case testIncrementalCompilation5]
import other_a
[file other_a.py]
from other_b import f
assert f(10) == 20
[file other_a.py.2]
from other_b import f
assert f(20) == 40
[file other_b.py]
def f(x: int) -> int:
return x * 2
[file driver.py]
import native
[rechecked other_a]
-- Delete one of the C files and make sure this forces recompilation
[case testIncrementalCompilation6]
import other_a
assert other_a.foo() == 10
[file other_a.py]
def foo() -> int: return 10
[file build/__native_other_a.c]
[delete build/__native_other_a.c.2]
[file driver.py]
import native
[rechecked other_a]
[case testSeparateCompilationWithUndefinedAttribute]
from other_a import A
def f() -> None:
a = A()
if a.x == 5:
print(a.y)
print(a.m())
else:
assert a.x == 6
try:
print(a.y)
except AttributeError:
print('y undefined')
else:
assert False
try:
print(a.m())
except AttributeError:
print('y undefined')
else:
assert False
[file other_a.py]
from other_b import B
class A(B):
def __init__(self) -> None:
self.y = 9
[file other_a.py.2]
from other_b import B
class A(B):
x = 6
def __init__(self) -> None:
pass
[file other_b.py]
class B:
x = 5
def __init__(self) -> None:
self.y = 7
def m(self) -> int:
return self.y
[file driver.py]
from native import f
f()
[rechecked native, other_a]
[out]
9
9
[out2]
y undefined
y undefined
[case testIncrementalCompilationWithDeletable]
import other_a
[file other_a.py]
from other_b import C
[file other_a.py.2]
from other_b import C
c = C()
print(getattr(c, 'x', None))
del c.x
print(getattr(c, 'x', None))
[file other_b.py]
class C:
__deletable__ = ['x']
def __init__(self) -> None:
self.x = 0
[file driver.py]
import native
[out]
[out2]
0
None
[case testIncrementalCompilationWithNonClassTypeDef]
import other_a
[file other_a.py]
from other_b import MyInt
[file other_a.py.2]
from other_b import MyInt, NT, TD
i = MyInt(42)
def f(x: MyInt) -> int:
return x + 1
def g(x: int) -> MyInt:
return MyInt(x + 2)
print(i)
print(f(i))
print(g(13))
def make_nt(x: int) -> NT:
return NT(x=MyInt(x))
print(make_nt(4))
def make_td(x: int) -> TD:
return {"x": MyInt(x)}
print(make_td(5))
[file other_b.py]
from typing import NewType, NamedTuple, TypedDict
from enum import Enum
MyInt = NewType("MyInt", int)
NT = NamedTuple("NT", [("x", MyInt)])
TD = TypedDict("TD", {"x": MyInt})
[file driver.py]
import native
[typing fixtures/typing-full.pyi]
[out]
[out2]
42
43
15
NT(x=4)
{'x': 5}
[case testExtraLibRtSourceFileDep]
table_list = list(range(256))
table_list[ord('A')] = ord('B')
table = bytes(table_list)
def translate(b: bytes) -> bytes:
# The primimitive for bytes.translate requires an optional C file from lib-rt
return b.translate(table)
[file driver.py]
import native
assert native.translate(b'ABCD') == b'BBCD'
[case testCrossModuleAttrDefaults]
from other import Parent
class Child(Parent):
extra: int = 99
def test() -> None:
c = Child()
assert c.config == {"key": "value"}
assert c.extra == 99
assert c.total == 60
p = Parent()
assert p.config == {"key": "value"}
assert p.total == 60
assert Parent.TAG == "parent"
[file other.py]
from typing import ClassVar, Dict
MY_DEFAULT: Dict[str, str] = {"key": "value"}
VAL_1: int = 10
VAL_2: int = 20
VAL_3: int = 30
class Parent:
config: Dict[str, str] = MY_DEFAULT
total: int = VAL_1 + VAL_2 + VAL_3
TAG: ClassVar[str] = "parent"
[file driver.py]
from native import test
test()
[case testExtraOpsFunction_experimental_librt]
from librt.strings import BytesWriter
def call_write(b: bytes) -> bytes:
w = BytesWriter()
w.write(b) # calls CPyBytesWriter_Write defined in byteswriter_extra_ops.c
return w.getvalue()
[file other.py]
from native import call_write
def test(b: bytes) -> bytes:
return call_write(b)
[file driver.py]
from other import test
input = b'x' * 512
assert test(input) == input
[case testLibrtDependencyInImportedFile_experimental_librt]
# Test that a compiled file (other.py) that does not depend on librt can import another compiled
# file (native.py) that does.
from librt.vecs import vec, append, pop
def call_append(s: str) -> str:
v = vec[str]()
v = append(v, s)
_, rv = pop(v)
return rv
[file other.py]
from native import call_append
def test_append() -> None:
assert call_append("test123") == "test123"
[file driver.py]
from other import test_append
test_append()
[case testIndirectLibrtDependency_experimental_librt]
# Test that a compiled file (other.py) that indirectly depends on librt can import another compiled
# file (native.py) that directly depends on it.
from librt.strings import BytesWriter, write_i16_le
from librt.vecs import vec, append, pop
from mypy_extensions import i64
glob_bw = BytesWriter()
glob_vec = vec[str](["one", "two", "three"])
def fn_returns_bw(b: bytes) -> BytesWriter:
w = BytesWriter()
w.write(b)
return w
def fn_returns_vec(i: i64) -> vec[i64]:
v = vec[i64]()
v = append(v, i)
return v
class ClassWithLibrtTypeMember:
def __init__(self, w: BytesWriter, v: vec[str]) -> None:
self.writer = w
self.vec = vec[vec[str]]([v])
def method_returns_bw(self) -> BytesWriter:
return self.writer
def method_returns_vec(self) -> vec[vec[str]]:
return self.vec
[file other.py]
import struct
from native import (
glob_bw, glob_vec, fn_returns_bw, fn_returns_vec, ClassWithLibrtTypeMember, write_i16_le, pop
)
from mypy_extensions import i64
def test_global(b: bytes) -> None:
glob_bw.write(b)
assert glob_bw.getvalue() == b
glob_vec[1] = "not two"
assert glob_vec[1] == "not two"
def test_fn(b: bytes, i: i64) -> None:
assert fn_returns_bw(b).getvalue() == b
assert fn_returns_vec(i)[0] == i
def test_class(b: bytes) -> None:
c = ClassWithLibrtTypeMember(glob_bw, glob_vec)
assert c.method_returns_bw().getvalue() == b
assert c.method_returns_vec()[0] == glob_vec
def test_reexport() -> None:
write_i16_le(glob_bw, 42)
assert glob_bw.getvalue()[-2:] == struct.pack("<h", 42)
glob_vec, s = pop(glob_vec)
assert len(glob_vec) == 2
assert s == "three"
[file driver.py]
from other import test_global, test_fn, test_class, test_reexport
input = b'x' * 512
test_global(input)
test_fn(input, 512)
test_class(input)
test_reexport()
[case testLibrtInternalInImportedFile_librt_internal]
from librt.internal import ReadBuffer, WriteBuffer, write_str, read_str, cache_version
def get_buffer_round_trip_result(s: str) -> str:
assert cache_version() == 0
w = WriteBuffer()
write_str(w, s)
r = ReadBuffer(w.getvalue())
return read_str(r)
[file other.py]
from native import get_buffer_round_trip_result
def test_buffer_round_trip() -> None:
assert get_buffer_round_trip_result("foo") == "foo"
[file driver.py]
from other import test_buffer_round_trip
test_buffer_round_trip()