Skip to content

Commit dc066d2

Browse files
Add _PyPickle_GetXIData().
1 parent 606003f commit dc066d2

File tree

6 files changed

+1090
-30
lines changed

6 files changed

+1090
-30
lines changed

Include/internal/pycore_crossinterp.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,13 @@ PyAPI_FUNC(_PyBytes_data_t *) _PyBytes_GetXIDataWrapped(
171171
xid_newobjfunc,
172172
_PyXIData_t *);
173173

174+
// _PyObject_GetXIData() for pickle
175+
PyAPI_DATA(PyObject *) _PyPickle_LoadFromXIData(_PyXIData_t *);
176+
PyAPI_FUNC(int) _PyPickle_GetXIData(
177+
PyThreadState *,
178+
PyObject *,
179+
_PyXIData_t *);
180+
174181

175182
/* using cross-interpreter data */
176183

Lib/test/_crossinterp_definitions.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ def ham_C_closure(z):
100100
ham_C_closure, *_ = eggs_closure_C(2)
101101

102102

103-
FUNCTIONS = [
103+
TOP_FUNCTIONS = [
104104
# shallow
105105
spam_minimal,
106106
spam_full,
@@ -112,6 +112,8 @@ def ham_C_closure(z):
112112
spam_NC,
113113
spam_CN,
114114
spam_CC,
115+
]
116+
NESTED_FUNCTIONS = [
115117
# inner func
116118
eggs_nested,
117119
eggs_closure,
@@ -125,6 +127,13 @@ def ham_C_closure(z):
125127
ham_C_nested,
126128
ham_C_closure,
127129
]
130+
FUNCTIONS = [
131+
*TOP_FUNCTIONS,
132+
*NESTED_FUNCTIONS,
133+
]
134+
135+
136+
# XXX set dishonest __file__, __module__, __name__
128137

129138

130139
#######################################
@@ -202,6 +211,13 @@ def __init__(self, a, b, c):
202211
# __str__
203212
# ...
204213

214+
def __eq__(self, other):
215+
if not isinstance(other, SpamFull):
216+
return NotImplemented
217+
return (self.a == other.a and
218+
self.b == other.b and
219+
self.c == other.c)
220+
205221
@property
206222
def prop(self):
207223
return True
@@ -222,9 +238,47 @@ class EggsNested:
222238
EggsNested = class_eggs_inner()
223239

224240

241+
TOP_CLASSES = {
242+
Spam: (),
243+
SpamOkay: (),
244+
SpamFull: (1, 2, 3),
245+
SubSpamFull: (1, 2, 3),
246+
SubTuple: ([1, 2, 3],),
247+
}
248+
CLASSES_WITHOUT_EQUALITY = [
249+
Spam,
250+
SpamOkay,
251+
]
252+
BUILTIN_SUBCLASSES = [
253+
SubTuple,
254+
]
255+
NESTED_CLASSES = {
256+
EggsNested: (),
257+
}
258+
CLASSES = {
259+
**TOP_CLASSES,
260+
**NESTED_CLASSES,
261+
}
262+
225263

226264
#######################################
227265
# exceptions
228266

229267
class MimimalError(Exception):
230268
pass
269+
270+
271+
class RichError(Exception):
272+
def __init__(self, msg, value=None):
273+
super().__init__(msg, value)
274+
self.msg = msg
275+
self.value = value
276+
277+
def __eq__(self, other):
278+
if not isinstance(other, RichError):
279+
return NotImplemented
280+
if self.msg != other.msg:
281+
return False
282+
if self.value != other.value:
283+
return False
284+
return True

Lib/test/support/import_helper.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import contextlib
22
import _imp
33
import importlib
4+
import importlib.machinery
45
import importlib.util
56
import os
67
import shutil
@@ -332,3 +333,110 @@ def ensure_lazy_imports(imported_module, modules_to_block):
332333
)
333334
from .script_helper import assert_python_ok
334335
assert_python_ok("-S", "-c", script)
336+
337+
338+
@contextlib.contextmanager
339+
def module_restored(name):
340+
"""A context manager that restores a module to the original state."""
341+
missing = name in sys.modules
342+
orig = sys.modules.get(name)
343+
if orig is None:
344+
mod = importlib.import_module(name)
345+
else:
346+
mod = type(sys)(name)
347+
mod.__dict__.update(orig.__dict__)
348+
sys.modules[name] = mod
349+
try:
350+
yield mod
351+
finally:
352+
if missing:
353+
sys.modules.pop(name, None)
354+
else:
355+
sys.modules[name] = orig
356+
357+
358+
def create_module(name, loader=None, *, ispkg=False):
359+
"""Return a new, empty module."""
360+
spec = importlib.machinery.ModuleSpec(
361+
name,
362+
loader,
363+
origin='<import_helper>',
364+
is_package=ispkg,
365+
)
366+
return importlib.util.module_from_spec(spec)
367+
368+
369+
def _ensure_module(name, ispkg, addparent, clearnone):
370+
try:
371+
mod = orig = sys.modules[name]
372+
except KeyError:
373+
mod = orig = None
374+
missing = True
375+
else:
376+
missing = False
377+
if mod is not None:
378+
# It was already imported.
379+
return mod, orig, missing
380+
# Otherwise, None means it was explicitly disabled.
381+
382+
assert name != '__main__'
383+
if not missing:
384+
assert orig is None, (name, sys.modules[name])
385+
if not clearnone:
386+
raise ModuleNotFoundError(name)
387+
del sys.modules[name]
388+
# Try normal import, then fall back to adding the module.
389+
try:
390+
mod = importlib.import_module(name)
391+
except ModuleNotFoundError:
392+
if addparent and not clearnone:
393+
addparent = None
394+
mod = _add_module(name, ispkg, addparent)
395+
return mod, orig, missing
396+
397+
398+
def _add_module(spec, ispkg, addparent):
399+
if isinstance(spec, str):
400+
name = spec
401+
mod = create_module(name, ispkg=ispkg)
402+
spec = mod.__spec__
403+
else:
404+
name = spec.name
405+
mod = importlib.util.module_from_spec(spec)
406+
sys.modules[name] = mod
407+
if addparent is not False and spec.parent:
408+
_ensure_module(spec.parent, True, addparent, bool(addparent))
409+
return mod
410+
411+
412+
def add_module(spec, *, parents=True):
413+
"""Return the module after creating it and adding it to sys.modules.
414+
415+
If parents is True then also create any missing parents.
416+
"""
417+
return _add_module(spec, False, parents)
418+
419+
420+
def add_package(spec, *, parents=True):
421+
"""Return the module after creating it and adding it to sys.modules.
422+
423+
If parents is True then also create any missing parents.
424+
"""
425+
return _add_module(spec, True, parents)
426+
427+
428+
def ensure_module_imported(name, *, clearnone=True):
429+
"""Return the corresponding module.
430+
431+
If it was already imported then return that. Otherwise, try
432+
importing it (optionally clear it first if None). If that fails
433+
then create a new empty module.
434+
435+
It can be helpful to combine this with ready_to_import() and/or
436+
isolated_modules().
437+
"""
438+
if sys.modules.get(name) is not None:
439+
mod = sys.modules[name]
440+
else:
441+
mod, _, _ = _force_import(name, False, True, clearnone)
442+
return mod

0 commit comments

Comments
 (0)