compat: move check for closure cellvar update wrapper function (#1092)
* compat: move check for closure cellvar update wrapper function
This sanity checking code ended up getting decoupled from the old
implementation in a18b3957d5
when a new,
much simpler method was added. This check can fail spuriously in
certain environments where it doesn't even need to be run because the
newer approach is used.
This is noticeable when using python scripts compiled by nuitka. Since
next-gen attrs uses slots on everything by default, the use of this
fixup function is now pervasive, as well.
* changelog: note fix
* Semantic newlines
---------
Co-authored-by: Hynek Schlawack <hs@ox.cx>
This commit is contained in:
parent
bf522367c0
commit
b950cb8d83
|
@ -0,0 +1 @@
|
|||
Fix slots class cellvar updating closure in CPython 3.8+ even when `__code__` introspection is unavailable.
|
|
@ -82,32 +82,32 @@ def make_set_closure_cell():
|
|||
|
||||
# Otherwise gotta do it the hard way.
|
||||
|
||||
# Create a function that will set its first cellvar to `value`.
|
||||
def set_first_cellvar_to(value):
|
||||
x = value
|
||||
return
|
||||
|
||||
# This function will be eliminated as dead code, but
|
||||
# not before its reference to `x` forces `x` to be
|
||||
# represented as a closure cell rather than a local.
|
||||
def force_x_to_be_a_cell(): # pragma: no cover
|
||||
return x
|
||||
|
||||
try:
|
||||
# Extract the code object and make sure our assumptions about
|
||||
# the closure behavior are correct.
|
||||
co = set_first_cellvar_to.__code__
|
||||
if co.co_cellvars != ("x",) or co.co_freevars != ():
|
||||
raise AssertionError # pragma: no cover
|
||||
|
||||
# Convert this code object to a code object that sets the
|
||||
# function's first _freevar_ (not cellvar) to the argument.
|
||||
if sys.version_info >= (3, 8):
|
||||
|
||||
def set_closure_cell(cell, value):
|
||||
cell.cell_contents = value
|
||||
|
||||
else:
|
||||
# Create a function that will set its first cellvar to `value`.
|
||||
def set_first_cellvar_to(value):
|
||||
x = value
|
||||
return
|
||||
|
||||
# This function will be eliminated as dead code, but
|
||||
# not before its reference to `x` forces `x` to be
|
||||
# represented as a closure cell rather than a local.
|
||||
def force_x_to_be_a_cell(): # pragma: no cover
|
||||
return x
|
||||
|
||||
# Extract the code object and make sure our assumptions about
|
||||
# the closure behavior are correct.
|
||||
co = set_first_cellvar_to.__code__
|
||||
if co.co_cellvars != ("x",) or co.co_freevars != ():
|
||||
raise AssertionError # pragma: no cover
|
||||
|
||||
# Convert this code object to a code object that sets the
|
||||
# function's first _freevar_ (not cellvar) to the argument.
|
||||
args = [co.co_argcount]
|
||||
args.append(co.co_kwonlyargcount)
|
||||
args.extend(
|
||||
|
|
Loading…
Reference in New Issue