python / cpython

The Python programming language
https://www.python.org
Other
63.37k stars 30.33k forks source link

Empty __module__ attribute for built-in static methods #115231

Open skirpichev opened 8 months ago

skirpichev commented 8 months ago

Bug report

Bug description:

An example:

>>> bytes.maketrans.__module__ is None
True

c.f. pure-python staticmethod:

>>> class Spam:
...     @staticmethod
...     def foo():
...         pass
... 
>>> Spam.foo.__module__
'__main__'

I'm not sure, maybe this should be treated rather as a feature request. Docs says about the attribute value: "The name of the module the function was defined in, or None if unavailable." But clearly, this value is available: the type_add_method() has type argument and we could query value of its __module__ attribute.

Edit: BTW, same happens for class methods, e.g.:

>>> int.from_bytes.__module__ is None
True

Probably this should be fixed as well.

CPython versions tested on:

CPython main branch

Operating systems tested on:

No response

Linked PRs

serhiy-storchaka commented 3 days ago

Built-in static and class methods has different types than static and class methods in Python classes. This is not a bug.

Static and class methods in Python classes started to inherit function attributes only since 3.10 (bpo-43682/gh-87848). cc @vstinner

skirpichev commented 3 days ago

Static and class methods in Python classes started to inherit function attributes only since 3.10

Hmm, above code snippet works on 3.8+ as well, e.g.:

Python 3.9.19+ (heads/3.9:3f5d9d12c7, Aug 29 2024, 13:17:09) 
[GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class Spam:
...     @staticmethod
...     def foo():
...         pass
... 
>>> Spam.foo.__module__
'__main__'
>>> 
serhiy-storchaka commented 3 days ago

Static and class methods in Python classes copy attributes from the wrapped methods. But unbound built-in methods do not have the __module__ attribute, so not copying it is okay. On other hand, bound built-in methods have __module__ equal to None:

>>> collections.deque.append.__module__
Traceback (most recent call last):
  File "<python-input-15>", line 1, in <module>
    collections.deque.append.__module__
AttributeError: 'method_descriptor' object has no attribute '__module__'. Did you mean: '__reduce__'?
>>> collections.deque().append.__module__ is None
True

We should first decide whether we need the __module__ attribute for regular builtin methods.

skirpichev commented 3 days ago

We should first decide whether we need the __module__ attribute for regular builtin methods.

That should be helpful for introspection. E.g. now the inspect._signature_fromstr() resolves module_dict to empty for e.g. bytes.maketrans() or int.from_bytes(). That essentially forbids e.g. using module constants as default values.