Repository: beartype/beartype

Issue #71: [Feature Request] PEP 604 Support
Created: 2021-11-17T10:26:40Z
Hi @leycec , thanks for a great library!
Upon discovered of this decorator, I thought I'd give beartype a run in my codebase -- I am a heavy user of dataclasses. And, of course, a heavy user of runtime-checks!
After the proof-of-concept work, everything still works. But I did notice:

the from future import __annotations__ had to be removed (I'm a 3.9 user). Is this required by your users?
the initial performance was poorer -- I'd continue to move the handcrafted runtime checks into Is[]. I'd report back later on this.

Duplicate issue #97: Issue with simple testing
Created: 2022-02-08T18:52:48Z
So I'm sure this is just a matter of user error, but I keep running into issues when playing around with beartype in the repl.  For some reason when I'm trying to do the following:
@beartype
def spam(ham: int | str) -> str:
    return str(ham)
... I end up with a huge traceback (see below).  Same thing happens if I do Union[int, str].  I'm not sure what I'm doing wrong here.
BeartypeDecorHintNonpepException          Traceback (most recent call last)
Input In [16], in <module>
      1 @beartype
----> 2 def spam(ham: int | str) -> str:
      3     return str(ham)

File ~\PycharmProjects\pglet-python\__pypackages__\3.10\lib\beartype\_decor\main.py:149, in beartype(func)
    146 func_data.reinit(func)
    148 # Generate the raw string of Python statements implementing this wrapper.
--> 149 func_wrapper_code = generate_code(func_data)
    151 # If this callable requires *NO* type-checking, silently reduce to a noop
    152 # and thus the identity decorator by returning this callable as is.
    153 if not func_wrapper_code:

File ~\PycharmProjects\pglet-python\__pypackages__\3.10\lib\beartype\_decor\_code\codemain.py:166, in generate_code(data)
    161 assert data.__class__ is BeartypeData, f'{repr(data)} not @beartype data.'
    163 # Python code snippet type-checking all callable parameters if one or more
    164 # such parameters are annotated with unignorable type hints *OR* the empty
    165 # string otherwise.
--> 166 code_check_params = _code_check_params(data)
    168 # Python code snippet type-checking the callable return if this return is
    169 # annotated with an unignorable type hint *OR* the empty string otherwise.
    170 code_check_return = _code_check_return(data)

File ~\PycharmProjects\pglet-python\__pypackages__\3.10\lib\beartype\_decor\_code\codemain.py:346, in _code_check_params(data)
    336     continue
    337 # Else, this parameter is non-ignorable.
    338
    339 # PEP-compliant type hint converted from this PEP-noncompliant type
   (...)
    344 #
    345 # Do this first *BEFORE* passing this hint to any further callables.
--> 346 hint = sanify_hint_root(
    347     hint=hint,
    348     func=func,
    349     pith_name=param_name,
    350     exception_prefix=f'{exception_prefix}type hint ',
    351 )
    353 # If this hint is ignorable, continue to the next parameter.
    354 #
    355 # Note that this is intentionally tested *AFTER* this hint has been
    356 # coerced into a PEP-compliant type hint to implicitly ignore
    357 # PEP-noncompliant type hints as well (e.g., "(object, int, str)").
    358 if is_hint_ignorable(hint):
    359     # print(f'Ignoring {data.func_name} parameter {param_name} hint {repr(hint)}...')

File ~\PycharmProjects\pglet-python\__pypackages__\3.10\lib\beartype\_util\hint\utilhintconv.py:218, in sanify_hint_root(hint, func, pith_name, exception_prefix)
    209 hint = func.__annotations__[pith_name] = _coerce_hint_root(
    210     hint=hint,
    211     func=func,
    212     pith_name=pith_name,
    213     exception_prefix=exception_prefix,
    214 )
    216 # If this object is neither a PEP-noncompliant type hint *NOR* supported
    217 # PEP-compliant type hint, raise an exception.
--> 218 die_unless_hint(hint=hint, exception_prefix=exception_prefix)
    219 # Else, this object is a supported PEP-compliant type hint.
    220
    221 # Reduce this hint to a lower-level PEP-compliant type hint if this hint is
   (...)
    243 # Note that parameters are intentionally passed positionally to both
    244 # optimize memoization efficiency and circumvent memoization warnings.
    245 hint = _reduce_hint(hint, exception_prefix)

File ~\PycharmProjects\pglet-python\__pypackages__\3.10\lib\beartype\_util\hint\utilhinttest.py:101, in die_unless_hint(hint, exception_prefix)
     96     die_if_hint_pep_unsupported(hint=hint, exception_prefix=exception_prefix)
     98 # Else, this hint is *NOT* PEP-compliant. In this case, raise an exception
     99 # only if this hint is also *NOT* PEP-noncompliant. By definition, all
    100 # PEP-noncompliant type hints are supported by @beartype.
--> 101 die_unless_hint_nonpep(hint=hint, exception_prefix=exception_prefix)

File ~\PycharmProjects\pglet-python\__pypackages__\3.10\lib\beartype\_util\hint\nonpep\utilnonpeptest.py:208, in die_unless_hint_nonpep(hint, is_str_valid, exception_cls, exception_prefix)
    203     assert isinstance(exception_cls, type), (
    204         f'{repr(exception_cls)} not type.')
    205     assert isinstance(exception_prefix, str), (
    206         f'{repr(exception_prefix)} not string.')
--> 208     raise exception_cls(
    209         f'{exception_prefix}type hint {repr(hint)} '
    210         f'neither PEP-compliant nor -noncompliant '
    211         f'(e.g., isinstanceable class, forward reference, or '
    212         f'tuple of isinstanceable classes and forward references).'
    213     )
    214 # Else, forward references are unsupported. In this case, raise an
    215 # exception noting that.
    216 else:
    217     raise exception_cls(
    218         f'{exception_prefix}type hint {repr(hint)} '
    219         f'neither PEP-compliant nor -noncompliant '
    220         f'(e.g., isinstanceable class or tuple of isinstanceable classes).'
    221     )

BeartypeDecorHintNonpepException: @beartyped spam() parameter "ham" type hint type hint int | str neither PEP-compliant nor -noncompliant (e.g., isinstanceable class, forward reference, or tuple of isinstanceable classes and forward references).

Closing comment (2022-02-08T23:10:58Z): marked as duplicate of #71