`ghostwriter.magic(numpy.matmul)` fails with NumPy 1.26.4 and Python 3.12
Traceback from pytest invocation below. From what I can tell, inspect.signature raises ValueError: callable <ufunc 'matmul'> is not supported by signature in Python 3.11, but returns <Signature (*args, **kwargs)> in Python 3.12. This makes ghostwriter._get_params return an empty OrderedDict, which is subsequently padded with None by zip_longest.
============================= test session starts ==============================
platform linux -- Python 3.12.2, pytest-8.1.1, pluggy-1.4.0
rootdir: /<<PKGBUILDDIR>>
configfile: pytest.ini
plugins: hypothesis-6.100.0, flaky-3.8.1
collected 6152 items / 1 error / 4037 deselected / 1 skipped / 2115 selected
==================================== ERRORS ====================================
_ ERROR collecting .pybuild/cpython3_3.12_hypothesis/build/tests/ghostwriter/test_expected_output.py _
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/_pytest/runner.py", line 340, in from_call
result: Optional[TResult] = func()
^^^^^^
File "/usr/lib/python3/dist-packages/_pytest/runner.py", line 388, in collect
return list(collector.collect())
^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/_pytest/python.py", line 576, in collect
self._register_setup_module_fixture()
File "/usr/lib/python3/dist-packages/_pytest/python.py", line 589, in _register_setup_module_fixture
self.obj, ("setUpModule", "setup_module")
^^^^^^^^
File "/usr/lib/python3/dist-packages/_pytest/python.py", line 315, in obj
self._obj = obj = self._getobj()
^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/_pytest/python.py", line 573, in _getobj
return importtestmodule(self.path, self.config)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/_pytest/python.py", line 520, in importtestmodule
mod = import_path(
^^^^^^^^^^^^
File "/usr/lib/python3/dist-packages/_pytest/pathlib.py", line 584, in import_path
importlib.import_module(module_name)
File "/usr/lib/python3.12/importlib/__init__.py", line 90, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
File "/usr/lib/python3/dist-packages/_pytest/assertion/rewrite.py", line 178, in exec_module
exec(co, module.__dict__)
File "/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_hypothesis/build/tests/ghostwriter/test_expected_output.py", line 132, in <module>
("magic_gufunc", ghostwriter.magic(numpy.matmul)),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_hypothesis/build/hypothesis/extra/ghostwriter.py", line 1301, in magic
make_(_make_ufunc_body, func, annotate=annotate)
File "/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_hypothesis/build/hypothesis/extra/ghostwriter.py", line 1202, in make_
imp, body = how(*args, **kwargs, except_=except_, style=style)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_hypothesis/build/hypothesis/extra/ghostwriter.py", line 1884, in _make_ufunc_body
call=_write_call(func, *ascii_lowercase[: func.nin], except_=except_),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_hypothesis/build/hypothesis/extra/ghostwriter.py", line 781, in _write_call
args = ", ".join(
^^^^^^^^^^
File "/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_hypothesis/build/hypothesis/extra/ghostwriter.py", line 784, in <genexpr>
if p.kind is inspect.Parameter.POSITIONAL_ONLY
^^^^^^
AttributeError: 'NoneType' object has no attribute 'kind'
=========================== short test summary info ============================
ERROR tests/ghostwriter/test_expected_output.py - AttributeError: 'NoneType' ...
!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
I actually can't reproduce with python 3.12.2 + numpy 1.26.4 on macos:
>>> assert numpy.__version__ == "1.26.4"
>>> assert sys.version_info[:3] == (3, 12, 2)
>>> ghostwriter.magic(numpy.matmul)
...
but #3955 ran into the same error, so I'd expect this to also be fixed once that is merged.
Ran into the same error, yes, but since it wasn't failing in CI we didn't make any changes. I think the fix will be to use if p is None or p.kind... as the condition here.
another option would be to manually raise here if the signature detected by inspect.signature is *args, **kwargs and the tricks below are likely to work.
So far as I can tell, this is working now:
Python 3.12.4 (main, Jul 12 2024, 16:02:27) [GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from hypothesis.extra.ghostwriter import magic
>>> import numpy as np
>>> magic(np.matmul)
'# This test code was written by the `hypothesis.extra.ghostwriter` module\n# and is provided under the Creative Commons Zero public domain dedication.\n\nimport numpy\nfrom hypothesis import given, strategies as st\nfrom hypothesis.extra.numpy import arrays, mutually_broadcastable_shapes\n\n\n@given(\n data=st.data(),\n shapes=mutually_broadcastable_shapes(signature="(n?,k),(k,m?)->(n?,m?)"),\n types=st.sampled_from([sig for sig in numpy.matmul.types if "O" not in sig]),\n)\ndef test_gufunc_matmul(data, shapes, types):\n input_shapes, expected_shape = shapes\n input_dtypes, expected_dtype = types.split("->")\n array_strats = [\n arrays(dtype=dtp, shape=shp, elements={"allow_nan": True})\n for dtp, shp in zip(input_dtypes, input_shapes)\n ]\n\n a, b = data.draw(st.tuples(*array_strats))\n result = numpy.matmul(a, b)\n\n assert result.shape == expected_shape\n assert result.dtype.char == expected_dtype\n'
>>> np.__version__
'1.26.4'