-
-
Notifications
You must be signed in to change notification settings - Fork 31.4k
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
inspect.classify_class_attrs ignores metaclass #63129
Comments
Part of the solution for bpo-18693 is to have The fix is changing line 325:
+ for base in (cls,) + mro + (type(cls),): or line 361:
Should we target previous Pythons with this fix? |
The global fix causes these two tests to fail: ====================================================================== Traceback (most recent call last):
File "/home/ethan/source/python/issue18693/Lib/test/test_inspect.py", line 485, in test_newstyle_mro
self.assertEqual(expected, got)
AssertionError: Tuples differ: (<class 'test.test_inspect.Tes... != (<class 'test.test_inspect.Tes... Second tuple contains 1 additional elements. (<class 'test.test_inspect.TestClassesAndFunctions.test_newstyle_mro.<locals>.D'>,
+ <class 'object'>, + <class 'type'>) ====================================================================== Traceback (most recent call last):
File "/home/ethan/source/python/issue18693/Lib/test/test_pydoc.py", line 396, in test_help_output_redirect
self.assertEqual(expected_text, result)
AssertionError: "Help on module test.pydoc_mod in test:\n\nNAME\n test.pydoc_mod - This is a [truncated]... != "Help on module test.pydoc_mod in test:\n\nNAME\n test.pydoc_mod - This is a [truncated]...
Help on module test.pydoc_mod in test:
NAME
test.pydoc_mod - This is a test module for test_pydoc
CLASSES
builtins.object
A
B
class A(builtins.object)
| Hello and goodbye
+ |
+ | Method resolution order:
+ | A
+ | builtins.object
+ | builtins.type
|
| Methods defined here:
|
| __init__()
| Wow, I have no function!
|
|
+ | Method resolution order: ====================================================================== I suspect (hope) updating the tests would be fine. |
Another option with the global fix is to only add the metaclass to the mro if the metaclass is not 'type'. |
Of course it is causing tests to fail. You are changing behaviour of an existing API. Please find another solution. |
Okay, taking a step back. It seems that currently inspect is geared towards instances and classes, not metaclasses. Consequently, so is help. So, how do we enhance inspect so that help can be metaclass aware? classify_class_attrs seems like an obvious choice, and it's docstring currently says this: def classify_class_attrs(cls):
"""Return list of attribute-descriptor tuples.
We could add additional 'kind' of 'hidden class method', and 'hidden class attributes' and then have classify_class_attrs explicitly search metaclasses. Or, since we have to make a new getmembers (getmetaclassmembers?), we could also make a new classify_metaclass_attrs that handled both class and metaclass. |
I'm afraid I don't really understand what you're talking about. A
[...]
The docstring is clear: "For each name in dir(cls)". If you want stuff I can understand wanting to better automate lookup of methods on But I have another question first: doesn't calling |
Antoine, to answer all your questions at once, and using an Enum as the example: --> dir(Color) --> Color.__members__ -->help(Color) Color = <enum 'Color'> Why? Because __members__ is not in Color.__dict__ --> Color.__dict__.keys() and inspect.classify_class_attrs doesn't look in metaclasses, instead assigning None as the class if it can't find it: --> inspect.classify_class_attrs(Color) # output trimmed for brevity So, even though __members__ does show up in dir(Color), classify_class_attrs incorrectly assigns its class. Can I use classify_class_attrs on Color.__class__? Sure, but then I get 50 items, only one of which was listed in dir(Color). Interestingly, getmembers(Color) does return __members__, even though it is a metaclass attribute and the docs warn that it won't: --> print('\n'.join([str(i) for i in inspect.getmembers(Color)])) So if getmembers() correctly reports it because it shows up in dir(), then classify_class_attrs should correctly identify it as well. |
This is a more useful help() -- patch attached. ============================================================================== class Color(enum.Enum)
| Method resolution order:
| Color
| enum.Enum
| builtins.object
|
| Data and other attributes defined here:
|
| blue = <Color.blue: 3>
|
| green = <Color.green: 2>
|
| red = <Color.red: 1>
|
| | Data descriptors inherited from enum.EnumMeta: |
[...]
Ok, you got me convinced :-) |
Cool. Latest patch has a slight doc fix for getmembers. Will commit on Friday if no other pertinent feedback. |
New changeset b0517bb271ad by Ethan Furman in branch 'default': |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: