blob: 467876303e630d2cca71efb64925fc7a8edbf6fc [file]
from __future__ import annotations
import tempfile
import unittest
from pathlib import Path
import pytest
from mypy import build
from mypy.options import Options
from mypyc.build import construct_groups
from mypyc.codegen import emitmodule
from mypyc.errors import Errors
from mypyc.irbuild.mapper import Mapper
from mypyc.options import CompilerOptions
class FakeSCC:
def __init__(self, mod_ids: list[str]) -> None:
self.mod_ids = mod_ids
class TestEmitModule(unittest.TestCase):
def test_compile_modules_to_ir_orders_scc_members_deterministically(self) -> None:
with tempfile.TemporaryDirectory() as tmp_dir, pytest.MonkeyPatch.context() as monkeypatch:
tmp_path = Path(tmp_dir)
a_py = tmp_path / "a.py"
b_py = tmp_path / "b.py"
a_py.write_text("import b\n\nclass A: pass\nclass C(A): pass\n", encoding="utf-8")
b_py.write_text(
"import a\n\nclass B(a.A): pass\nclass D(a.A): pass\n", encoding="utf-8"
)
sources = [
build.BuildSource(str(a_py), "a", None),
build.BuildSource(str(b_py), "b", None),
]
options = Options()
options.preserve_asts = True
options.mypy_path = [str(tmp_path)]
options.cache_dir = str(tmp_path / ".mypy_cache")
for source in sources:
options.per_module_options.setdefault(source.module, {})["mypyc"] = True
compiler_options = CompilerOptions(strict_traceback_checks=True)
groups = construct_groups(
sources, False, use_shared_lib=True, group_name_override=None
)
result = emitmodule.parse_and_typecheck(sources, options, compiler_options, groups)
try:
group_map = {
source.module: lib_name for group, lib_name in groups for source in group
}
children_by_order = []
for order in (["a", "b"], ["b", "a"]):
monkeypatch.setattr(
emitmodule,
"sorted_components",
lambda graph, order=order: [FakeSCC(order)],
)
mapper = Mapper(group_map)
errors = Errors(options)
modules = emitmodule.compile_modules_to_ir(
result, mapper, compiler_options, errors
)
assert errors.num_errors == 0, errors.new_messages()
classes = {
cl.fullname: cl for module in modules.values() for cl in module.classes
}
children = classes["a.A"].children
assert children is not None
children_by_order.append([child.fullname for child in children])
assert children_by_order[1] == children_by_order[0]
finally:
result.manager.metastore.close()