summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2021-02-20 14:17:18 (GMT)
committerGitHub <noreply@github.com>2021-02-20 14:17:18 (GMT)
commit46496f9d12582bf11f4911ad0f23315d6f277907 (patch)
tree8382b24a5036df07fe75c59f0a45cd401d84b17a /Lib/test
parent4233ff3ee4add287b3617f38943d01a7a6f4d7c4 (diff)
downloadcpython-46496f9d12582bf11f4911ad0f23315d6f277907.zip
cpython-46496f9d12582bf11f4911ad0f23315d6f277907.tar.gz
cpython-46496f9d12582bf11f4911ad0f23315d6f277907.tar.bz2
bpo-42990: Functions inherit current builtins (GH-24564)
The types.FunctionType constructor now inherits the current builtins if the globals dictionary has no "__builtins__" key, rather than using {"None": None} as builtins: same behavior as eval() and exec() functions. Defining a function with "def function(...): ..." in Python is not affected, globals cannot be overriden with this syntax: it also inherits the current builtins. PyFrame_New(), PyEval_EvalCode(), PyEval_EvalCodeEx(), PyFunction_New() and PyFunction_NewWithQualName() now inherits the current builtins namespace if the globals dictionary has no "__builtins__" key. * Add _PyEval_GetBuiltins() function. * _PyEval_BuiltinsFromGlobals() now uses _PyEval_GetBuiltins() if builtins cannot be found in globals. * Add tstate parameter to _PyEval_BuiltinsFromGlobals().
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_funcattrs.py27
1 files changed, 27 insertions, 0 deletions
diff --git a/Lib/test/test_funcattrs.py b/Lib/test/test_funcattrs.py
index 15cf250..77977d0 100644
--- a/Lib/test/test_funcattrs.py
+++ b/Lib/test/test_funcattrs.py
@@ -1,3 +1,4 @@
+import textwrap
import types
import unittest
@@ -78,6 +79,32 @@ class FunctionPropertiesTest(FuncAttrsTest):
self.cannot_set_attr(self.b, '__builtins__', 2,
(AttributeError, TypeError))
+ # bpo-42990: If globals is specified and has no "__builtins__" key,
+ # a function inherits the current builtins namespace.
+ def func(s): return len(s)
+ ns = {}
+ func2 = type(func)(func.__code__, ns)
+ self.assertIs(func2.__globals__, ns)
+ self.assertIs(func2.__builtins__, __builtins__)
+
+ # Make sure that the function actually works.
+ self.assertEqual(func2("abc"), 3)
+ self.assertEqual(ns, {})
+
+ # Define functions using exec() with different builtins,
+ # and test inheritance when globals has no "__builtins__" key
+ code = textwrap.dedent("""
+ def func3(s): pass
+ func4 = type(func3)(func3.__code__, {})
+ """)
+ safe_builtins = {'None': None}
+ ns = {'type': type, '__builtins__': safe_builtins}
+ exec(code, ns)
+ self.assertIs(ns['func3'].__builtins__, safe_builtins)
+ self.assertIs(ns['func4'].__builtins__, safe_builtins)
+ self.assertIs(ns['func3'].__globals__['__builtins__'], safe_builtins)
+ self.assertNotIn('__builtins__', ns['func4'].__globals__)
+
def test___closure__(self):
a = 12
def f(): print(a)