-
-
Notifications
You must be signed in to change notification settings - Fork 11.2k
Description
Describe the issue:
Any class decorated using the the decorator set_module('to_this_module')
, defined on numpy/_utils/__init__.py
, is pointing the location of it's source code in the wrong place in externally generated docs. This error affects the automatically generated link appearing as a [source]
, in the function header in the documentation web site, and also in the File:
attribute appearing in the footer of the helper shown by the IPython magic helper operator ?
.
As an example, consider the poly1d class definition, which is located on file numpy/lib/_polynomial_impl.py
, an screenshot of the documentation is shown below indicating that the code is located at `numpy/init.py
The same error appears while calling the ? np.poly1d
helper on IPython, which results in
Init signature: np.poly1d(c_or_r, r=False, variable=None)
Docstring: ... (omited)
File: ~/mycode/numpy-aureliobarbosa/numpy-dev/lib/python3.12/site-packages/numpy/__init__.py
Type: type
Subclasses:
This error currently affects at least 25 classes, which can be tracked in the repository with the regex @set_module\(['"].*?['"]\)\nclass
(I used VSCode for that). The full list of affected classes will complement this message. This problem doen't affect functions decorated with set_module as will become clear in the following
After some investigation I found that external tools (numpydoc
?, IPython
) automatically searching for where the source code of a certain object is located rely on the stdlib function inpect.getfile(object)
(or another function on the module inspect which will call getfile) to recover the actual location of the code in the directory tree. This function is simple and it's code can be found here, and in the case of classes, it end up calling the following code:
module = sys.modules.get(object.__module__)
if getattr(module, '__file__', None):
return module.__file__
which will return the __init__.py
file of the module passed using @set_module('module')
, since this decorator dynamically changes the the property __module__
of a class or a function. Using @set_module('module')
to decorate functions doesn't harm documentation because when calling inspect.getfile(object)
, when object
is a function, returns object.__code__.co_filename
, which wasn't affected by the set_module decorator.
My original intention was to try to fix the documentation but it turned it out that the problem is originating in the decorator @set_module
which, in my opinion, is breaking a contract that is commonly expected by other tools operating on a property of classes, as it also affects the behavior of IPython
.
It should be possible to fix the online documentation (maybe changing numpydoc
?) but the problem would continue to exist in any tool which automatically try to locate the source code of those classes in a standard
way. In order to fix this documentation/code issue a decision a decision should be made concerning the usage of the decorator @set_module
.
Although using numpy for some time, I am still new on its codebase, if someone can give me a hint on the reasons for using @set_module
it would help to implement a fix. Anyway, hope the current investigation helps when searching for a solution to this issue.
Regards
Reproduce the code example:
import sys
import numpy as np
object = np.poly1d
module = sys.modules.get(object.__module__)
print(module.__file__)
# should be expecting '<codebase>/numpy/lib/_polynomial_impl.py'
Error message:
Python and NumPy Versions:
Python: 3.12.8
NumPy: 2.2.4
IPython: 9.0.4
Runtime Environment:
No response
Context for the issue:
No response