gh-132775: Unrevert "Add _PyCode_GetVarCounts()" (gh-133265)

This reverts commit 811edcf (gh-133232), which itself reverted the original commit 811edcf (gh-133128).

We reverted the original change due to failing s390 builds (a big-endian architecture).
It ended up that I had not accommodated op caches.
This commit is contained in:
Eric Snow 2025-05-05 13:24:29 -06:00 committed by GitHub
parent b275b8f342
commit 24ebb9ccfd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 732 additions and 3 deletions

View file

@ -777,6 +777,236 @@ class CodeTest(unittest.TestCase):
kinds = _testinternalcapi.get_co_localskinds(func.__code__)
self.assertEqual(kinds, expected)
@unittest.skipIf(_testinternalcapi is None, "missing _testinternalcapi")
def test_var_counts(self):
self.maxDiff = None
def new_var_counts(*,
posonly=0,
posorkw=0,
kwonly=0,
varargs=0,
varkwargs=0,
purelocals=0,
argcells=0,
othercells=0,
freevars=0,
globalvars=0,
attrs=0,
unknown=0,
):
nargvars = posonly + posorkw + kwonly + varargs + varkwargs
nlocals = nargvars + purelocals + othercells
if isinstance(globalvars, int):
globalvars = {
'total': globalvars,
'numglobal': 0,
'numbuiltin': 0,
'numunknown': globalvars,
}
else:
g_numunknown = 0
if isinstance(globalvars, dict):
numglobal = globalvars['numglobal']
numbuiltin = globalvars['numbuiltin']
size = 2
if 'numunknown' in globalvars:
g_numunknown = globalvars['numunknown']
size += 1
assert len(globalvars) == size, globalvars
else:
assert not isinstance(globalvars, str), repr(globalvars)
try:
numglobal, numbuiltin = globalvars
except ValueError:
numglobal, numbuiltin, g_numunknown = globalvars
globalvars = {
'total': numglobal + numbuiltin + g_numunknown,
'numglobal': numglobal,
'numbuiltin': numbuiltin,
'numunknown': g_numunknown,
}
unbound = globalvars['total'] + attrs + unknown
return {
'total': nlocals + freevars + unbound,
'locals': {
'total': nlocals,
'args': {
'total': nargvars,
'numposonly': posonly,
'numposorkw': posorkw,
'numkwonly': kwonly,
'varargs': varargs,
'varkwargs': varkwargs,
},
'numpure': purelocals,
'cells': {
'total': argcells + othercells,
'numargs': argcells,
'numothers': othercells,
},
'hidden': {
'total': 0,
'numpure': 0,
'numcells': 0,
},
},
'numfree': freevars,
'unbound': {
'total': unbound,
'globals': globalvars,
'numattrs': attrs,
'numunknown': unknown,
},
}
import test._code_definitions as defs
funcs = {
defs.spam_minimal: new_var_counts(),
defs.spam_full: new_var_counts(
posonly=2,
posorkw=2,
kwonly=2,
varargs=1,
varkwargs=1,
purelocals=4,
globalvars=3,
attrs=1,
),
defs.spam: new_var_counts(
posorkw=1,
),
defs.spam_N: new_var_counts(
posorkw=1,
purelocals=1,
),
defs.spam_C: new_var_counts(
posorkw=1,
purelocals=1,
argcells=1,
othercells=1,
),
defs.spam_NN: new_var_counts(
posorkw=1,
purelocals=1,
),
defs.spam_NC: new_var_counts(
posorkw=1,
purelocals=1,
argcells=1,
othercells=1,
),
defs.spam_CN: new_var_counts(
posorkw=1,
purelocals=1,
argcells=1,
othercells=1,
),
defs.spam_CC: new_var_counts(
posorkw=1,
purelocals=1,
argcells=1,
othercells=1,
),
defs.eggs_nested: new_var_counts(
posorkw=1,
),
defs.eggs_closure: new_var_counts(
posorkw=1,
freevars=2,
),
defs.eggs_nested_N: new_var_counts(
posorkw=1,
purelocals=1,
),
defs.eggs_nested_C: new_var_counts(
posorkw=1,
purelocals=1,
argcells=1,
freevars=2,
),
defs.eggs_closure_N: new_var_counts(
posorkw=1,
purelocals=1,
freevars=2,
),
defs.eggs_closure_C: new_var_counts(
posorkw=1,
purelocals=1,
argcells=1,
othercells=1,
freevars=2,
),
defs.ham_nested: new_var_counts(
posorkw=1,
),
defs.ham_closure: new_var_counts(
posorkw=1,
freevars=3,
),
defs.ham_C_nested: new_var_counts(
posorkw=1,
),
defs.ham_C_closure: new_var_counts(
posorkw=1,
freevars=4,
),
}
assert len(funcs) == len(defs.FUNCTIONS), (len(funcs), len(defs.FUNCTIONS))
for func in defs.FUNCTIONS:
with self.subTest(func):
expected = funcs[func]
counts = _testinternalcapi.get_code_var_counts(func.__code__)
self.assertEqual(counts, expected)
def func_with_globals_and_builtins():
mod1 = _testinternalcapi
mod2 = dis
mods = (mod1, mod2)
checks = tuple(callable(m) for m in mods)
return callable(mod2), tuple(mods), list(mods), checks
func = func_with_globals_and_builtins
with self.subTest(f'{func} code'):
expected = new_var_counts(
purelocals=4,
globalvars=5,
)
counts = _testinternalcapi.get_code_var_counts(func.__code__)
self.assertEqual(counts, expected)
with self.subTest(f'{func} with own globals and builtins'):
expected = new_var_counts(
purelocals=4,
globalvars=(2, 3),
)
counts = _testinternalcapi.get_code_var_counts(func)
self.assertEqual(counts, expected)
with self.subTest(f'{func} without globals'):
expected = new_var_counts(
purelocals=4,
globalvars=(0, 3, 2),
)
counts = _testinternalcapi.get_code_var_counts(func, globalsns={})
self.assertEqual(counts, expected)
with self.subTest(f'{func} without both'):
expected = new_var_counts(
purelocals=4,
globalvars=5,
)
counts = _testinternalcapi.get_code_var_counts(func, globalsns={},
builtinsns={})
self.assertEqual(counts, expected)
with self.subTest(f'{func} without builtins'):
expected = new_var_counts(
purelocals=4,
globalvars=(2, 0, 3),
)
counts = _testinternalcapi.get_code_var_counts(func, builtinsns={})
self.assertEqual(counts, expected)
def isinterned(s):
return s is sys.intern(('_' + s + '_')[1:-1])