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.

Ruh-roh! CACHING protocols? More like CRASHING protocols (in 3.7)! Amirite?

See original GitHub issue

So hereā€™s a head-scratcher:

# test_ruh_roh.py
from abc import abstractmethod
from beartype import beartype
from beartype.typing import TYPE_CHECKING, Iterable, Protocol, TypeVar, Union, runtime_checkable

_T_co = TypeVar("_T_co", covariant=True)

if TYPE_CHECKING:
    from abc import ABCMeta as _BeartypeCachingProtocolMeta
else:
    _BeartypeCachingProtocolMeta = type(Protocol)

# - - - - - - - - - - - - - - - - SupportsInt - - - - - - - - - - - - - - - -

@runtime_checkable
class SupportsInt(
    Protocol,  # <-- this is totally cool
    metaclass=_BeartypeCachingProtocolMeta,
):
    __slots__: Union[str, Iterable[str]] = ()
    @abstractmethod
    def __int__(self) -> int:
        pass

@beartype  # <-- this works
def myint(arg: SupportsInt) -> int:
    return int(arg)

print(f"{myint(0.0)} == {0}?")
assert myint(0.0) == 0

# - - - - - - - - - - - - - - - - SupportsAbs[_T_co] - - - - - - - - - - - - - - - -

@runtime_checkable
class SupportsAbs(
    Protocol[_T_co],  # <-- uh-oh, now we're askin' for trouble
    metaclass=_BeartypeCachingProtocolMeta,
):
    __slots__: Union[str, Iterable[str]] = ()
    @abstractmethod
    def __abs__(self) -> _T_co:
        pass

@beartype  # <-- boom
def myabs(arg: SupportsAbs[_T_co]) -> _T_co:
    return abs(arg)

print(f"{myabs(-1)} == {1}?")
assert myabs(-1) == 1

Using beartype @ 8da3ab48e80d37267b38938f22bf8ce2d1c070ba in 3.8:

% python3.8 -m mypy test_ruh_roh.py
Success: no issues found in 1 source file
% python3.8 test_ruh_roh.py
0 == 0?
1 == 1?

And now 3.7:

% python3.7 -m mypy test_ruh_roh.py
Success: no issues found in 1 source file
% python3.7 test_ruh_roh.py
0 == 0?
Traceback (most recent call last):
  File "test_ruh_roh.py", line 45, in <module>
    def myabs(arg: SupportsAbs[_T_co]) -> _T_co:
  File "/ā€¦/beartype/beartype/_decor/main.py", line 193, in beartype
    return beartype_args_mandatory(obj, conf)
  File "/ā€¦/beartype/beartype/_decor/_core.py", line 140, in beartype_args_mandatory
    return _beartype_func(func=obj, conf=conf)
  File "/ā€¦/beartype/beartype/_decor/_core.py", line 171, in _beartype_func
    func_wrapper_code = generate_code(func_data)
  File "/ā€¦/beartype/beartype/_decor/_code/codemain.py", line 222, in generate_code
    code_check_params = _code_check_args(bear_call)
  File "/ā€¦/beartype/beartype/_decor/_code/codemain.py", line 477, in _code_check_args
    func=bear_call.func_wrappee, arg_name=arg_name),
  File "/ā€¦/beartype/beartype/_util/error/utilerror.py", line 202, in reraise_exception_placeholder
    raise exception.with_traceback(exception.__traceback__)
  File "/ā€¦/beartype/beartype/_decor/_code/codemain.py", line 392, in _code_check_args
    exception_prefix=EXCEPTION_PREFIX,
  File "/ā€¦/beartype/beartype/_util/hint/utilhintconv.py", line 214, in sanify_hint_root
    die_unless_hint(hint=hint, exception_prefix=exception_prefix)
  File "/ā€¦/beartype/beartype/_util/hint/utilhinttest.py", line 102, in die_unless_hint
    die_unless_hint_nonpep(hint=hint, exception_prefix=exception_prefix)
  File "/ā€¦/beartype/beartype/_util/hint/nonpep/utilnonpeptest.py", line 206, in die_unless_hint_nonpep
    f'{exception_prefix}type hint {repr(hint)} either '
beartype.roar.BeartypeDecorHintNonpepException: @beartyped myabs() parameter "arg" type hint __main__.SupportsAbs[+_T_co] either PEP-noncompliant or currently unsupported by @beartype.

Iā€™m scratching my head for two reasons: 1) numerary gets away with something nearly identical without breaking, even in 3.7; and 2) everything works as expected for 3.8.

So I think I screwed up a translation somewhere (most likely in #103).

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:12 (10 by maintainers)

github_iconTop GitHub Comments

2reactions
positacommented, Mar 11, 2022

Thank you for removing the festering nonsense that I introduced to pollute an otherwise pristine codebase! My apologies for not doing it myself sooner. šŸ˜ž

If I didnā€™t already tell you, one of my favorite things is to delete problematic code. Iā€™m chalking this up to a win. ā¤ļø

Anyone can write code. It takes a real bear to delete it.

2reactions
leyceccommented, Mar 8, 2022

date night

Thatā€™s a funny way to spell ā€œMandatory Friday Afternoons at the Rick & Morty Matinee.ā€ Cottage country: you know we gets wild here. šŸ˜

sipping hot tea by the wood pellet stove with a good book

You know us well. Our 500-pound Main Coon cat Wolfie (so-named for good reason) rumbles contentedly. Your knowledge of the hidden life and hobbies of the average bottom-feeding Canadian cabin-dweller isā€¦ uncanny.

I intended to insert additional quips here, but then got tired. Instead:

  • I merged #110 to expose the rot at the core of our beartype.typing.Protocol Python 3.7 backport. We rejoice in our shared failures.
  • I wonder if this logic might suffice to fix this. Despite being untested in every way, I choose to believe in hope and change. I literally just added or IS_PYTHON_3_7, so thereā€™s no way this works:
                # Protocol class to be passed as the "cls" parameter to the
                # unwrapped superclass typing.Protocol.__class_getitem__()
                # dunder method. There exist two unique cases corresponding to
                # two unique branches of an "if" conditional in that method,
                # depending on whether either this "Protocol" superclass or a
                # user-defined subclass of this superclass is being
                # subscripted. Specifically, this class is...
                protocol_cls = (
                    # If this "Protocol" superclass is being directly
                    # subclassed by one or more type variables (e.g.,
                    # "Protocol[S, T]"), the non-caching "typing.Protocol"
                    # superclass underlying this caching protocol superclass.
                    # Since the aforementioned "if" conditional performs an
                    # explicit object identity test for the "typing.Protocol"
                    # superclass, we *MUST* pass that rather than this
                    # superclass to trigger that conditional appropriately.
                    _ProtocolSlow
                    if cls is Protocol or IS_PYTHON_3_7 else
                    # Else, a user-defined subclass of this "Protocol"
                    # superclass is being subclassed by one or more type
                    # variables *OR* types satisfying the type variables
                    # subscripting the superclass (e.g.,
                    # "UserDefinedProtocol[str]" for a user-defined subclass
                    # class UserDefinedProtocol(Protocol[AnyStr]). In this
                    # case, this subclass as is.
                    cls
                )

Mr. Hypno Palm

šŸ¦¾

ā€¦I have to wonder whether things really should be this hard.

ā€¦heh. If it wasnā€™t hard, Guido would have done it. This is why he didnā€™t. We suffer that others may actually use protocols at runtime. We do this in remembrance of typing.Protocol, that no one may ever use that again.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Cache coherency protocols (examples) - Wikipedia
Examples of coherency protocols for cache memory are listed here. For simplicity, all "miss" Read and Write status transactions which obviously come fromĀ ......
Read more >
Recovery in Spritely NFS - CiteSeerX
ABSTRACT: NFS suffers from its lack of an explicit cache-consistency protocol. The Spritely NFS experi- ment, which grafted Sprite's cache-consistencyĀ ...
Read more >
Is there a way to set a different pickle version for Django cache ...
However as I'm using python 3.9 and production is running python 3.7, I'm running into "unsupported pickle protocol" errors when the cacheĀ ...
Read more >
Cache Coherence Protocols in Multiprocessor System
This is a basic cache coherence protocol used in multiprocessor system. The letters of protocol name identify possible states in which aĀ ...
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