diff --git a/Doc/library/inspect.rst b/Doc/library/inspect.rst index 850d6018bab..10339641c3b 100644 --- a/Doc/library/inspect.rst +++ b/Doc/library/inspect.rst @@ -95,6 +95,8 @@ attributes: | | __globals__ | global namespace in which | | | | this function was defined | +-----------+-------------------+---------------------------+ +| | __builtins__ | builtins namespace | ++-----------+-------------------+---------------------------+ | | __annotations__ | mapping of parameters | | | | names to annotations; | | | | ``"return"`` key is | @@ -251,6 +253,10 @@ attributes: Add ``cr_origin`` attribute to coroutines. +.. versionchanged:: 3.10 + + Add ``__builtins__`` attribute to functions. + .. function:: getmembers(object[, predicate]) Return all the members of an object in a list of ``(name, value)`` diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index 0fba27c7d58..b903b3e0b81 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -280,6 +280,11 @@ Other Language Changes * Assignment expressions can now be used unparenthesized within set literals and set comprehensions, as well as in sequence indexes (but not slices). +* Functions have a new ``__builtins__`` attribute which is used to look for + builtin symbols when a function is executed, instead of looking into + ``__globals__['__builtins__']``. + (Contributed by Mark Shannon in :issue:`42990`.) + New Modules =========== diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index befb7ab436c..54a4cbed44e 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -682,9 +682,10 @@ class TestNamedTuple(unittest.TestCase): self.assertEqual(np.y, 2) def test_new_builtins_issue_43102(self): - self.assertEqual( - namedtuple('C', ()).__new__.__globals__['__builtins__'], - {}) + obj = namedtuple('C', ()) + new_func = obj.__new__ + self.assertEqual(new_func.__globals__['__builtins__'], {}) + self.assertEqual(new_func.__builtins__, {}) ################################################################################ diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py index 11d68cc75e2..15cf250f192 100644 --- a/Lib/test/test_funcattrs.py +++ b/Lib/test/test_funcattrs.py @@ -73,6 +73,11 @@ class FunctionPropertiesTest(FuncAttrsTest): self.cannot_set_attr(self.b, '__globals__', 2, (AttributeError, TypeError)) + def test___builtins__(self): + self.assertIs(self.b.__builtins__, __builtins__) + self.cannot_set_attr(self.b, '__builtins__', 2, + (AttributeError, TypeError)) + def test___closure__(self): a = 12 def f(): print(a) diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-02-17-19-02-21.bpo-42990.SKXHiI.rst b/Misc/NEWS.d/next/Core and Builtins/2021-02-17-19-02-21.bpo-42990.SKXHiI.rst new file mode 100644 index 00000000000..cc17154762a --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-02-17-19-02-21.bpo-42990.SKXHiI.rst @@ -0,0 +1,3 @@ +Functions have a new ``__builtins__`` attribute which is used to look for +builtin symbols when a function is executed, instead of looking into +``__globals__['__builtins__']``. Patch by Mark Shannon and Victor Stinner. diff --git a/Objects/funcobject.c b/Objects/funcobject.c index b331c4c4d6e..523930da8dc 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -250,6 +250,7 @@ static PyMemberDef func_memberlist[] = { {"__doc__", T_OBJECT, OFF(func_doc), 0}, {"__globals__", T_OBJECT, OFF(func_globals), READONLY}, {"__module__", T_OBJECT, OFF(func_module), 0}, + {"__builtins__", T_OBJECT, OFF(func_builtins), READONLY}, {NULL} /* Sentinel */ };