classification
Title: inspect: getmembers calls properties
Type: behavior Stage: patch review
Components: Library (Lib) Versions: Python 3.9
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: cheryl.sabella, hongweipeng, jnsdrtlf
Priority: normal Keywords: patch

Created on 2019-10-01 12:01 by jnsdrtlf, last changed 2020-03-29 19:22 by jnsdrtlf.

Pull Requests
URL Status Linked Edit
PR 16521 closed jnsdrtlf, 2019-10-01 12:07
Messages (9)
msg353688 - (view) Author: Jonas Drotleff (jnsdrtlf) * Date: 2019-10-01 12:01
When calling inspect.getmembers on a class that has a property (@property), the property will be called by the getattr call in getmembers.

Example:

import inspect

class Example:
    def __init__(self, var):
        self._var = var
        print('__init__')

    def foo(self, bar):
        print(bar)
        print('foo')

    @property
    def var(self):
        print('Access property')
        return self._var


if __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:

__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...>)]
msg353698 - (view) Author: Sanjay (Sanjay) * Date: 2019-10-01 14:03
the issue happens in 2.7 as well
msg353871 - (view) Author: hongweipeng (hongweipeng) * Date: 2019-10-03 18:30
The results of this example are different from mine(version 3.7.4).
```
__init__
--- getmembers from instance ---
Access property
[('__class__', <class '__main__.Example'>), ... ('var', 'Hello')]
--- getmembers from class    ---
[('__class__', <class 'type'>),'var', <property object at 0x>)]
```
msg353872 - (view) Author: Jonas Drotleff (jnsdrtlf) * Date: 2019-10-03 18:48
> The results of this example are different from mine(version 3.7.4)

I do not really see any difference. What do you mean?
msg353895 - (view) Author: hongweipeng (hongweipeng) * Date: 2019-10-04 03:16
I mean why member `__class__` is expected to be `<attribute '__class__'...>)`. I check PR16521,for __class__, it always gets `<attribute '__class__'...>)`.
msg353900 - (view) Author: Jonas Drotleff (jnsdrtlf) * Date: 2019-10-04 06:49
Oh, yes I see what you mean. That's my fault, it seems like I copied the wrong line. Sorry.

But the important piece is the 'var' attribute. Sorry for the confusion.
msg360715 - (view) Author: Cheryl Sabella (cheryl.sabella) * (Python committer) Date: 2020-01-26 01:21
Here is a link to the discussion of this on ideas:
https://discuss.python.org/t/implement-inspect-getmembers-static/2550
msg360748 - (view) Author: Jonas Drotleff (jnsdrtlf) * Date: 2020-01-27 09:34
> Here is a link to the discussion of this on ideas

Thank you for posting the link.

I feel like I came to a dead end with this issue. As I am fairly new to CPython and have never contributed to this project before, I have no idea how to address this and to whom. Maybe this is just to irrelevant and not important, but even then we should probably close this issue or mark it as "indefinitely postponed" or something similar.
msg365274 - (view) Author: Jonas Drotleff (jnsdrtlf) * Date: 2020-03-29 19:22
I'm still thinking about this bug/issue/undefined behaviour. Today I wanted to test its behaviour with async:

import inspect


class Foo:
    def __init__(self, bar):
        self._bar = bar

    @property
    async def spam(self):
        print('Called spam')
        return self._bar


if __name__ == '__main__':
    instance = Foo('eggs')
    members = inspect.getmembers(instance)

##

This will result in a RuntimeWarning:


RuntimeWarning: coroutine 'Foo.spam' was never awaited
  members = inspect.getmembers(instance)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback


Sure, async properties might not be particularly beautiful or best-practice, but I frequently stumble upon code where getmembers would fail – just like this example. However, I am still clueless about what to do.
History
Date User Action Args
2020-03-29 19:22:40jnsdrtlfsetmessages: + msg365274
2020-01-27 09:34:14jnsdrtlfsetmessages: + msg360748
2020-01-26 01:21:23cheryl.sabellasetnosy: + cheryl.sabella

messages: + msg360715
versions: - Python 2.7, Python 3.5, Python 3.6, Python 3.7, Python 3.8
2019-10-04 06:49:31jnsdrtlfsetmessages: + msg353900
2019-10-04 03:16:04hongweipengsetmessages: + msg353895
2019-10-03 18:48:46jnsdrtlfsetnosy: - Sanjay
messages: + msg353872
2019-10-03 18:30:19hongweipengsetnosy: + hongweipeng
messages: + msg353871
2019-10-01 14:03:07Sanjaysetnosy: + Sanjay

messages: + msg353698
versions: + Python 2.7
2019-10-01 12:07:43jnsdrtlfsetkeywords: + patch
stage: patch review
pull_requests: + pull_request16113
2019-10-01 12:01:59jnsdrtlfcreate