Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

bpo-38337: Change getattr to inspect.getattr_static#16521

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
3j14 wants to merge8 commits intopython:masterfrom3j14:fix-issue-38337
Closed

bpo-38337: Change getattr to inspect.getattr_static#16521

3j14 wants to merge8 commits intopython:masterfrom3j14:fix-issue-38337

Conversation

3j14
Copy link

@3j143j14 commentedOct 1, 2019
edited by bedevere-bot
Loading

When callinginspect.getmembers on a class that has a property (@property), the property will be called by thegetattr call ingetmembers.

Example:

importinspectclassExample:def__init__(self,var):self._var=varprint('__init__')deffoo(self,bar):print(bar)print('foo')@propertydefvar(self):print('Access property')returnself._varif__name__=='__main__':ex=Example('Hello')print('--- getmembers from instance ---')print(inspect.getmembers(ex))print('--- getmembers from class    ---')print(inspect.getmembers(Example))

Result:

__init__--- getmembers from instance ---Access property[('__class__', <attribute '__class__' of 'object' objects>), ..., ('var', 'Hello')]--- getmembers from class    ---[('__class__', <attribute '__class__' of 'object' objects>), ..., ('var', <property object at 0x...>)]

Expected (new result):

__init__--- getmembers from instance ---[('__class__', <attribute '__class__' of 'object' objects>), ..., ('var', <property object at 0x...>)]--- getmembers from class    ---[('__class__', <attribute '__class__' of 'object' objects>), ..., ('var', <property object at 0x...>)]

https://bugs.python.org/issue38337

@the-knights-who-say-ni

Hello, and thanks for your contribution!

I'm a bot set up to make sure that the project can legally accept this contribution by verifying everyone involved has signed thePSF contributor agreement (CLA).

CLA Missing

Our records indicate the following people have not signed the CLA:

@jnsdrtlf

For legal reasons we need all the people listed to sign the CLA before we can look at your contribution. Please followthe steps outlined in the CPython devguide to rectify this issue.

If you have recently signed the CLA, please wait at least one business day
before our records are updated.

We also demand...A SHRUBBERY!

You cancheck yourself to see if the CLA has been received.

Thanks again for the contribution, we look forward to reviewing it!

@s-sanjay
Copy link
Contributor

should we add a test case ?

@brandtbucherbrandtbucher added needs backport to 3.7 type-bugAn unexpected behavior, bug, or error labelsOct 1, 2019
Copy link
Member

@brandtbucherbrandtbucher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Thanks @jnsdrtlf, and welcome to CPython! 😎

I have a minor change to suggest for the NEWS entry, but otherwise this looks like a good improvement.

I also agree that adding regression test is probably a good idea.

@brandtbucher
Copy link
Member

Actually, from looking at the test failures... I'm not sure if this is the desired behavior (and the docs are ambiguous). Maybe@1st1 can shed some light on the "correct" behavior of this function?

@1st1
Copy link
Member

1st1 commentedOct 1, 2019

Sinceinspect.getmembers is an introspection function it shouldn't run any actual code (i.e. executing getters). It should compute its result statically. Usinggetattr_static is the right idea here, for sure.

brandtbucher, 3j14, and jaymegordo reacted with thumbs up emoji

@brandtbucher
Copy link
Member

brandtbucher commentedOct 1, 2019
edited
Loading

Okay then. So this probably doesn't need a new test, but the ~4 failing ones should be updated!

@1st1
Copy link
Member

1st1 commentedOct 1, 2019

So this probably doesn't need a new test, but the ~4 failing ones should be updated!

I think it needs a new test. Basically an object with a property and a test ensuring that the property was discovered by getmembers, but the getter code wasn't run.

kernc reacted with thumbs up emoji

As suggested by@brandtbucherCo-Authored-By: Brandt Bucher <brandtbucher@gmail.com>
@3j14
Copy link
Author

3j14 commentedOct 1, 2019

I think it needs a new test. Basically an object with a property and a test ensuring that the property was discovered by getmembers, but the getter code wasn't run.

Sounds good! I will get back to work and write a test later today.

Make sure inspect.getmembers won't call properties or other dynamic attributes
@3j14
Copy link
Author

3j14 commentedOct 1, 2019

The testtest_getmembers_VirtualAttribute expects this method

@types.DynamicClassAttributedefeggs(self):return'spam'

to be called. It asserts whether('eggs', 'spam') is ininspect.getmembers. But this is exactly the behavior that I tried to avoid with my PR.

There is also some wierd behaviour when overwriting__getattr__ in a metaclass. This probably needs more insight on howinspect.getmembers should behave.

Failing tests:

  • test_get_slot_members
  • test_getmembers_method
  • test_getmembers_VirtualAttribute

@@ -1191,6 +1191,27 @@ def f(self):
self.assertIn(('f', b.f), inspect.getmembers(b))
self.assertIn(('f', b.f), inspect.getmembers(b, inspect.ismethod))

def test_getmembers_static(self):
class Foo:
def __init__(bar):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Usedef __init__(self, bar): please.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Oups 🤦‍♂ Fixed in commit b415224

@hongweipeng

This comment has been minimized.

@3j14
Copy link
Author

3j14 commentedOct 7, 2019
edited
Loading

Another inconsistent behaviour:inspect.isdatadescriptor should returnTrue for properties:

Return true if the object is a data descriptor.

Data descriptors have both aget and aset method. Examples are properties (defined in Python), getsets, and members

(Python Docs)

However, the following code does not return any properties:

classFoo:def__init__(self,data):self._bar=data@propertydefbar(self):print('--BAR--')returnself._barinspect.getmembers(Foo('test'),inspect.isdatadescriptor)

Result

--BAR--[]

Expected (new result)

[('__class__',<attribute'__class__'of'object'objects>), ('__dict__',<attribute'__dict__'of'Foo'objects>), ('__weakref__',<attribute'__weakref__'of'Foo'objects>), ('bar',<propertyobjectat0x...>)]

Is this correct so far? I am still confused about howgetmembers should behave. Seetest_getmembers_VirtualAttribute, this test expects a different behaviour.

@3j14
Copy link
Author

3j14 commentedOct 7, 2019

Additionally,

classFoo:passinspect.getattr_static(Foo('test'),'__class__')

returns<attribute '__class__' of 'object' objects> whereasgetattr would return<class '__main__.Foo'>. What shouldgetmembers return? If it returns<attribute '__class__' of 'object' objects>, theinspect.isclass predicate would not work:

classFoo:pass# Will return [] if getattr_static is usedinspect.getmembers(Foo('test'),inspect.isclass)

@@ -347,7 +347,10 @@ def getmembers(object, predicate=None):
# like calling their __get__ (see bug #1785), so fall back to
# looking in the __dict__.
try:
value = getattr_static(object, key)
if isinstance(getattr_static(object, key), property):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Why can't we always usegetattr_static? If there's a reason for not using it always, please describe that in a comment.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This is related to my latest comment. Sorry, I didn't make this clear:

getattr_static(...,'__class__') returns<attribute '__class__' of 'object' objects> whereasgetattr would return<class '__main__.Foo'>. What should getmembers return? Usinggetattr_static for every attribute doesn't seem to be the solution. It works fine with methods, functions and properties, but some edge cases seem to requiregetattr (such as__class__). It is not clear what the expected behaviour is.

kernc reacted with thumbs up emoji
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Got it, well, describe this in a comment :)

@3j14
Copy link
Author

3j14 commentedOct 8, 2019
edited
Loading

In3ac2093, I've changedinspect.getmembers to only useinspect.getattr_static for properties, as other members (e.g.__class__) are expected to be returned usinggetattr(obj,'__class__'):

getattr_static(obj,'__class__') returns<attribute '__class__' of 'object' objects> whereasgetattr would return<class '__main__.Foo'>

This feels more like a temporary fix - could be reverted to the first fix I've committed - although I am just not sure which is better.

At this point,I am not sure what the actual expected behaviour should be. Someone should review this and the test case that is currently failing, as it expects a different behaviour (return the actual value of the property).

Copy link
Member

@1st11st1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Jonas, I thought about this PR for some time and I think we should reject it. Modifyinggetmembers in any way would break backwards compatibility in a very non-obvious way for many users. The ship to fix it has sailed.

We can add a new functiongetmembers_static that would usegetattr_static instead ofgetattr. It must be a new distinct function, though.

@bedevere-bot
Copy link

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phraseI have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@3j14
Copy link
Author

3j14 commentedOct 10, 2019
edited
Loading

@1st1 I share your thoughts on that. It does not seem to be obvious, whatgetmembers should return - and changing it in any way will break existing code. This has already caused me a lot of headaches.

As for introducing a functiongetmembers_static: I still have some questions that should be discussed before doing so:

  1. Whatshouldgetmembers_static return? Isgetattr_static appropriate for every member? This would break some predicates (e.g.isclass, see comment above). There does not seem to be a "simple" solution.

  2. A technical question: The new method should pass most of the same tests asgetmembers. Would one just copy and paste the old ones? It would also share most of the code - except for maybe 1 line - withgetmembers.

  3. Is there a reason forgetmembers to return a list of tuples? I would have suggested to use adict instead, which feels more intuitive on first though.

Is there a better place to discuss such questions?

@1st1
Copy link
Member

Is there a better place to discuss such questions?

I think it would be better if you could post this to the python-ideas mailing list. I've very limited time and would hate to get this thing staled because of me.

@1st1
Copy link
Member

Or post it here:https://discuss.python.org/c/ideas

@csabella
Copy link
Contributor

I added a link to the discussion on the bug tracker.

@jaymegordo
Copy link

This would be very helpful, running into the same issue with inspect.getmembers evaluating@Property decorated methods.

getmembers_static would solve it.

@vstinnervstinner deleted the branchpython:masterMay 3, 2021 21:29
@jnsdrtlfjnsdrtlfmannequin mentioned this pull requestApr 10, 2022
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@hongweipenghongweipenghongweipeng left review comments

@1st11st11st1 requested changes

@brandtbucherbrandtbucherbrandtbucher requested changes

Assignees
No one assigned
Labels
awaiting changestype-bugAn unexpected behavior, bug, or error
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

10 participants
@3j14@the-knights-who-say-ni@s-sanjay@brandtbucher@1st1@hongweipeng@bedevere-bot@csabella@jaymegordo@vstinner

[8]ページ先頭

©2009-2025 Movatter.jp