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:
T 2023-02-26 16:07:34 -08:00 committed by GitHub
parent bf522367c0
commit b950cb8d83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 19 deletions

View File

@ -0,0 +1 @@
Fix slots class cellvar updating closure in CPython 3.8+ even when `__code__` introspection is unavailable.

View File

@ -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(