Files
youknowdot 9f6f771965 Align lazy imports and f/t-string interpolation with Python 3.15 (#9179)
* Preserve interpolation source text and canonical metadata

Source-only checkpoint; candidate validation and the existing annotation expectation reconciliation remain pending.

Assisted-by: OpenAI Codex:model version unavailable

* Align existing annotation expectations with CPython metadata

Update only the nine existing expected strings confirmed against pinned CPython 3.15, with explicit user approval.

Assisted-by: OpenAI Codex:model version unavailable

* Preserve template metadata through compilation and interactive input

Escape literal debug prefixes, retain None AST expression metadata internally, and continue incomplete triple-quoted t-strings in the existing shell.

Assisted-by: OpenAI Codex:model version unavailable

* Classify normalized unclosed brackets as REPL line continuations

Assisted-by: OpenAI Codex:model version unavailable

* Nest equivalent REPL parse-error alternatives for Clippy

Assisted-by: OpenAI Codex:model version unavailable

* Remove fulfilled annotation migration lint workaround

The canonical expected strings no longer trigger literal_string_with_formatting_args, so the previous lint expectation is obsolete.

Assisted-by: OpenAI Codex:model version unavailable

* Complete lazy-import exception and traceback library closure

Copy canonical traceback and legacy exception mappings with preserved RustPython guards. Copy explicit non-Python library assets by exact path so exception hierarchy data does not expand into the entire test package.

Assisted-by: OpenAI Codex:model version unavailable

* Provide Python 3.15 traceback metadata for missing modules and attributes

Preserve AttributeError context for missing class attribute deletion, matching type_update_dict. Expose canonical generated missing-stdlib messages through the native sysconfig modules without importing CPython build-specific disabled-module assumptions.

Assisted-by: OpenAI Codex:model version unavailable
2026-10-18 17:11:26 +09:00

181 lines
7.1 KiB
Python

"""Tests for copy_lib.py - library copying with dependencies."""
import contextlib
import pathlib
import tempfile
import unittest
class TestCopySingle(unittest.TestCase):
"""Tests for _copy_single helper function."""
def test_copies_file(self):
"""Test copying a single file."""
from update_lib.cmd_copy_lib import _copy_single
with tempfile.TemporaryDirectory() as tmpdir:
tmpdir = pathlib.Path(tmpdir)
src = tmpdir / "source.py"
src.write_text("content")
dst = tmpdir / "dest.py"
_copy_single(src, dst, verbose=False)
self.assertTrue(dst.exists())
self.assertEqual(dst.read_text(), "content")
def test_copies_directory(self):
"""Test copying a directory."""
from update_lib.cmd_copy_lib import _copy_single
with tempfile.TemporaryDirectory() as tmpdir:
tmpdir = pathlib.Path(tmpdir)
src = tmpdir / "source_dir"
src.mkdir()
(src / "file.py").write_text("content")
dst = tmpdir / "dest_dir"
_copy_single(src, dst, verbose=False)
self.assertTrue(dst.exists())
self.assertTrue((dst / "file.py").exists())
def test_removes_existing_before_copy(self):
"""Test that existing destination is removed before copy."""
from update_lib.cmd_copy_lib import _copy_single
with tempfile.TemporaryDirectory() as tmpdir:
tmpdir = pathlib.Path(tmpdir)
src = tmpdir / "source.py"
src.write_text("new content")
dst = tmpdir / "dest.py"
dst.write_text("old content")
_copy_single(src, dst, verbose=False)
self.assertEqual(dst.read_text(), "new content")
def test_directory_copy_excludes_bytecode_cache_directories(self):
from update_lib.cmd_copy_lib import _copy_single
with tempfile.TemporaryDirectory() as tmpdir:
root = pathlib.Path(tmpdir)
src = root / "source"
dst = root / "destination"
for relative in ("__pycache__", "package/__pycache__", "assets"):
(src / relative).mkdir(parents=True)
files = {
"__init__.py": b"source\n",
"package/module.py": b"nested source\n",
"assets/data.bin": b"\x00\xffasset",
"assets/__pycache__": b"ordinary file, not a directory",
"assets/fixture.pyc": b"canonical bytecode fixture",
"__pycache__/module.cpython-315.pyc": b"stale cache",
"package/__pycache__/module.cpython-315.pyc": b"nested cache",
}
for relative, content in files.items():
(src / relative).write_bytes(content)
_copy_single(src, dst, verbose=False)
expected = {
relative: content
for relative, content in files.items()
if "__pycache__" not in pathlib.Path(relative).parts[:-1]
}
actual = {
path.relative_to(dst).as_posix(): path.read_bytes()
for path in dst.rglob("*")
if path.is_file()
}
self.assertEqual(actual, expected)
self.assertFalse((dst / "__pycache__").exists())
self.assertFalse((dst / "package/__pycache__").exists())
for relative, content in files.items():
self.assertEqual((src / relative).read_bytes(), content)
class TestCopyLib(unittest.TestCase):
"""Tests for copy_lib function."""
def test_nested_data_file_preserves_siblings(self):
from update_lib.cmd_copy_lib import copy_lib
for name in ("hierarchy.txt", "fixture.bin", "README"):
with self.subTest(name=name), tempfile.TemporaryDirectory() as tmpdir:
root = pathlib.Path(tmpdir)
source = root / "cpython/Lib/test/data" / name
source.parent.mkdir(parents=True)
source.write_bytes(b"canonical\x00\xff\n")
(source.parent / "other.txt").write_bytes(b"unselected source")
target = root / "Lib/test/data" / name
target.parent.mkdir(parents=True)
target.write_bytes(b"old")
sibling = root / "Lib/test/test_local.py"
sibling.write_bytes(b"local guards\n")
with contextlib.chdir(root):
copy_lib(source, verbose=False)
self.assertEqual(target.read_bytes(), source.read_bytes())
self.assertEqual(sibling.read_bytes(), b"local guards\n")
self.assertFalse((target.parent / "other.txt").exists())
def test_missing_data_file_does_not_copy_containing_package(self):
from update_lib.cmd_copy_lib import copy_lib
with tempfile.TemporaryDirectory() as tmpdir:
root = pathlib.Path(tmpdir)
source = root / "cpython/Lib/test/missing.txt"
source.parent.mkdir(parents=True)
(source.parent / "other.py").write_text("unselected source")
sibling = root / "Lib/test/test_local.py"
sibling.parent.mkdir(parents=True)
sibling.write_bytes(b"local guards\n")
with contextlib.chdir(root), self.assertRaises(FileNotFoundError):
copy_lib(source, verbose=False)
self.assertEqual(sibling.read_bytes(), b"local guards\n")
self.assertFalse((sibling.parent / "other.py").exists())
def test_python_module_still_copies_hard_dependencies(self):
from update_lib.cmd_copy_lib import copy_lib
with tempfile.TemporaryDirectory() as tmpdir:
root = pathlib.Path(tmpdir)
source = root / "cpython/Lib"
source.mkdir(parents=True)
for name in ("pickle.py", "_compat_pickle.py"):
(source / name).write_text(name)
with contextlib.chdir(root):
copy_lib(source / "pickle.py", verbose=False)
for name in ("pickle.py", "_compat_pickle.py"):
self.assertEqual((root / "Lib" / name).read_text(), name)
def test_package_still_copies_directory(self):
from update_lib.cmd_copy_lib import copy_lib
with tempfile.TemporaryDirectory() as tmpdir:
root = pathlib.Path(tmpdir)
source = root / "cpython/Lib/json"
source.mkdir(parents=True)
for name in ("__init__.py", "decoder.py"):
(source / name).write_text(name)
with contextlib.chdir(root):
copy_lib(source, verbose=False)
for name in ("__init__.py", "decoder.py"):
self.assertEqual((root / "Lib/json" / name).read_text(), name)
def test_raises_on_path_without_lib(self):
"""Test that copy_lib raises ValueError when path doesn't contain /Lib/."""
from update_lib.cmd_copy_lib import copy_lib
with self.assertRaises(ValueError) as ctx:
copy_lib(pathlib.Path("some/path/without/lib.py"))
self.assertIn("/Lib/", str(ctx.exception))
if __name__ == "__main__":
unittest.main()