diff options
author | da-woods <dw-git@d-woods.co.uk> | 2023-02-24 09:04:27 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-02-24 10:04:27 +0100 |
commit | 8db63cf0944998819fb70d9639d53ff777ec8ac1 (patch) | |
tree | f09bb431d34a28e3e7381095bac00939d7f245b1 | |
parent | 6037b9066f4762e08ca2220922784d1cbd22d4cc (diff) | |
download | cython-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.py | 14 | ||||
-rw-r--r-- | tests/run/locals.pyx | 12 |
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" |