Skip to content

TYPING: _64Bit reported as incompatible with NBitBase #24569

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

Closed
bersbersbers opened this issue Aug 28, 2023 · 3 comments · Fixed by #24792
Closed

TYPING: _64Bit reported as incompatible with NBitBase #24569

bersbersbers opened this issue Aug 28, 2023 · 3 comments · Fixed by #24792

Comments

@bersbersbers
Copy link
Contributor

bersbersbers commented Aug 28, 2023

Describe the issue:

mypy reports an error in the following code. Comparing ndarray[Any, dtype[signedinteger[_64Bit]]] and ndarray[Any, dtype[signedinteger[NBitBase]]], the only difference seems to be _64Bit vs. NBitBase - although the former is a subclass of the latter:

class _256Bit(NBitBase): # type: ignore[misc]
pass
class _128Bit(_256Bit): # type: ignore[misc]
pass
class _96Bit(_128Bit): # type: ignore[misc]
pass
class _80Bit(_96Bit): # type: ignore[misc]
pass
class _64Bit(_80Bit): # type: ignore[misc]
pass

Reproduce the code example:

import numpy as np
import numpy.typing as npt

def fun(array: npt.NDArray[np.bool_]) -> npt.NDArray[np.signedinteger[npt.NBitBase]]:
    return np.flatnonzero(array)

Error message:

C:\Code\project>mypy bug.py
bug.py:5: error: Incompatible return value type (got "ndarray[Any, dtype[signedinteger[_64Bit]]]", expected "ndarray[Any, dtype[signedinteger[NBitBase]]]")  [return-value]
Found 1 error in 1 file (checked 1 source file)

Runtime information:

1.25.2
3.11.5 (tags/v3.11.5:cce6ba9, Aug 24 2023, 14:38:34) [MSC v.1936 64 bit (AMD64)]

Context for the issue:

I had to choose between reporting this at mypy or here first. Hope I made a decent choice, but I am happy to report elsewhere as well.

@bersbersbers
Copy link
Contributor Author

bersbersbers commented Aug 28, 2023

Here's two more examples, the second of which is also flagged by pyright as well as PyLance - so it is probably not a mypy issue:

from numpy import int64, integer
from numpy._typing import _64Bit
from numpy.typing import NBitBase, NDArray

a: NDArray[integer[_64Bit]]
b: NDArray[integer[NBitBase]]
b = a

IMAGE_TYPE: type[integer[NBitBase]] = int64
bug.py:9:39 - error: Expression of type "int64" cannot be assigned to declared type "type[integer[NBitBase]]"
    "int64" is incompatible with "type[integer[NBitBase]]"
    Type "int64" cannot be assigned to type "type[integer[NBitBase]]"
      Type parameter "_NBit1@integer" is invariant, but "_64Bit" is not the same as "NBitBase" (reportGeneralTypeIssues)

The key seems to be that Type parameter _NBit1 is invariant - is that intentional? If so, my examples are not expected to work at all, I guess. However, the documentation says that

The precision of numpy.number subclasses is treated as a covariant generic parameter (see NBitBase)

https://numpy.org/devdocs/reference/typing.html#number-precision

@bersbersbers
Copy link
Contributor Author

After having thought about this for a while, I think that I might need to use a TypeVar bound to NBitBase rather than NBitBase itself. (I find it really hard to tell which classes in np and npt are to be used which way.) "Type parameter _NBit1 is invariant" might mean that parameters to integer are treated as invariant. If those two thoughts are correct, I think my code above is invalid.

@BvB93
Copy link
Member

BvB93 commented Sep 1, 2023

The precision of numpy.number subclasses is treated as a covariant generic parameter (see NBitBase)

Ah, so the documentation didn't get updated back then. The variance of the np.number subclasses got updated back in #18174, as their old covariant nature would lead to the likes of np.float32 being considered subtypes of np.float64 (there's the question of how well we can statically deal with number bitsizes in general, but that's another can of worms...).

As for your example: like any other type with an invariant parameter I'd resort to using Any as a placeholder for "can be any arbitrary size".

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

Successfully merging a pull request may close this issue.

3 participants