Mergednumpy/numpy#3285533.3Kstars
DOC,TST: Fix code snippets in subclassing ndarray (User Guide docs) and stop xfailing it in tutorial doctests
By Mohd Maaz Khan, merged by mattip into numpy/numpy on 6 Oct 2026
Conversation
maaz7409opened this pull request on 2 Oct 2026description.mdAuthor PR summary
Currently, line 639 of
doc/source/user/basics.subclassing.rstsuper().__array_wrap__(self, out_arr, context, return_scalar)explicitly passes self parameter.
When code is ran according to doc snippet, it raises
TypeError: takes at most 3 arguments (4 given)as shown below>>> obj = MySubClass(np.arange(5), info='spam') In __array_finalize__: self is MySubClass([0, 1, 2, 3, 4]) obj is array([0, 1, 2, 3, 4]) >>> arr2 = np.arange(5)+1 >>> ret = np.add(arr2,obj) In __array_wrap__: self is MySubClass([0, 1, 2, 3, 4]) arr is array([1, 3, 5, 7, 9]) In __array_wrap__: self is MySubClass([0, 1, 2, 3, 4]) arr is array([1, 3, 5, 7, 9]) In __array_wrap__: self is MySubClass([0, 1, 2, 3, 4]) arr is array([1, 3, 5, 7, 9]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/workspaces/numpy/doc/bug-reports/tests/test1.py", line 22, in __array_wrap__ return super().__array_wrap__(self, out_arr, context, return_scalar) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: __array_wrap__() takes at most 3 arguments (4 given)This PR fixed it by simply removing
selfbeing passed as 1st argument, because when calling parent class methodsuper(),selfshouldn't be passed explicitly.super().__array_wrap__(out_arr, context, return_scalar)I've tested this and it works.
>>> obj = MySubClass(np.arange(5), info='spam') In __array_finalize__: self is MySubClass([0, 1, 2, 3, 4]) obj is array([0, 1, 2, 3, 4]) >>> arr2 = np.arange(5)+1 >>> ret = np.add(arr2,obj) In __array_wrap__: self is MySubClass([0, 1, 2, 3, 4]) arr is array([1, 3, 5, 7, 9]) In __array_finalize__: self is MySubClass([1, 3, 5, 7, 9]) obj is MySubClass([0, 1, 2, 3, 4]) >>> ret MySubClass([1, 3, 5, 7, 9]) >>> ret.info 'spam'AI Disclosure
Claude Code was used in identifying this bug.
mattipcommented on 3 Oct 2026Member I wonder why CI did not catch this. We do
python3 tools/refguide_check.py -v, is that not enough?maaz7409commented on 4 Oct 2026Author @mattip i looked into it.
So, answer to your question is no,
refguide_check.pycan't catch this. It validates the ReST syntax of docstrings and checks that everything in a module's__all__appears in the reference guide. It doesn't readdoc/source/user/*.rst, and it doesn't execute any example code. I ran it locally and it passes, because it never opens this page.It used to have
--doctestsand--rstmodes, until the doctesting was moved tospin check-docsandspin check-tutorialsin mid-2024. The CI step is also still labelled "check doctests."The check that does cover this page is
spin check-tutorials. Butbasics.subclassing.rstis indt_config.pytest_extra_xfailinnumpy/conftest.py, with the reason.. testcode:: admonitions not understood.As far as I can tell, the pytest doctest runner ignores.. testcode::blocks, so the classes defined there never exist and the page fails with aNameErrorbefore reaching this example. When I ran it, the old and the fixed page both showedXFAIL, so the check can't tell them apart.From the git historyy , the page also seems to have been excluded from doctesting for a long time (a skip list in
refguide_check.pyfrom 2020, then the xfail), so I don't think any CI configuration has run this example since it became an.rstfile. ( I'm going by the config at each commit, not old CI logs ).The tool that does run
.. testcode::issphinx-build -b doctest. Running it on this page reproduces the sameTypeErroron main and doesn't hit it with this PR. I couldn't find anywhere CI runs that builder.mattipcommented on 5 Oct 2026Member So I think this file should be refactored. Instead of an admonition, all the testcode blocks should be reformatted like this block
>>> class C: ... def __new__(cls, *args): ... print('Cls in __new__:', cls) ... print('Args in __new__:', args) ... # The `object` type __new__ method takes a single argument. ... return object.__new__(cls) ... def __init__(self, *args): ... print('type(self) in __init__:', type(self)) ... print('Args in __init__:', args)so that CI's
spin check-tutorialscan be run on it.maaz7409commented on 5 Oct 2026Author @mattip I have refactored the page like you suggested :
-
All the
.. testcode::blocks that define classes are now normal>>>/...blocks, same style as theclass C:block you pointed to. There were 7 of them (D, C, InfoArray, RealisticInfoArray, A, MySubClass, SillySubClass). -
I didn't put blank lines inside the classes. A blank line in the middle of a class breaks copy-paste into a plain Python prompt (the class would end there), and the
class C:block doesn't have any either. -
The three
def sum(...)examples at the end are not real code, just method signatures with...as the body. So instead of>>>I turned them into.. code-block:: python. Their...body was also not indented under thedef, which isn't valid Python, so I fixed the indentation too. -
I didn't change any of the actual example code. Only the expected output.
Once the examples actually ran, 10 of them failed, and in every case the code was fine and only the printed output in the docs was out of date:
- Classes defined in the page print with the module name, e.g.
<class '__main__.C'>and not<class 'C'>. The page already used the__main__.form near the top, but not further down (D, C, InfoArray, RealisticInfoArray). So 8 examples needed that. - Two lines still had the old Python 2 style output:
<type 'NoneType'>and<type 'numpy.ndarray'>. Now they're<class 'NoneType'>and<class 'numpy.ndarray'>.
In a separate commit I removed
basics.subclassing.rstfromdt_config.pytest_extra_xfailinnumpy/conftest.py. The page passes now, and if it stays on the xfail list, a future break would just show up asXFAILand CI would stay green, which is how this bug got through.We can add the TST label to PR title since it also changes test configuration.
A title something like this
DOC,TST: Fix code snippets in subclassing ndarray ( User guide docs) and drop xfail for itIs this alright?
Tests :
spin check-tutorials doc/source/user/basics.subclassing.rst→ passes. Before the change it wasXFAIL.
- To be sure the test really catches the original bug, I put the extra
selfback insuper().__array_wrap__(...)for a moment. The check then failed withTypeError: __array_wrap__() takes at most 3 arguments (4 given), so it would have caught this.
- built the docs locally via
SPHINXOPTS="-W -n" spin docs
Should I make the push? Or do I first paste the diff docstring ( showing the changes I made)?
-
mattipcommented on 5 Oct 2026Member Commit the changes and push to your branch. Then this PR will have two commits. Documentation CI will run, confirming the chsnges work as advertised.
Thanks
maaz7409commented on 6 Oct 2026Author Looks like Actions had some issue
mattipcommented on 6 Oct 2026Member Actions was flaky yesterday, but the CI build ran and the important line shows success:
doc/source/user/basics.subclassing.rst::basics.subclassing.rst PASSED [ 44%]mattipmerged this pull request on 6 Oct 2026
Copied from GitHub when this site was built; comments by bots are left out.