Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for numpy.typing #270

Open
mhostetter opened this issue Jul 13, 2023 · 7 comments
Open

Support for numpy.typing #270

mhostetter opened this issue Jul 13, 2023 · 7 comments

Comments

@mhostetter
Copy link
Contributor

Hey guys. Hope you're well.

I was adding a type annotation to a function that is npt.DTypeLike, see here. However, when displayed with sphinx-immaterial the underlying Union is unpacked. Is there a way to only display npt.DTypeLike in our API docs?

from typing import Optional
import numpy as np
import numpy.typing as npt

def pack(x: np.ndarray, bpe: int, dtype: Optional[npt.DTypeLike] = None) -> np.ndarray:
    return x

image

@mhostetter
Copy link
Contributor Author

I found this https://stackoverflow.com/a/67483317/11694321. It says to add from __future__ import annotations to the top of the module to add this to conf.py.

autodoc_type_aliases = {
    "npt.DTypeLike": "~numpy.typing.DTypeLike",
}

This now give me the following. It is almost perfect. It is succinct, but the pink DTypeLike doesn't hyperlink (even though the yellow one below does, using :obj:numpy.typing.DTypeLike).

image

@jbms
Copy link
Owner

jbms commented Jul 13, 2023

Do you get any warnings?

I would expect this to work. This theme also has its own type alias mechanism that applies to the Python domain generally (not just to autodoc-generated things):

https://jbms.github.io/sphinx-immaterial/apidoc/python/index.html#confval-python_type_aliases

You could try using that instead. I believe the autodoc_type_aliases only apply in certain cases (and not, for example, when using text signatures as obtained from things defined by C extensions), but I would expect them to apply in this case.

If you don't specify the autodoc_type_aliases, do you get the same thing except it shows npt.DTypeLike?

@mhostetter
Copy link
Contributor Author

I got no warnings. I'm including a reproducible example. foo-270.zip

  • With no from __future__ import annotations and nothing special in conf.py I get the expanded Union.
  • Adding from __future__ import annotations doesn't help.
  • Adding just autodoc_type_aliases = {"npt.DTypeLike": "~numpy.typing.DTypeLike"} displays the hint as DTypeLike, but it doesn't hyperlink.
  • Adding just python_type_aliases = {"npt.DTypeLike": "~numpy.typing.DTypeLike"} displays the expanded Union.
  • Adding both autodoc_type_aliases = {"npt.DTypeLike": "~numpy.typing.DTypeLike"} and python_type_aliases = {"npt.DTypeLike": "~numpy.typing.DTypeLike"} displays the hint as DTypeLike, but it doesn't hyperlink.

I'm using Sphinx v5.3.0 and Sphinx Immaterial v0.11.5 in Python 3.8.10.

@mhostetter
Copy link
Contributor Author

This may be another clue... Using the autodoc_type_aliases trick above, the following give these outputs.

Acceptable

def unpack(x: np.ndarray, bpe: int, dtype: npt.DTypeLike) -> np.ndarray:

image

Something's wrong

def unpack(x: np.ndarray, bpe: int, dtype: npt.DTypeLike = np.uint8) -> np.ndarray:

image

And I now get these warnings.

/mnt/c/Users/matth/repos/sdr/<python_apigen_rst_epilog>:2: WARNING: Parameter name 'x' does not match any of the parameters defined in the signature: ['x: ~numpy.ndarray', 'bpe: int', "dtype: ~numpy.typing.DTypeLike = <class 'numpy.uint8'>"]
/mnt/c/Users/matth/repos/sdr/<python_apigen_rst_epilog>:2: WARNING: Parameter name 'bpe' does not match any of the parameters defined in the signature: ['x: ~numpy.ndarray', 'bpe: int', "dtype: ~numpy.typing.DTypeLike = <class 'numpy.uint8'>"]
/mnt/c/Users/matth/repos/sdr/<python_apigen_rst_epilog>:2: WARNING: Parameter name 'dtype' does not match any of the parameters defined in the signature: ['x: ~numpy.ndarray', 'bpe: int', "dtype: ~numpy.typing.DTypeLike = <class 'numpy.uint8'>"]

@jbms
Copy link
Owner

jbms commented Jul 13, 2023

The default value issue is the same as #140. That makes the signature unparsable as an ast, which causes sphinx to fall back to a more heuristic parsing which prevents a lot of things from working.

@jbms
Copy link
Owner

jbms commented Jul 13, 2023

I looked into this --- the issue is that numpy.typing.DTypeLike is not a class object but a data object, but Sphinx has hardcoded that the type annotation xrefs use the class role:

https://github.com/sphinx-doc/sphinx/blob/d3c91f951255c6729a53e38c895ddc0af036b5b9/sphinx/domains/python.py#L100

There is room for a lot of improvement in that function.

Separately, I'd suggest always building with nitpicky = True in your config, otherwise it is too easy to miss invalid references. You can silence expected missing references with nitpick_ignore.

@mhostetter
Copy link
Contributor Author

I'm running into this again. This function (no from __future__ import annotations)

def db(
    x: npt.ArrayLike,
    type: Literal["value", "power", "voltage"] = "value",
) -> npt.NDArray[np.float_]:

is rendered like this, which is borderline unreadable.

image

Any thoughts on ways to work around this? I'd really like to use native NumPy types, where possible. Thanks again for all the great work on this theme!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants