8000 Add Interpreter.get(). · python/cpython@283ddab · GitHub
[go: up one dir, main page]

Skip to content

Commit 283ddab

Browse files
Add Interpreter.get().
1 parent 8e99e66 commit 283ddab

File tree

3 files changed

+120
-0
lines changed

3 files changed

+120
-0
lines changed

Lib/test/support/interpreters.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,16 @@ def bind(self, ns=None, /, **kwargs):
112112
ns = dict(ns, **kwargs) if ns is not None else kwargs
113113
_interpreters.set___main___attrs(self._id, ns)
114114

115+
# XXX getattr?
116+
def get(self, name, default=None, /):
117+
"""Return the attr value from the interpreter's __main__.
118+
119+
The value must be shareable.
120+
"""
121+
found = _interpreters.get___main___attrs(self._id, (name,), default)
122+
assert len(found) == 1, found
123+
return found[name]
124+
115125
# XXX Rename "run" to "exec"?
116126
# XXX Do not allow init to overwrite (by default)?
117127
def run(self, src_str, /, *, init=None):

Lib/test/test_interpreters.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,36 @@ def test_not_shareable(self):
526526
interp.run('print(spam)')
527527

528528

529+
class TestInterpreterGet(TestBase):
530+
531+
def test_empty(self):
532+
interp = interpreters.create()
533+
with self.assertRaises(TypeError):
534+
interp.get()
535+
536+
def test_found(self):
537+
interp = interpreters.create()
538+
obj1 = interp.get('__name__')
539+
interp.bind(spam=42)
540+
obj2 = interp.get('spam')
541+
542+
self.assertEqual(obj1, '__main__')
543+
self.assertEqual(obj2, 42)
544+
545+
def test_not_found(self):
546+
interp = interpreters.create()
547+
obj1 = interp.get('spam')
548+
obj2 = interp.get('spam', 'eggs')
549+
550+
self.assertIs(obj1, None)
551+
self.assertEqual(obj2, 'eggs')
552+
553+
def test_not_shareable(self):
554+
interp = interpreters.create()
555+
with self.assertRaises(ValueError):
556+
interp.get('__builtins__')
557+
558+
529559
class TestInterpreterRun(TestBase):
530560

531561
def test_success(self):

Modules/_xxsubinterpretersmodule.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,84 @@ PyDoc_STRVAR(set___main___attrs_doc,
456456
\n\
457457
Bind the given attributes in the interpreter's __main__ module.");
458458

459+
static PyObject *
460+
interp_get___main___attrs(PyObject *self, PyObject *args)
461+
{
462+
PyObject *id, *names;
463+
PyObject *dflt = Py_None;
464+
if (!PyArg_ParseTuple(args, "OO|O:" MODULE_NAME ".get___main___attrs",
465+
&id, &names, &dflt))
466+
{
467+
return NULL;
468+
}
469+
470+
// Look up the interpreter.
471+
PyInterpreterState *interp = PyInterpreterID_LookUp(id);
472+
if (interp == NULL) {
473+
return NULL 8000 ;
474+
}
475+
476+
// Prep the result.
477+
PyObject *found = PyDict_New();
478+
if (found == NULL) {
479+
return NULL;
480+
}
481+
482+
// Set up the shared ns.
483+
_PyXI_namespace *shared = _PyXI_NamespaceFromNames(names);
484+
if (shared == NULL) {
485+
if (!PyErr_Occurred()) {
486+
PyErr_SetString(PyExc_ValueError, "expected non-empty list of names");
487+
}
488+
Py_DECREF(found);
489+
return NULL;
490+
}
491+
492+
_PyXI_session session = {0};
493+
494+
// Prep and switch interpreters, including apply the updates.
495+
if (_PyXI_Enter(&session, interp, NULL) < 0) {
496+
Py_DECREF(found);
497+
assert(!PyErr_Occurred());
498+
_PyXI_ApplyCapturedException(&session, NULL);
499+
assert(PyErr_Occurred());
500+
return NULL;
501+
}
502+
503+
// Extract the requested attrs from __main__.
504+
int res = _PyXI_FillNamespaceFromDict(shared, session.main_ns, &session);
505+
506+
// Clean up and switch back.
507+
_PyXI_Exit(&session);
508+
509+
if (res == 0) {
510+
assert(!PyErr_Occurred());
511+
// Copy the objects into the result dict.
512+
if (_PyXI_ApplyNamespace(shared, found, dflt) < 0) {
513+
Py_CLEAR(found);
514+
}
515+
}
516+
else {
517+
if (!PyErr_Occurred()) {
518+
_PyXI_ApplyCapturedException(&session, NULL);
519+
assert(PyErr_Occurred());
520+
}
521+
else {
522+
assert(!_PyXI_HasCapturedException(&session));
523+
}
524+
Py_CLEAR(found);
525+
}
526+
527+
_PyXI_FreeNamespace(shared);
528+
return found;
529+
}
530+
531+
PyDoc_STRVAR(get___main___attrs_doc,
532+
"get___main___attrs(id, names, default=None, /)\n\
533+
\n\
534+
Look up the given attributes in the interpreter's __main__ module.\n\
535+
Return the default if not found.");
536+
459537
static PyUnicodeObject *
460538
convert_script_arg(PyObject *arg, const char *fname, const char *displayname,
461539
const char *expected)
@@ -754,6 +832,8 @@ static PyMethodDef module_functions[] = {
754832

755833
{"set___main___attrs", _PyCFunction_CAST(interp_set___main___attrs),
756834
METH_VARARGS, set___main___attrs_doc},
835+
{"get___main___attrs", _PyCFunction_CAST(interp_get___main___attrs),
836+
METH_VARARGS, get___main___attrs_doc},
757837
{"is_shareable", _PyCFunction_CAST(object_is_shareable),
758838
METH_VARARGS | METH_KEYWORDS, is_shareable_doc},
759839

0 commit comments

Comments
 (0)
0