Skip to content

Commit ddace94

Browse files
committed
Keep the copied bootstrap unchanged in the native relocation PR
Restore the exact CPython 3.14 bootstrap and retain only the private exact-dict relocation primitive and its direct native regressions. Remove the PR-added callback integration tests while preserving native helper assertions. This prepares a primitive only; imports do not call it and the import race remains unresolved. Assisted-by: Codex:model-version-unavailable
1 parent 5dab876 commit ddace94

3 files changed

Lines changed: 10 additions & 293 deletions

File tree

‎Lib/importlib/_bootstrap.py‎

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -844,19 +844,6 @@ def _module_repr_from_spec(spec):
844844
return f'<module {spec.name!r} ({spec.origin})>'
845845

846846

847-
def _reorder_module(spec):
848-
# RustPython: an exact dict can update shutdown order without exposing a
849-
# temporarily absent module to another importing thread.
850-
modules = sys.modules
851-
if type(modules) is dict and hasattr(_imp, '_dict_move_to_end'):
852-
return _imp._dict_move_to_end(modules, spec.name)
853-
# Preserve custom pop/setitem behavior, including a pop that rebinds
854-
# sys.modules or changes spec.name. CPython also uses this fallback.
855-
module = sys.modules.pop(spec.name)
856-
sys.modules[spec.name] = module
857-
return module
858-
859-
860847
# Used by importlib.reload() and _load_module_shim().
861848
def _exec(spec, module):
862849
"""Execute the spec's specified module in an existing module's namespace."""
@@ -883,7 +870,8 @@ def _exec(spec, module):
883870
finally:
884871
# Update the order of insertion into sys.modules for module
885872
# clean-up at shutdown.
886-
module = _reorder_module(spec)
873+
module = sys.modules.pop(spec.name)
874+
sys.modules[spec.name] = module
887875
return module
888876

889877

@@ -894,11 +882,13 @@ def _load_backward_compatible(spec):
894882
spec.loader.load_module(spec.name)
895883
except:
896884
if spec.name in sys.modules:
897-
module = _reorder_module(spec)
885+
module = sys.modules.pop(spec.name)
886+
sys.modules[spec.name] = module
898887
raise
899888
# The module must be in sys.modules at this point!
900889
# Move it to the end of sys.modules.
901-
module = _reorder_module(spec)
890+
module = sys.modules.pop(spec.name)
891+
sys.modules[spec.name] = module
902892
if getattr(module, '__loader__', None) is None:
903893
try:
904894
module.__loader__ = spec.loader
@@ -956,7 +946,8 @@ def _load_unlocked(spec):
956946
# We don't ensure that the import-related module attributes get
957947
# set in the sys.modules replacement case. Such modules are on
958948
# their own.
959-
module = _reorder_module(spec)
949+
module = sys.modules.pop(spec.name)
950+
sys.modules[spec.name] = module
960951
_verbose_message('import {!r} # {!r}', spec.name, spec.loader)
961952
finally:
962953
spec._initializing = False

‎crates/vm/src/stdlib/_imp.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ mod _imp {
200200

201201
use super::FrozenError;
202202

203-
// Keep sys.modules entries present while importlib updates shutdown order.
203+
// Private exact-dict relocation primitive for future import-cache ordering.
204204
#[pyfunction]
205205
fn _dict_move_to_end(
206206
modules: PyRefExact<PyDict>,
Lines changed: 1 addition & 275 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,7 @@
1-
"""Import-cache ordering must not temporarily remove an exact-dict entry.
2-
3-
The trace-visible presence assertion is a RustPython atomicity invariant, not
4-
an assertion supplied by CPython's old pop/set bootstrap. CPython still checks
5-
the fallback's value, ordering, exception and custom-mapping semantics here.
6-
"""
1+
"""Private exact-dict relocation and callback-reentry regression coverage."""
72

83
import _imp
9-
import os
104
import sys
11-
import types
12-
from importlib import _bootstrap as frozen
135

146

157
def raises(kind, call, expected=None):
@@ -22,258 +14,6 @@ def raises(kind, call, expected=None):
2214
raise AssertionError(f"{kind.__name__} was not raised")
2315

2416

25-
def source_bootstrap():
26-
path = os.path.join(
27-
os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
28-
"Lib",
29-
"importlib",
30-
"_bootstrap.py",
31-
)
32-
source = types.ModuleType("atomic_reorder_source_bootstrap")
33-
with open(path, encoding="utf-8") as stream:
34-
exec(compile(stream.read(), path, "exec"), source.__dict__)
35-
for name in (
36-
"sys",
37-
"_imp",
38-
"_thread",
39-
"_warnings",
40-
"_weakref",
41-
"_bootstrap_external",
42-
):
43-
setattr(source, name, getattr(frozen, name))
44-
source._blocking_on = source._WeakValueDictionary()
45-
return source
46-
47-
48-
class Loader:
49-
def __init__(self, action):
50-
self.action = action
51-
52-
def create_module(self, spec):
53-
return None
54-
55-
def exec_module(self, module):
56-
self.action(module)
57-
58-
59-
def invoke(bootstrap, action, mode="load"):
60-
name = "_atomic_reorder_test"
61-
spec = bootstrap.ModuleSpec(name, Loader(action))
62-
if mode == "exec":
63-
module = bootstrap.module_from_spec(spec)
64-
sys.modules[name] = module
65-
return bootstrap._exec(spec, module)
66-
return bootstrap._load_unlocked(spec)
67-
68-
69-
def check_trace_presence(bootstrap, mode):
70-
original = sys.modules
71-
old_trace = sys.gettrace()
72-
name = "_atomic_reorder_trace"
73-
expected = types.ModuleType(name)
74-
after = "_atomic_reorder_trace_after"
75-
state = {"armed": False, "events": 0}
76-
failure = RuntimeError("legacy loader failed with its entry still present")
77-
codes = {
78-
bootstrap._exec.__code__,
79-
bootstrap._load_unlocked.__code__,
80-
}
81-
if hasattr(bootstrap, "_load_backward_compatible"):
82-
codes.add(bootstrap._load_backward_compatible.__code__)
83-
if hasattr(bootstrap, "_reorder_module"):
84-
codes.add(bootstrap._reorder_module.__code__)
85-
86-
def trace(frame, event, arg):
87-
if event == "line" and state["armed"] and frame.f_code in codes:
88-
state["events"] += 1
89-
assert name in sys.modules, (mode, frame.f_code.co_name, frame.f_lineno)
90-
assert sys.modules[name] is expected
91-
return trace
92-
93-
def finish(module):
94-
sys.modules[name] = expected
95-
sys.modules[after] = object()
96-
state["armed"] = True
97-
98-
class LegacyLoader:
99-
def load_module(self, fullname):
100-
assert fullname == name
101-
finish(expected)
102-
if mode == "legacy_error":
103-
raise failure
104-
return expected
105-
106-
try:
107-
sys.modules = original.copy()
108-
loader = LegacyLoader() if mode.startswith("legacy") else Loader(finish)
109-
spec = bootstrap.ModuleSpec(name, loader)
110-
if mode == "exec":
111-
initial = bootstrap.module_from_spec(spec)
112-
sys.modules[name] = initial
113-
call = lambda: bootstrap._exec(spec, initial)
114-
elif mode.startswith("legacy"):
115-
call = lambda: bootstrap._load_backward_compatible(spec)
116-
else:
117-
call = lambda: bootstrap._load_unlocked(spec)
118-
sys.settrace(trace)
119-
if mode == "legacy_error":
120-
raises(RuntimeError, call, failure)
121-
else:
122-
assert call() is expected
123-
sys.settrace(old_trace)
124-
assert state["events"] > 0, "the successful loader window was not traced"
125-
assert list(sys.modules)[-2:] == [after, name]
126-
finally:
127-
sys.settrace(old_trace)
128-
sys.modules = original
129-
130-
131-
def check_loader_semantics(bootstrap):
132-
original = sys.modules
133-
name = "_atomic_reorder_test"
134-
after = "_atomic_reorder_after"
135-
try:
136-
for mode in ("load", "exec"):
137-
for replacement in (object(), None):
138-
sys.modules = original.copy()
139-
140-
def replace(module):
141-
sys.modules[name] = replacement
142-
sys.modules[after] = object()
143-
144-
assert invoke(bootstrap, replace, mode) is replacement
145-
assert sys.modules[name] is replacement
146-
assert list(sys.modules)[-2:] == [after, name]
147-
148-
sys.modules = original.copy()
149-
150-
def remove(module):
151-
del sys.modules[name]
152-
153-
exc = raises(KeyError, lambda: invoke(bootstrap, remove, mode))
154-
assert exc.args == (name,)
155-
assert name not in sys.modules
156-
157-
sys.modules = original.copy()
158-
replacement = object()
159-
rebound = {"before": object(), name: replacement, after: object()}
160-
161-
def rebind(module):
162-
sys.modules = rebound
163-
164-
assert invoke(bootstrap, rebind, mode) is replacement
165-
assert sys.modules is rebound
166-
assert list(rebound) == ["before", after, name]
167-
168-
sys.modules = original.copy()
169-
failure = RuntimeError("loader failure after deliberate removal")
170-
171-
def remove_and_fail(module):
172-
del sys.modules[name]
173-
raise failure
174-
175-
raises(RuntimeError, lambda: invoke(bootstrap, remove_and_fail), failure)
176-
assert name not in sys.modules
177-
178-
sys.modules = original.copy()
179-
180-
def fail_with_entry(module):
181-
sys.modules[after] = object()
182-
raise failure
183-
184-
raises(
185-
RuntimeError, lambda: invoke(bootstrap, fail_with_entry, "exec"), failure
186-
)
187-
assert list(sys.modules)[-2:] == [after, name]
188-
189-
if hasattr(bootstrap, "_load_backward_compatible"):
190-
191-
class LegacyLoader:
192-
def load_module(self, fullname):
193-
sys.modules[fullname] = None
194-
del sys.modules[fullname]
195-
raise failure
196-
197-
spec = bootstrap.ModuleSpec(name, LegacyLoader())
198-
sys.modules = original.copy()
199-
raises(
200-
RuntimeError, lambda: bootstrap._load_backward_compatible(spec), failure
201-
)
202-
assert name not in sys.modules
203-
finally:
204-
sys.modules = original
205-
206-
207-
def check_custom_mappings(bootstrap):
208-
original = sys.modules
209-
name = "_atomic_reorder_custom"
210-
value = object()
211-
events = []
212-
213-
class Subclass(dict):
214-
def pop(self, key):
215-
events.append(("pop", key))
216-
return super().pop(key)
217-
218-
def __setitem__(self, key, value):
219-
events.append(("set", key, value))
220-
super().__setitem__(key, value)
221-
222-
class Mapping:
223-
def __init__(self, pairs):
224-
self.data = dict(pairs)
225-
226-
def pop(self, key):
227-
events.append(("pop", key))
228-
return self.data.pop(key)
229-
230-
def __setitem__(self, key, value):
231-
events.append(("set", key, value))
232-
self.data[key] = value
233-
234-
try:
235-
spec = bootstrap.ModuleSpec(name, None)
236-
for cls in (Subclass, Mapping):
237-
events.clear()
238-
modules = cls([(name, value), ("after", None)])
239-
sys.modules = modules
240-
assert bootstrap._reorder_module(spec) is value
241-
assert events == [("pop", name), ("set", name, value)]
242-
assert list(modules if cls is Subclass else modules.data) == ["after", name]
243-
244-
rebound = Subclass()
245-
new_name = "_atomic_reorder_rebound"
246-
247-
class Rebinding(Subclass):
248-
def pop(self, key):
249-
result = super().pop(key)
250-
sys.modules = rebound
251-
spec.name = new_name
252-
return result
253-
254-
events.clear()
255-
modules = Rebinding({name: value})
256-
sys.modules = modules
257-
assert bootstrap._reorder_module(spec) is value
258-
assert events == [("pop", name), ("set", new_name, value)]
259-
assert sys.modules is rebound
260-
assert rebound[new_name] is value
261-
assert name not in modules
262-
263-
failure = KeyError("custom pop exception")
264-
265-
class Raising(Subclass):
266-
def pop(self, key):
267-
raise failure
268-
269-
events.clear()
270-
sys.modules = Raising({new_name: value})
271-
raises(KeyError, lambda: bootstrap._reorder_module(spec), failure)
272-
assert events == []
273-
finally:
274-
sys.modules = original
275-
276-
27717
def check_native_helper():
27818
move = _imp._dict_move_to_end
27919
first, middle, last = object(), object(), object()
@@ -445,19 +185,5 @@ def __del__(self):
445185
assert list(mapping)[-1] == key
446186

447187

448-
source = source_bootstrap()
449-
for bootstrap in (frozen, source):
450-
if sys.implementation.name == "rustpython":
451-
# Run this before inspecting the new helper so a baseline executable
452-
# fails on the actual pop/set gap, not just a missing private API.
453-
modes = ("load", "exec")
454-
if hasattr(bootstrap, "_load_backward_compatible"):
455-
modes += ("legacy", "legacy_error")
456-
for mode in modes:
457-
check_trace_presence(bootstrap, mode)
458-
check_loader_semantics(bootstrap)
459-
if hasattr(bootstrap, "_reorder_module"):
460-
check_custom_mappings(bootstrap)
461-
462188
if sys.implementation.name == "rustpython":
463189
check_native_helper()

0 commit comments

Comments
 (0)