question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Upstream Bug] Please notify NumPy that `numpy.typing.DTypeLike` is broken

See original GitHub issue

Hi,

Once again I feel bad to open a new issue (although I learned more in the last one than in some Python tutorials). But there is once again a feature that would make beartype even better (for myself). I guess that the np.typing.DTypeLike is not supported. Nevertheless, this issue is not urgent at all. There is a simple Annotation to implement an DTypeLike type within beartype.

This time I was smart enough to execute my example as a script to get more helpful error messages. I am using Python==3.10.4, beartype==0.10.4 and numpy==1.21.6

from typing import Annotated

import numpy as np
import numpy.typing as npt
from beartype import beartype
from beartype.vale import Is


@beartype
def f(x: npt.NDArray) -> npt.NDArray:
    return x


# this runs fine
mat = np.zeros((4, 4))
f(mat)

DTypeLike = Annotated[
    type, Is[lambda dtype: np.issubdtype(dtype, np.generic)],
]

@beartype
def g(x: npt.NDArray, dtype: DTypeLike) -> npt.NDArray:
    return x.astype(dtype)


# runs fine
g(mat, dtype=np.float64)
# and throws expected error
g(mat, dtype='no_type')


@beartype
def h(x: npt.NDArray, dtype: npt.DTypeLike) -> npt.NDArray:
    return x.astype(dtype)

# this runs following error
h(mat, dtype=np.float64)

Using the npt.DTypeLike class throws following error:

/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_util/hint/pep/utilpeptest.py:317: BeartypeDecorHintPep585DeprecationWarning: PEP 484 type hint typing.Tuple[typing.Any, int] deprecated by PEP 585 scheduled for removal in the first Python version released after October 5th, 2025. To resolve this, import this hint from "beartype.typing" rather than "typing". See this discussion for further details and alternatives:
    https://github.com/beartype/beartype#pep-585-deprecations
  warn(
/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_util/hint/pep/utilpeptest.py:317: BeartypeDecorHintPep585DeprecationWarning: PEP 484 type hint typing.Tuple[typing.Any, typing.Any] deprecated by PEP 585 scheduled for removal in the first Python version released after October 5th, 2025. To resolve this, import this hint from "beartype.typing" rather than "typing". See this discussion for further details and alternatives:
    https://github.com/beartype/beartype#pep-585-deprecations
  warn(
/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_util/hint/pep/utilpeptest.py:317: BeartypeDecorHintPep585DeprecationWarning: PEP 484 type hint typing.List[typing.Any] deprecated by PEP 585 scheduled for removal in the first Python version released after October 5th, 2025. To resolve this, import this hint from "beartype.typing" rather than "typing". See this discussion for further details and alternatives:
    https://github.com/beartype/beartype#pep-585-deprecations
  warn(
Traceback (most recent call last):
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_util/cls/pep/utilpep3119.py", line 124, in die_unless_type_isinstanceable
    isinstance(None, cls)  # type: ignore[arg-type]
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/typing.py", line 1497, in __instancecheck__
    raise TypeError("Instance and class checks can only be used with"
TypeError: Instance and class checks can only be used with @runtime_checkable protocols

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/user/Documents/test_beartype/dtype.py", line 35, in <module>
    def h(x: npt.NDArray, dtype: npt.DTypeLike) -> npt.NDArray:
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_decor/cache/cachedecor.py", line 77, in beartype
    return beartype_args_mandatory(obj, conf)
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_decor/_core.py", line 140, in beartype_args_mandatory
    return _beartype_func(func=obj, conf=conf)
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_decor/_core.py", line 171, in _beartype_func
    func_wrapper_code = generate_code(func_data)
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_decor/_code/codemain.py", line 222, in generate_code
    code_check_params = _code_check_args(bear_call)
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_decor/_code/codemain.py", line 470, in _code_check_args
    reraise_exception_placeholder(
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_util/error/utilerror.py", line 202, in reraise_exception_placeholder
    raise exception.with_traceback(exception.__traceback__)
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_decor/_code/codemain.py", line 445, in _code_check_args
    ) = pep_code_check_hint(hint)
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_util/cache/utilcachecall.py", line 343, in _callable_cached
    raise exception
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_util/cache/utilcachecall.py", line 335, in _callable_cached
    return_value = params_flat_to_return_value[params_flat] = func(
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_decor/_code/_pep/_pephint.py", line 1951, in pep_code_check_hint
    hint_curr_expr=add_func_scope_type(
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_decor/_code/_pep/_pepscope.py", line 198, in add_func_scope_type
    die_unless_type_isinstanceable(cls=cls, exception_prefix=exception_prefix)
  File "/home/user/anaconda3/envs/mosaic/lib/python3.10/site-packages/beartype/_util/cls/pep/utilpep3119.py", line 165, in die_unless_type_isinstanceable
    raise exception_cls(exception_message) from exception
beartype.roar.BeartypeDecorHintPep3119Exception: @beartyped g() parameter "dtype" type hint <class 'numpy.typing._dtype_like._SupportsDType'> uncheckable at runtime (i.e., not passable

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
braniiicommented, May 12, 2022

@leycec thank you so much for this helpful answer. Once again you have brought a PEP to my attention. Thx for that 😃 I tried applying the @runtime_checkable to the _SupportDType class, but it still seems to fail. I guess it is related with the other types used in the DTypeLike union/definition, probably the dtype class. I will open an issue on numpy this weekend, and will try to suggest a fix. Would be freaking cool contributing to numpy.

1reaction
leyceccommented, May 11, 2022

Ah-ha! Thanks so much for yet another blisteringly smart feature request. Thankfully for my Tuesday evening, this (surprise!) is an upstream NumPy issue. Me: 😮

You Say Wut

Here’s why. Ever heard of PEP 544-style typing.Protocol-based structural subtyping? Gr8, m8. We laboriously continue. PEP 544 is more than slightly nonsensical, because it requires third-party protocol authors (…like NumPy) to explicitly opt-in to runtime type-checking. That is to say, you have to manually decorate every single protocol you ever declare with the otherwise useless @typing.runtime_checkable decorator: e.g.,

# Always do this, lazily copied from the official Python docs.
from typing import Protocol, runtime_checkable

@runtime_checkable
class GoodProto(Protocol):
    def meth(self) -> int:  # <-- yes, official Python docs define a "meth" protocol
        ...

# *NEVER DO THIS.*
class BadProto(Protocol):
    def meth(self) -> int:  # <-- yes, official Python docs define a "meth" protocol
        ...

Guess which kind of protocols NumPy defines? Yes. That’s right, good friend. NumPy authors forgot to manually decorate their protocols with @runtime_checkable, which is why @beartype and other runtime type-checkers (e.g., typeguard) vomit all over themselves when presented with those protocols.

This is why I growl to myself in an unseemly manner.

What We Goin’ Do Is Dis

Would you mind submitting this exact same issue to NumPy’s upstream issue tracker, @braniii? If you’d like to force a NumPy contribution into your already stunning resume, …always looks hot, bro 😎 you might even submit a PR resolving this.

Fortunately for your Tuesday evening, I’ve already dissected this for you. What you’d need to do is exactly this…

# Change this class declaration in "numpy.typing._dtype_like"...
class _SupportsDType(Protocol[_DType_co]):
    @property
    def dtype(self) -> _DType_co: ...

# ...to look like this, instead! *BOOM.*
from typing import runtime_checkable

@runtime_checkable
class _SupportsDType(Protocol[_DType_co]):
    @property
    def dtype(self) -> _DType_co: ...

If you have even more spare open-source seconds to hurl at this demonstrable problem that will explosively blow up again and again in your face, you might also crawl through the numpy.typing subpackage and do the exact same thing for every other protocol. Notably, I see a similarly problematic:

  • numpy.typing._array_like._SupportsArray protocol.
  • numpy.typing._nested_sequence._NestedSequence protocol.

Whatever you manage to do: thanks soooo much, Danny N.! You make the world a safer place for the quiet data scientists who prowl amongst us.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Support for `numpy.typing.NDArray` · Issue #195 - GitHub
Right now, typeguard doesn't check that the dtype is respected, and doesn't emit notifications when passed a ndarray that has the wrong dtype...
Read more >
Typing (numpy.typing) — NumPy v1.24 Manual
Users who want to write statically typed code should instead use the numpy.ndarray.view method to create a view of the array with a...
Read more >
No module named 'numpy.typing'" - Stack Overflow
I am trying to import ArrayLike doing from numpy.typing import ArrayLike , and I get the error mentioned in the title:.
Read more >
New Tumbleweed snapshot 20210710 released!
New Tumbleweed snapshot 20210710 released! ... Please note that this mail was generated by a script. The described changes are computed based on...
Read more >
Contributing to the code base — pandas 1.5.2 documentation
This can be expressed as a string like "object" , a numpy.dtype like ... pandas uses mypy and pyright to statically analyze the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found