-
-
Notifications
You must be signed in to change notification settings - Fork 53
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
[Bug] Internal error when using beartype
in contexts where a callable / class doesn't have __module__
defined
#381
Comments
Note that, for the above example: print(f.__module__) # None |
So. You bring to me a third-party horror show, huh? During the bountiful peak of Summer in a nation not known for Summer, huh? ...friends don't let friends live in Canada This is fine. I can do this. I can code instead of garden, hike, or bicycle! I believe in myself! @beartype Is On a Crazy Train and You're InvitedActually, I believe I can elucidate a bit of what's happening here. What's happening here is that either Specifically, someone who shall remain nameless appears to be stringifying type hints (i.e., converting normal type hints from normal usable runtime objects into useless strings that @beartype can't do much with). Like all type-checkers, @beartype treats stringified type hints as forward references to undefined classes that are subsequently defined later. @beartype resolves forward references by dynamically importing those previously undefined classes at the last possible moment from the modules defining those classes. So far so good, right? But let's back up a bit. You might now be ruminating to yourself:
We do. In the traceback you so graciously copy-pasted above, we clearly see that the private What forward reference could possibly be resolved here? I'm not quite sure, honestly. I only see a single type hint # Is "Int" a class defined something like this...?
class Int(...): ...
# ...or is "Int" a string referring to a class that has yet to be defined like this...?
Int = 'GehHehHehYouGoAndJustDieBeartype' I'm assuming the former. The latter would be kinda weird, right? And you're not weird, unlike me. You live in Boston. Everyone cool lives in Boston! When the Badness Get Going, the Code Get Blowing UpSo.
Somewhere, someone who is not you is forcefully rewriting your module to resemble: from __future__ import annotations # <-- NO GODS WHY NOOOOOOOOOOOOOOOOOOOOOOOOOOOO
from my_lib.typing import typecheck, Int
@typecheck # beartype
def f(x: Int):
return x + 1.0
try:
f(1.0)
except TypeError as e:
print(e) @leycec Bout to Throw Down the Gauntlet on Somebody's Issue TrackerSo. Some Bad Dude™ both destroyed type hints and the standard Of course, this isn't to say that @beartype isn't at least partially at fault here. @beartype is raising an unreadable exception, which is totally our fault. That said, a dramatic explosion in badness is still happening. Since @beartype was given a function annotated by a forward reference but given no means of resolving that forward reference, the best that @beartype can do here is raise a more human-readable exception message resembling: BeartypeCallHintForwardReference: Function f() parameter "x"
forward reference "Int" not resolvable, as f() dunder attribute
"__module__" undefined. So much bad stuff is happening here all
at once that @beartype can no longer cope with the explosion in badness. Rage! Rage at the dying of the codebase, @beartype!
|
This commit improves the readability of exceptions raised by edge-case `@beartype`-decorated callables annotated by one or more forward references while also failing to define the `__module__` dunder attribute, resolving issue #381 kindly submitted by dynamical Bostonian and bonafide real-life main character @femtomc (McCoy R. Becker). For unknown (and probably indefensible) reasons, the third-party `markdown-exec` package appears to define such horrifying callables. When confronted with such horrifying callables, the `@beartype` decorator now raises human-readable exceptions resembling: ```python beartype.roar.BeartypeDecorHintForwardRefException: Function muh_func() parameter "muh_arg" forward reference type hint "MuhType" unresolvable, as "muh_func.__module__" dunder attribute undefined (e.g., due to <function muh_func at 0x7f030d402160> being defined only dynamically in-memory). So much bad stuff is happening here all at once that @beartype can no longer cope with the explosion in badness. ``` Flex those burly exception messages, @beartype! Flex 'em! (*A flexible lexicon on iconic nicks!*)
Resolved by b215401... which is to say, I basically did nothing. That commit sucks so much! I fully admit it. Sadly, there's simply not much of value that @beartype can add here. The problem and thus the solution is outside our paws. All @beartype can do is raise more human-readable exceptions here. Given this minimal-working example that exhibits a similar issue... from beartype import beartype
def muh_func(muh_arg: 'MuhType'):
return muh_arg + 1.0
del muh_func.__module__ # <-- *GAH!* wat u doin, markdown-exec!?!? y u do us dirty like that?
muh_func_checked = beartype(muh_func) ...@beartype now raises this slightly more readable exception: beartype.roar.BeartypeDecorHintForwardRefException: Function muh_func() parameter "muh_arg" forward
reference type hint "MuhType" unresolvable, as "muh_func.__module__" dunder attribute undefined (e.g.,
due to <function muh_func at 0x7fd3f5402160> being defined only dynamically in-memory). So much bad
stuff is happening here all at once that @beartype can no longer cope with the explosion in badness. I now blame |
I understand the humorous tone (and I know you have this reputation to keep @leycec), though your answers could definitely use less negative words towards a project you don't know, whether it's why it does what it does, or how it does it 😉 For the explanation: |
Yeah I have to say I really don't like this communication style. |
It is what it is. I'm happy – nay, delighted even – to call out bad actors for bad behaviour. It's simply honesty. When @beartype behaves badly (...an all too common occurrence, sadly), I expect and hope for an equal dose of honesty. Then again, I'm literally autistic. I don't necessarily play well with others, because I praise honesty and integrity well above conviviality and sociability. You can have honesty or you can have sociability – but you can't necessarily have both. This probably explains why hierarchical institutions tend to favour sociability over honesty. As a hierarchical institution increases in scale, sociability supplies the continuous stream of ideological "glue" needed to weld disparate individuals with diverse dispositions, intentions, and expectations into a cohesive unity. Honesty's pretty much out the window at that point, huh? Of course, even honesty can swing too far. Linus Torvalds is the open-source poster child for "honesty" so acerbic that it was really just toxic abusiveness by another word. It's a fine line. Being autistic, I neurologically have no idea where the line even is. I try never to cross the line... but all I can do is try. I try to always inject humour, good cheer, and a penchant for madcap memes into everything I do. In the end, though, I'm just fumbling around in the dark like Daredevil on all all-night circus bender. But... yeah. Honesty. What you gonna do, huh? 🤔 |
@femtomc, as a work-around, have you considered something like what @pawamoy, this is a bit off topic, but it can be useful to recall that human beings are diverse, with many different communication styles. One of the wonderful things about this modern world is venues like these which afford collaboration across great divides. Understanding that others' styles may differ than our own or stray slightly from our preferences can be very helpful. Admittedly, this difficult sometimes, but I find it useful to start with the assumption that we all come with the best of intentions and we're all doing the best we reasonably can. This affords connection to others without first requiring they conform to our individual ideals. @leycec, have I ever told you you're my hero? You are the wind beneath my wings. 🪽💨 |
@femtomc: Gah! I forgot to mention the most important and useful thing while delivering an unimportant and useless manologue – which is that import sys # <-- new imports x 1
from beartype import beartype, BeartypeConf, BeartypeStrategy # <-- new imports x 2
from my_lib.typing import Int
# If "markdown-exec" is currently running, reduce the @beartype decorator to a noop.
if 'markdown_exec' in sys.modules:
typecheck = beartype(conf=BeartypeConf(strategy=BeartypeStrategy.O0))
# Else, preserve the @beartype decorator as is.
else:
typecheck = beartype
@typecheck
def f(x: Int):
return x + 1.0
try:
f(1.0)
except TypeError as e:
print(e) Does that actually work? No idea, bro. It should – but I should have hair. "Don't worry!", they said. "Hair loss skips a generation!", they said. Sometimes, should just isn't good enough. 😭 @posita: Such a boss! Such a boss reply! Understanding intensifies. Now, let's retroactively time-travel to the past ...wait. isn't time-travel by definition retroactive? 🤔 as I beg you to deliver this empathetic pro-neurodiversity wall of inspirational speech to all of my prior workplaces. We can finish the night at an all-you-can-stuff-into-your-face izakaya in downtown Manhattan. I might still live and work in the United States if we establish this time loop right now. My Canadian wife is wailing in anguish, though! Noooooooooooo. And... on second thought, let's not do this. The space-time continuum is warped enough. 😅
|
@posita thanks for chiming in. I do recall that human beings are diverse, with many different communication styles. That is exactly why I allowed myself to express that I was uncomfortable with the way @leycec put things. I don't ask, and will never ask of anyone to conform to a particular communication style. You do what you want. Note that I wrote communication and not writing: I actually like @leycec's writing style. I did smile when reading your answers @leycec. But to me they're just full of assumptions that something does what it does for a reason, while we all know that the software world is riddled with bugs and unexpected/accidental behavior. You actually don't need to call out "bad actors", because we're all "bad actors" at some point. I'd prefer we keep this negative wording for actually bad/malicious actors. Or just, you know, don't use it in the entirety of our comments towards someone else's project. There's a way to be funny without being mean and making assumptions. I hope you'll be able to use my answer as a data point to know where my line is (and maybe others') in the future, if you even care, instead of doubling-down on assumptions and negative wording 🤷
These are completely insensitive things to say to other open-source maintainers.
...nothing. |
At the risk of venturing waaay off topic. I concede that humor (perhaps especially written exaggeration or irony) resonates very differently with different people. I accept this isn't your cup of tea. With all love and respect, I also don't see the presence of mal-intent anywhere in this thread. I'm willing to stake my career that @leycec does not take pleasure in the suffering of others, and doubt very much you do either. Perhaps we can all give each other the benefit of the doubt? |
Hi!
I'm attempting to show users of my library what a
beartype
error will look like, if they trip over it.I have some code:
Now, if I execute this inside my documentation (which is using
mkdocs
, andmarkdown-exec
https://github.com/pawamoy/markdown-exec) -- I get what I think is an internalbeartype
error rendered into my documentation:I believe this is due to how
markdown-exec
works -- perhaps the__module__
dunder is not defined for objects which are defined in the context whichmarkdown-exec
executes the code.But simply, I'm wondering if I can turn off this level of reporting -- via customizing the configuration. It also seems reasonable to expect that this could be a hard problem (it makes sense for
beartype
to expect that this attribute is always defined). I can then go file an issue atmarkdown-exec
.Environment
I'm using
beartype==0.18.5
.The text was updated successfully, but these errors were encountered: