python / python/cpython

ENH: improve doctest class item discovery to include members

Open
#127,962 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

stdlib type-feature
Dominant language
Python
Stars
77.2k
Forks
35.9k
PR merge metrics
PR metrics pending

Description

Feature or enhancement

Proposal:
>>> import numpy as np
>>> import doctest, pprint
>>> finder = doctest.DocTestFinder()
>>> pprint.pprint(finder.find(np.dtype))
[<DocTest dtype from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (11 examples)>,
 <DocTest dtype.__bool__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__class_getitem__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (2 examples)>,
 <DocTest dtype.__eq__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__ge__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__getitem__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__gt__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__hash__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__le__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__len__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__lt__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__mul__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__ne__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__repr__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__rmul__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.__str__ from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (no examples)>,
 <DocTest dtype.newbyteorder from /home/matti/oss/numpy/build-install/usr/lib/python3.11/site-packages/numpy/__init__.py:None (17 examples)>]

But this does not discover many other items in np.dtype.__dict__ since they are members:

>>> pprint.pprint([(v, type(v)) for k, v in np.dtype.__dict__.items() if k not in ('__doc__',) ])
[(<built-in method __new__ of numpy._DTypeMeta object at 0x74f8bcb40920>,
  <class 'builtin_function_or_method'>),
 (<slot wrapper '__repr__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__hash__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__str__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__lt__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__le__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__eq__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__ne__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__gt__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__ge__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__bool__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__len__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__getitem__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__mul__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<slot wrapper '__rmul__' of 'numpy.dtype' objects>,
  <class 'wrapper_descriptor'>),
 (<method '__reduce__' of 'numpy.dtype' objects>, <class 'method_descriptor'>),
 (<method '__setstate__' of 'numpy.dtype' objects>,
  <class 'method_descriptor'>),
 (<method 'newbyteorder' of 'numpy.dtype' objects>,
  <class 'method_descriptor'>),
 (<method '__class_getitem__' of 'numpy.dtype' objects>,
  <class 'classmethod_descriptor'>),
 (<member 'type' of 'numpy.dtype' objects>, <class 'member_descriptor'>),
 (<member 'kind' of 'numpy.dtype' objects>, <class 'member_descriptor'>),
 (<member 'char' of 'numpy.dtype' objects>, <class 'member_descriptor'>),
 (<member 'num' of 'numpy.dtype' objects>, <class 'member_descriptor'>),
 (<member 'byteorder' of 'numpy.dtype' objects>, <class 'member_descriptor'>),
 (<member 'itemsize' of 'numpy.dtype' objects>, <class 'member_descriptor'>),
 (<member 'alignment' of 'numpy.dtype' objects>, <class 'member_descriptor'>),
 (<member 'flags' of 'numpy.dtype' objects>, <class 'member_descriptor'>),
 (<attribute 'subdtype' of 'numpy.dtype' objects>, <class 'getset_descriptor'>),
 (<attribute 'descr' of 'numpy.dtype' objects>, <class 'getset_descriptor'>),
 (<attribute 'str' of 'numpy.dtype' objects>, <class 'getset_descriptor'>),
 (<attribute 'name' of 'numpy.dtype' objects>, <class 'getset_descriptor'>),
 (<attribute 'base' of 'numpy.dtype' objects>, <class 'getset_descriptor'>),
 (<attribute 'shape' of 'numpy.dtype' objects>, <class 'getset_descriptor'>),
 (<attribute 'ndim' of 'numpy.dtype' objects>, <class 'getset_descriptor'>),
 (<attribute 'isbuiltin' of 'numpy.dtype' objects>,
  <class 'getset_descriptor'>),
 (<attribute 'isnative' of 'numpy.dtype' objects>, <class 'getset_descriptor'>),
 (<attribute 'isalignedstruct' of 'numpy.dtype' objects>,
  <class 'getset_descriptor'>),
 (<attribute 'fields' of 'numpy.dtype' objects>, <class 'getset_descriptor'>),
 (<attribute 'metadata' of 'numpy.dtype' objects>, <class 'getset_descriptor'>),
 (<attribute 'names' of 'numpy.dtype' objects>, <class 'getset_descriptor'>),
 (<attribute 'hasobject' of 'numpy.dtype' objects>,
  <class 'getset_descriptor'>)]

I think the problem is here where only certain kinds of items are checked. Adding inspect.isdatadescriptor() I think would fix this.

Has this already been discussed elsewhere?

No response given

Links to previous discussion of this feature:

numpy/numpy#28002
scipy/scipy_doctest#178

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in Lib/doctest.py around line 1064, where DocTestFinder checks which class items to discover. Compare the current item checks with the proposed inspect.isdatadescriptor() addition and review the linked NumPy and SciPy discussions. Done means doctest discovery includes the relevant class members without breaking existing discovery behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
testing-qa, tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.