886 lines
14 KiB
Plaintext
886 lines
14 KiB
Plaintext
-- 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
|
|
def f(x: int) -> int:
|
|
from p.other import h
|
|
return 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
|
|
[file driver.py]
|
|
import native
|
|
from native import f
|
|
from p.other import g
|
|
assert f(3) == 7
|
|
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 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 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_extensions 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
|
|
|
|
[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_extensions 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_extensions 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_extensions import Final
|
|
X: Final = 10
|
|
|
|
[file other.py.2]
|
|
from typing_extensions 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 native, 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
|