Skip to content

[3.13] gh-120449: fix test_pyclbr introspection for mangled names (GH-120450) #120700

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 60 additions & 8 deletions Lib/test/pyclbr_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@ class B (object):
def bm(self): pass

class C (B):
foo = Other().foo
om = Other.om

d = 10

# XXX: This causes test_pyclbr.py to fail, but only because the
# introspection-based is_method() code in the test can't
# distinguish between this and a genuine method function like m().
# The pyclbr.py module gets this right as it parses the text.
# This one is correctly considered by both test_pyclbr.py and pyclbr.py
# as a non-method of C.
foo = Other().foo

# This causes test_pyclbr.py to fail, but only because the
# introspection-based is_method() code in the test can't
# distinguish between this and a genuine method function like m().
#
#f = f
# The pyclbr.py module gets this right as it parses the text.
om = Other.om
f = f

def m(self): pass

Expand All @@ -31,3 +33,53 @@ def sm(self): pass

@classmethod
def cm(self): pass

# Check that mangling is correctly handled

class a:
def a(self): pass
def _(self): pass
def _a(self): pass
def __(self): pass
def ___(self): pass
def __a(self): pass

class _:
def a(self): pass
def _(self): pass
def _a(self): pass
def __(self): pass
def ___(self): pass
def __a(self): pass

class __:
def a(self): pass
def _(self): pass
def _a(self): pass
def __(self): pass
def ___(self): pass
def __a(self): pass

class ___:
def a(self): pass
def _(self): pass
def _a(self): pass
def __(self): pass
def ___(self): pass
def __a(self): pass

class _a:
def a(self): pass
def _(self): pass
def _a(self): pass
def __(self): pass
def ___(self): pass
def __a(self): pass

class __a:
def a(self): pass
def _(self): pass
def _a(self): pass
def __(self): pass
def ___(self): pass
def __a(self): pass
24 changes: 15 additions & 9 deletions Lib/test/test_pyclbr.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ def ismethod(oclass, obj, name):

objname = obj.__name__
if objname.startswith("__") and not objname.endswith("__"):
objname = "_%s%s" % (oclass.__name__, objname)
if stripped_typename := oclass.__name__.lstrip('_'):
objname = f"_{stripped_typename}{objname}"
return objname == name

# Make sure the toplevel functions and classes are the same.
Expand Down Expand Up @@ -111,12 +112,16 @@ def ismethod(oclass, obj, name):
for m in py_item.__dict__.keys():
if ismethod(py_item, getattr(py_item, m), m):
actualMethods.append(m)
foundMethods = []
for m in value.methods.keys():
if m[:2] == '__' and m[-2:] != '__':
foundMethods.append('_'+name+m)
else:
foundMethods.append(m)

if stripped_typename := name.lstrip('_'):
foundMethods = []
for m in value.methods.keys():
if m.startswith('__') and not m.endswith('__'):
foundMethods.append(f"_{stripped_typename}{m}")
else:
foundMethods.append(m)
else:
foundMethods = list(value.methods.keys())

try:
self.assertListEq(foundMethods, actualMethods, ignore)
Expand Down Expand Up @@ -150,8 +155,9 @@ def test_easy(self):
"DocTestCase", '_DocTestSuite'))
self.checkModule('difflib', ignore=("Match",))

def test_decorators(self):
self.checkModule('test.pyclbr_input', ignore=['om'])
def test_cases(self):
# see test.pyclbr_input for the rationale behind the ignored symbols
self.checkModule('test.pyclbr_input', ignore=['om', 'f'])

def test_nested(self):
mb = pyclbr
Expand Down
Loading