summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorda-woods <dw-git@d-woods.co.uk>2023-02-24 09:04:27 +0000
committerGitHub <noreply@github.com>2023-02-24 10:04:27 +0100
commit8db63cf0944998819fb70d9639d53ff777ec8ac1 (patch)
treef09bb431d34a28e3e7381095bac00939d7f245b1
parent6037b9066f4762e08ca2220922784d1cbd22d4cc (diff)
downloadcython-8db63cf0944998819fb70d9639d53ff777ec8ac1.tar.gz
Make unused **keyword argument show up in locals() (GH-4899)
If you had a function ``` def f(**kwds): return locals() ``` then 'kwds' would not appear in locals. Found while investigating one of the coverage gaps listed in https://github.com/cython/cython/issues/4163. ``` allow_null = all(ref.node.allow_null for ref in self.starstar_arg.entry.cf_references) # 3772 ↛ exit if allow_null: # 3773 ↛ 3774 code.putln("%s = NULL;" % (self.starstar_arg.entry.cname,)) ``` This uncovered code was wrong and has been removed. The only way I can see to have an `allow_null` reference to the ** argument would be to use `locals()`, and in this case an empty dict should be generated.
-rw-r--r--Cython/Compiler/Nodes.py14
-rw-r--r--tests/run/locals.pyx12
2 files changed, 17 insertions, 9 deletions
diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py
index 44c5f0f98..9c320cafa 100644
--- a/Cython/Compiler/Nodes.py
+++ b/Cython/Compiler/Nodes.py
@@ -3934,15 +3934,11 @@ class DefNodeWrapper(FuncDefNode):
self.starstar_arg.entry.cname, self.error_value()))
code.put_gotref(self.starstar_arg.entry.cname, py_object_type)
code.putln("} else {")
- allow_null = all(ref.node.allow_null for ref in self.starstar_arg.entry.cf_references)
- if allow_null:
- code.putln("%s = NULL;" % (self.starstar_arg.entry.cname,))
- else:
- code.putln("%s = PyDict_New();" % (self.starstar_arg.entry.cname,))
- code.putln("if (unlikely(!%s)) return %s;" % (
- self.starstar_arg.entry.cname, self.error_value()))
- code.put_var_gotref(self.starstar_arg.entry)
- self.starstar_arg.entry.xdecref_cleanup = allow_null
+ code.putln("%s = PyDict_New();" % (self.starstar_arg.entry.cname,))
+ code.putln("if (unlikely(!%s)) return %s;" % (
+ self.starstar_arg.entry.cname, self.error_value()))
+ code.put_var_gotref(self.starstar_arg.entry)
+ self.starstar_arg.entry.xdecref_cleanup = False
code.putln("}")
if self.self_in_stararg and not self.target.is_staticmethod:
diff --git a/tests/run/locals.pyx b/tests/run/locals.pyx
index 9473ad01e..2e7c0a961 100644
--- a/tests/run/locals.pyx
+++ b/tests/run/locals.pyx
@@ -5,6 +5,8 @@ def get_locals(x, *args, **kwds):
"""
>>> sorted( get_locals(1,2,3, k=5).items() )
[('args', (2, 3)), ('kwds', {'k': 5}), ('x', 1), ('y', 'hi'), ('z', 5)]
+ >>> sorted( get_locals(1).items() ) # args and kwds should *always* be present even if not passed
+ [('args', ()), ('kwds', {}), ('x', 1), ('y', 'hi'), ('z', 5)]
"""
cdef int z = 5
y = "hi"
@@ -14,6 +16,8 @@ def get_vars(x, *args, **kwds):
"""
>>> sorted( get_vars(1,2,3, k=5).items() )
[('args', (2, 3)), ('kwds', {'k': 5}), ('x', 1), ('y', 'hi'), ('z', 5)]
+ >>> sorted( get_vars(1).items() )
+ [('args', ()), ('kwds', {}), ('x', 1), ('y', 'hi'), ('z', 5)]
"""
cdef int z = 5
y = "hi"
@@ -23,6 +27,8 @@ def get_dir(x, *args, **kwds):
"""
>>> sorted( get_dir(1,2,3, k=5) )
['args', 'kwds', 'x', 'y', 'z']
+ >>> sorted( get_dir(1) )
+ ['args', 'kwds', 'x', 'y', 'z']
"""
cdef int z = 5
y = "hi"
@@ -36,6 +42,8 @@ def in_locals(x, *args, **kwds):
True
>>> in_locals('X')
False
+ >>> in_locals('kwds')
+ True
"""
cdef int z = 5
y = "hi"
@@ -49,6 +57,8 @@ def in_dir(x, *args, **kwds):
True
>>> in_dir('X')
False
+ >>> in_dir('kwds')
+ True
"""
cdef int z = 5
y = "hi"
@@ -62,6 +72,8 @@ def in_vars(x, *args, **kwds):
True
>>> in_vars('X')
False
+ >>> in_vars('kwds')
+ True
"""
cdef int z = 5
y = "hi"