mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Compare update_lib contents and benchmark CPython parsing consistently (#9393)
Assisted-by: Codex:GPT-6
This commit is contained in:
1 parent
cdb39399bd
commit
248f334844
4 files changed
+57
-8
No files matched your search
@@ -54,6 +54,9 @@ in two ways:
|
|||||||
1. The time to parse the file to AST
|
1. The time to parse the file to AST
|
||||||
2. The time it takes to execute the file
|
2. The time it takes to execute the file
|
||||||
|
|
||||||
|
Parsing stops at an AST in both implementations. The CPython reference uses
|
||||||
|
`compile(..., flags=ast.PyCF_ONLY_AST)` without compiling bytecode.
|
||||||
|
|
||||||
Execution includes compilation and runs each iteration with a fresh namespace whose `__name__`
|
Execution includes compilation and runs each iteration with a fresh namespace whose `__name__`
|
||||||
is `"__main__"`, so script entry points run in both RustPython and CPython.
|
is `"__main__"`, so script entry points run in both RustPython and CPython.
|
||||||
|
|
||||||
|
|||||||
@@ -95,9 +95,14 @@ pub fn benchmark_file_parsing(
|
|||||||
let builtins = pyo3::types::PyModule::import(py, "builtins")
|
let builtins = pyo3::types::PyModule::import(py, "builtins")
|
||||||
.expect("Failed to import builtins");
|
.expect("Failed to import builtins");
|
||||||
let compile = builtins.getattr("compile").expect("no compile in builtins");
|
let compile = builtins.getattr("compile").expect("no compile in builtins");
|
||||||
|
let ast = pyo3::types::PyModule::import(py, "ast").expect("Failed to import ast");
|
||||||
|
let only_ast: i32 = ast
|
||||||
|
.getattr("PyCF_ONLY_AST")
|
||||||
|
.and_then(|flag| flag.extract())
|
||||||
|
.expect("no PyCF_ONLY_AST in ast");
|
||||||
b.iter(|| {
|
b.iter(|| {
|
||||||
let x = compile
|
let x = compile
|
||||||
.call1((contents, name, "exec"))
|
.call1((contents, name, "exec", only_ast))
|
||||||
.expect("Failed to parse code");
|
.expect("Failed to parse code");
|
||||||
black_box(x);
|
black_box(x);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -222,11 +222,29 @@ def get_cpython_dir(src_path: pathlib.Path) -> pathlib.Path:
|
|||||||
# === Comparison utilities ===
|
# === Comparison utilities ===
|
||||||
|
|
||||||
|
|
||||||
|
def _files_are_same(left: pathlib.Path, right: pathlib.Path) -> bool:
|
||||||
|
# Recheck contents even when size and timestamps match, including after a
|
||||||
|
# previous comparison. filecmp caches results by those metadata alone.
|
||||||
|
with left.open("rb") as left_file, right.open("rb") as right_file:
|
||||||
|
while True:
|
||||||
|
chunk = left_file.read(65536)
|
||||||
|
if chunk != right_file.read(65536):
|
||||||
|
return False
|
||||||
|
if not chunk:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def _dircmp_is_same(dcmp: filecmp.dircmp) -> bool:
|
def _dircmp_is_same(dcmp: filecmp.dircmp) -> bool:
|
||||||
"""Recursively check if two directories are identical."""
|
"""Recursively check if two directories are identical."""
|
||||||
if dcmp.diff_files or dcmp.left_only or dcmp.right_only:
|
if dcmp.left_only or dcmp.right_only or dcmp.common_funny:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
for name in dcmp.common_files:
|
||||||
|
if not _files_are_same(
|
||||||
|
pathlib.Path(dcmp.left) / name, pathlib.Path(dcmp.right) / name
|
||||||
|
):
|
||||||
|
return False
|
||||||
|
|
||||||
for subdir in dcmp.subdirs.values():
|
for subdir in dcmp.subdirs.values():
|
||||||
if not _dircmp_is_same(subdir):
|
if not _dircmp_is_same(subdir):
|
||||||
return False
|
return False
|
||||||
@@ -236,14 +254,17 @@ def _dircmp_is_same(dcmp: filecmp.dircmp) -> bool:
|
|||||||
|
|
||||||
def compare_paths(cpython_path: pathlib.Path, local_path: pathlib.Path) -> bool:
|
def compare_paths(cpython_path: pathlib.Path, local_path: pathlib.Path) -> bool:
|
||||||
"""Compare a CPython path with a local path (file or directory)."""
|
"""Compare a CPython path with a local path (file or directory)."""
|
||||||
if not local_path.exists():
|
if not cpython_path.exists() or not local_path.exists():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if cpython_path.is_file():
|
try:
|
||||||
return filecmp.cmp(cpython_path, local_path, shallow=False)
|
if cpython_path.is_file():
|
||||||
|
return local_path.is_file() and _files_are_same(cpython_path, local_path)
|
||||||
dcmp = filecmp.dircmp(cpython_path, local_path)
|
if not cpython_path.is_dir() or not local_path.is_dir():
|
||||||
return _dircmp_is_same(dcmp)
|
return False
|
||||||
|
return _dircmp_is_same(filecmp.dircmp(cpython_path, local_path))
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def compare_file_contents(
|
def compare_file_contents(
|
||||||
|
|||||||
@@ -325,6 +325,26 @@ import nonexistent
|
|||||||
class TestDircmpIsSame(unittest.TestCase):
|
class TestDircmpIsSame(unittest.TestCase):
|
||||||
"""Tests for _dircmp_is_same function."""
|
"""Tests for _dircmp_is_same function."""
|
||||||
|
|
||||||
|
def test_matching_metadata(self):
|
||||||
|
import os
|
||||||
|
|
||||||
|
from update_lib.file_utils import compare_paths
|
||||||
|
|
||||||
|
with tempfile.TemporaryDirectory() as tmpdir:
|
||||||
|
left, right = (pathlib.Path(tmpdir) / name for name in ("left", "right"))
|
||||||
|
for directory in (left, right):
|
||||||
|
(directory / "nested").mkdir(parents=True)
|
||||||
|
(directory / "nested/module.py").write_bytes(b"x = 1\n")
|
||||||
|
source, destination = (p / "nested/module.py" for p in (left, right))
|
||||||
|
timestamp = source.stat().st_mtime_ns
|
||||||
|
os.utime(destination, ns=(timestamp, timestamp))
|
||||||
|
self.assertTrue(compare_paths(source, destination))
|
||||||
|
self.assertTrue(compare_paths(left, right))
|
||||||
|
destination.write_bytes(b"x = 2\n")
|
||||||
|
os.utime(destination, ns=(timestamp, timestamp))
|
||||||
|
self.assertFalse(compare_paths(source, destination))
|
||||||
|
self.assertFalse(compare_paths(left, right))
|
||||||
|
|
||||||
def test_identical_directories(self):
|
def test_identical_directories(self):
|
||||||
"""Test that identical directories return True."""
|
"""Test that identical directories return True."""
|
||||||
import filecmp
|
import filecmp
|
||||||
|
|||||||
Reference in new issue
Block a user