Skip to content

Releases: beartype/beartype

Beartype 0.18.5: Going even Broker with Beartype

21 Apr 07:25
Compare
Choose a tag to compare

The @beartype 0.18.X release cycle continues to bear lukewarm fruit that tastes vaguely starchy. It's cheap and smells faintly of kerosene. It keeps the hunger at bay even as it fails to fully satiate.

Beartype 0.18.5 preserves this trend by resolving... just a single issue! Beartype 0.18.5 resolves a critical low-level issue in @beartype's dynamic type-checking code generator for nested beartype validator-in-container type hints (e.g., type hints of the form list[typing.Annotated[{type}, Is[{validator}]]]). Someone, somewhere cares deeply about this. You might even be that someone.

Hype is completely out the window at this point, everybody. We're just hardening the fat-packed abs of the bear against critical breakage, because your codebase matters more to us than our sleep. And now...

This release comes courtesy these proud GitHub Sponsors, without whom @leycec's cats would currently be eating grasshoppers:

Thanks so much, masters of fintech and metrology.


The Masters of Fintech and Metrology. That's who.

Beartype 0.18.4: Going for Broke with Beartype

19 Apr 07:34
Compare
Choose a tag to compare

The @beartype 0.18.X release cycle continues to bear lukewarm fruit that tastes vaguely starchy. It's cheap and smells faintly of kerosene. It keeps the hunger at bay even as it fails to fully satiate.

Beartype 0.18.4 preserves this trend by resolving... just a single issue! Beartype 0.18.4 resolves a critical low-level issue in @beartype's dynamic type-checking code generator for nested tuple-in-dictionary type hints (i.e., type hints of the form dict[tuple[...], ...]). Someone, somewhere cares deeply about this. You might even be that someone.

Hype is completely out the window at this point, everybody. We're just hardening the fat-packed abs of the bear against critical breakage, because your codebase matters more to us than our sleep. And now...

This release comes courtesy these proud GitHub Sponsors, without whom @leycec's cats would currently be eating grasshoppers:

Thanks so much, masters of fintech and metrology.


The Masters of Fintech and Metrology. That's who.

Beartype 0.18.3: For Justice, For Victory, For QA

18 Apr 06:35
Compare
Choose a tag to compare

Beartype 0.18.3 is the minor patch release that your careening codebase can no longer live without:

pip install --upgrade beartype

Actually... I lied. I know! I gotta stop doing that. But the sordid truth is that beartype 0.18.3 is mostly just for @iamrecursion and @sylvorg, who single-handedly reported more issues in a single week than the exploding size of @leycec's JRPG backlog. And we know how big that is, don't we? It's big. It's so big it wraps around like a self-sustaining Niven ringworld habitat at Lagrange point L1. Big-big.

Beartype 0.18.3 is for @iamrecursion and @sylvorg. May their usernames live forever in git log infamy. In this release, a few more bugs die.

But first...

GitHub Sponsors: They Scratch the Bear's Back. Now, The Bear Scratches Back.

This release comes courtesy these proud GitHub Sponsors, without whom @leycec's cats would currently be eating grasshoppers:

Thanks so much, masters of fintech and metrology.


The Masters of Fintech and Metrology. That's who.

Type Variables Bound by Forward References: So This Is a Thing, Huh?

So. Funny story. Turns out you can bound PEP 484-compliant type variables (i.e., typing.TypeVar(...) objects) with forward references specified as strings. Who knew? Everybody except @leycec. Nobody tells that guy nuthin'.

Beartype 0.18.3 now explicitly supports type variables bound by forward references. These are type hints of the form:

TypeVar('{TypeVarName}', bounds='{UndefinedType}')

Previously, @beartype only partially supported such variables due to @leycec failing to realize that such variables even existed and constituted a valid use case. This is why your codebase can't have good things. Now, @beartype fully supports heinous abominations valid use cases like:

from beartype import beartype
from typing import TypeVar

# Type variable bound by a forward reference. @beartype supports your
# weird stuff, because normalcy is just a null pointer to garbage.
Fuggit = TypeVar('Fuggit', bound='EnduringMisery')

@beartype
class EnduringMisery(object):
    def searing_pain(self) -> tuple[Fuggit, Fuggit]:
        return ('Fuggit...', '...up!')

# Can anyone guess what this does? That's right. It blows up. Fuggit!
blinding_agony = EnduringMisery()
blinding_agony.searing_pain()


hangin' with the bear homies in apocalyptic wasteland ain't no thang

beartype.vale.Is[...]: Now It Supports Crazy Stuff

The functional beartype validator factory beartype.vale.Is[...] is now subscriptable (indexable) by all manner of shambolic nightmares. Previously, you had to subscript Is[...] with low-level functions and methods. Now, you can subscript Is[...] with high-level callable objects like:

  • Class-based callables (i.e., objects whose classes define the __call__() dunder method, rendering otherwise uncallable objects callable): e.g.,

    from beartype.door import is_bearable
    from beartype.typing import Annotated
    from beartype.vale import Is
    from functools import partial
    
    class TruthSeeker(object):
        def __call__(self, obj: object) -> bool:
            '''
            Tester method returning :data:`True` only if the passed object
            evaluates to :data:`True` when coerced into a boolean and whose
            first parameter is ignorable.
            '''
    
            return bool(obj)
    
    # Beartype validator matching only objects that evaluate to "True".
    Truthy = Annotated[object, Is[TruthSeeker()]]
    
    assert is_bearable('', Truthy) is False
    assert is_bearable('Even lies are true now, huh?', Truthy) is True
  • Partials (i.e., high-level functools.partial(...) callable objects wrapping low-level functions and methods): e.g.,

    from beartype.door import is_bearable
    from beartype.typing import Annotated
    from beartype.vale import Is
    from functools import partial
    
    def is_true(ignorable_arg, obj):
        '''
        Tester function returning :data:`True` only if the passed object
        evaluates to :data:`True` when coerced into a boolean and whose first
        parameter is ignorable.
        '''
    
        return bool(obj)
    
    # Partial of the is_true() tester defined above, effectively ignoring the
    # "ignorable_arg" parameter accepted by that tester.
    is_true_partial = partial(is_true, 'Gods. This code is literally unreadable.')
    
    # Beartype validator matching only objects that evaluate to "True".
    Truthy = Annotated[object, Is[is_true_partial]]
    
    assert is_bearable('', Truthy) is False
    assert is_bearable('Even lies are true now, huh?', Truthy) is True

Is this valuable? No idea. Let's pretend I did something useful tonight so I can sleep without self-recrimination.


...heh. your eyes are now bleeding

Triply-Redeclared Types: Just don't ask.

Beartype 0.18.3 now sports improved support we rhymin' like it's 2099 ova here for Jupyter Notebook cells. Do you like Jupyter? Do you like @beartype? Then you need beartype 0.18.3 now, because beartype 0.18.2 probably already broke everything without your informed consent. Woops.

Beartype 0.18.3 resolves inscrutable non-determinism (which is technically deterministic if you squint at it, but we don't talk about that) with respect to repeatedly redefined classes defining one or more methods annotated by one or more self-referential relative forward reference (i.e., referring to the class currently being defined). @beartype is now considerably more robust against non-determinism in Jupyter cells containing @beartype-decorated self-referential classes like:

from beartype import beartype

@beartype
class MuhSelfReferentialClass(object):
    def __init__(self, muh_var: int) -> None:
        self.muh_var = muh_var

    @classmethod
    def muh_factory(cls, muh_var: int) -> "MuhSelfReferentialClass":
        '''
        This is fine now. No matter how much you reload the cell
        defining this class, @beartype will still stan for you.

        I have no idea what "stan" even means. I think it's good.
        '''

        return MuhSelfReferentialClass(muh_var + 42)

muh_object = MuhSelfReferentialClass.muh_factory(42)

Flex those burly QA biceps, @beartype. Flex 'em.


things explode when you put @beartype back in the sheath

__class_getitem__ = classmethod(GenericAlias): We Do That Too, Whatever That Is

So. You want to refactor your heroic class that will truly shape the course of human history into a subscriptable type hint factory. You even know about the convenient but unreadable one-line idiom for casting this dark magic. Previously, @beartype refused to support your bad habits arcane knowledge. Now, @beartype understands and appreciates everything you're trying to do for humanity.

Beartype 0.18.3 generalizes the @beartype decorator to support decoration of user-defined types that declare class methods by directly calling the builtin @classmethod decorator as a function passed a C-based callable type (e.g., classmethod(types.GenericAlias)). Doing so enables @beartype to support the standard idiom for user-defined subscriptable type hint factories under Python >= 3.9:

from abc import ABCMeta
from beartype import beartype
from types import GenericAlias

@beartype
class MuhTypeHintFactory(metaclass=ABCMeta):
    '''
    Congrats. Subscripting this class now trivially makes new type hints
    that @beartype fails to understand or appreciate.
    '''

    # This exact one liner appears verbatim throughout the standard
    # library as well as popular third-party packages like NumPy.
    __class_getitem__ = classmethod(GenericAlias)

# Not sure what this means, but you insist you know what you're doing.
# *Do* you, though? *Do* you? @beartype is out to lunch on this one.
MuhTypeHint = MuhTypeHintFactory[str]


the pancakes get me every time. srsly. what is with those pancakes?

Forward Reference Deprioritization: What Does This Even Mean!?

Beartype 0.18.3 deprioritizes @beartype-specific forward reference proxies (i.e., internal objects proxying external user-defined types that have yet to be defined) in type tuples passed as the second arguments to the isinstance() builtin, reducing the likelihood that type-checks involving forward references will raise unexpected exceptions. For example, consider this simple example:

from beartype import beartype
from beartype.typing import Union

@beartype
def explosive_funk(muh_arg: Union['UndefinedType', None] = None):
    print("You thought this was gonna blow up, huh? You're not alone.")
    print("Unless you're in space. In which case you're really alone.")

explosive_funk()

class UndefinedType(object...
Read more

Beartype 0.18.2: Now With Even Less Broky

03 Apr 07:57
Compare
Choose a tag to compare

Much like your neighbour's obese cat, even @beartype 0.18.1 didn't quite work out as expected. This patch release temporarily squelches (i.e., silences) a low-level assert statement erroneously performed during @beartype's dynamic code generation loop. Is this the end to the horror show that keeps on giving? Will the ill-fated @beartype 0.18.x release cycle finally pass muster and stop violating the world? Tune in next time as @leycec clutches his chest in agony live on GitHub.

Obligatory awesome peeps!

GitHub Sponsors: They Scratch the Bear's Back. Now, The Bear Scratches Back.

This release comes courtesy these proud GitHub Sponsors, without whom @leycec's cats would currently be eating grasshoppers:

Thanks so much, masters of fintech.


The Masters of Fintech. That's who.

Beartype 0.18.1: Now With Less Broky

03 Apr 07:24
Compare
Choose a tag to compare

Much like your neighbour's obese cat, @beartype 0.18.0 didn't quite work out as expected. This patch release temporarily reverts default value type-checking (i.e., type-checking of default values of optional parameters annotated by type hints accepted by @beartype-decorated callables), restoring sanity to the downstream community of @beartype consumers.

Although desirable, this functionality is also a lot more nuanced than @leycec previously assumed -- resulting in @leycec clutching his bald head as if he still had something to clutch there. Since improving this functionality to be robust against breakage is non-trivial, the proper solution is to temporarily disable that functionality. Thus, we cry.

Obligatory awesome peeps!

GitHub Sponsors: They Scratch the Bear's Back. Now, The Bear Scratches Back.

This release comes courtesy these proud GitHub Sponsors, without whom @leycec's cats would currently be eating grasshoppers:

Thanks so much, masters of fintech.


The Masters of Fintech. That's who.

Beartype 0.18.0: Dictionaries and Defaults at the Event Horizon of the Typing Hole

02 Apr 08:07
Compare
Choose a tag to compare

Beartype 0.18.0 whimsically gyrates around in balloon pants while chanting: "Can't touch this."


...even the token bald man in a smoking post-apocalyptic wasteland doesn't know

It's kinda creepy, honestly – and it's really getting on your nerves. Yes, we get it. You think you're hot junk, @beartype 0.18.0! Yet you can't help but admire the sweat that coats its body. Beartype 0.18.0 worked out for this release. It's buff now. It's tough now. It does things now. It does things you thought it did five years ago now. Beartype 0.18.0 finally caught up to your expectations. It even tried to exceed them. It didn't, of course. It couldn't. It's only a bear. It rarely bathes. And, anyway, your expectations were unreasonable.

But... it almost did. Prepare to have your expectations almost exceeded:

pip install --upgrade beartype

But what is @beartype 0.18.0? What does it do? Nuthing, huh? It's all just hollow hype and empty promises again, huh?

To answer that reasonable question, let's unreasonably back up with an extended monologue while the camera man slow pans across @leycec's baldpate. What was @beartype < 0.18.0? Why would anyone actually suffer install older @beartype releases? In the anachronistic words of an inconvenient acronym I just made up: scientific quality assurance (SciQA). So you wanna type-check...

We're agreed that @beartype < 0.18.0 was limited in scope. If you fit inside that scope, your codebase fits inside a backpack. Congratulations. It pays to be lean. But what if you have a real codebase? What if you wanted to actually type-check general-purpose Python containers outside that scope?

You use @beartype 0.18.0! That's right. We're finally type-checking general-purpose Python containers. But first...

A Bald Man in Yellow Tights Confronts a Murderous Cyborg Live on GitHub

Prepare your battle-hardened body and soul for the epic maelstrom of delivered features that follows by watching this malicious YouTube video! Just kidding. It's wholesome. Really. It's Saitama vs. Genos – surely humanity's crowning achievement. Praise be to Arifumi Imai for he has seen the countenance of many small gods and found them all sadly lacking.

@leycec always queues up Saitama vs. Genos when he needs to get hyped. Gonna groom the hair off a scary cat giving you the ugly fish-eyed thousand-yard death grimace? Saitama vs. Genos. Gonna remount your girlfriend's 64-core ThreadInfernoBurner CPU that's already sintered six motherboards into charred thermal paste in the wood shed out back that the sea walruses are rifling through? Saitama vs. Genos. When things get real, you just get realer. Saitama vs. Genos.


when your shoulders rip off their hinges, you just hope that t-shirt was disposable

And now...

GitHub Sponsors: They Scratch the Bear's Back. Now, The Bear Scratches Back.

This release comes courtesy these proud GitHub Sponsors, without whom @leycec's cats would currently be eating grasshoppers:

Thanks so much, masters of fintech.


The Masters of Fintech. That's who.

And now... the moment people I have never met have been waiting for.

Dictionaries: The Mapping is Not the Territory, Whatever That Means

Beartype 0.18.0 now deeply type-checks the first key-value pair of each dictionary (mapping) annotated by a dictionary (mapping) type hint in O(1) constant time with negligible constant factors. This means near-real-time with runtime overhead of at most ~1µs (i.e., one microsecond, one millionth of a second) per type-check. This includes all hints of the form:

  • dict[..., ...].
  • collections.defaultdict[..., ...].
  • collections.abc.Mapping[..., ...].
  • collections.abc.MutableMapping[..., ...].
  • collections.abc.OrderedDict[..., ...].
  • typing.DefaultDict[..., ...].
  • typing.Dict[..., ...].
  • typing.Mapping[..., ...].
  • typing.MutableMapping[..., ...].
  • typing.OrderedDict[..., ...].

This (...probably) also includes @wesselb's multiple-dispatch pièce de résistance Plum, which should now automatically multiple-dispatch across different kinds of dictionaries without @wesselb actually having to do anything. Let us choose to believe this optimistic prophecy I have delivered.

Beartype 0.18.0 does so (...effectively) recursively on arbitrarily nested combinations and permutations of those type hints. The proof is in the disgusting British blood pudding possibly named something like "toad-in-the-bear-hole":

from beartype import beartype
from collections.abc import Mapping, MutableMapping

@beartype
def go_bear(bear_bros_for_life: dict[
    int, Mapping[str, MutableMapping[bytes, bool]]]) -> None:
    print(bear_bros_for_life)

# This passes. A beautiful dictionary brings a tear to the eye.
go_bear({
    1: {
        'Beautiful bird;': {
            b'thou voyagest to thine home,': False,
        },
    },
})

# This fails! A horrible dictionary brings your app crashing to the ground.
go_bear({
    1: {
        'With thine,': {
            b'and welcome thy return with eyes': 1,
        },
    },
})

Type-checking violation messages even identify the exact key-value pair of arbitrarily complex pure-Python data structures responsible for those violations. The above example now helps you ruin your coworker's all-too-brief web app career by raising:

beartype.roar.BeartypeCallHintParamViolation: Function __main__.go_bear()
parameter bear_bros_for_life={1: {'With thine,': {b'and welcome thy return with eyes': 1}}}
violates type hint dict[int, collections.abc.Mapping[str, collections.abc.MutableMapping[bytes, bool]]],
as dict key int 1 value dict key str 'With thine,' value dict key bytes
b'and welcome thy return with eyes' value int 1 not instance of bool.

Beartype 0.18.0: I swear that looks more readable when you see it in person.


if my leg ever bends like that, please call for help

Defaults: Apparently, Beartype < 0.18.0 Didn't Bother Checking Those

...heh. So, funny story. Apparently, @beartype < 0.18.0 didn't bother type-checking the default values of optional parameters at early @beartype decoration time. Why even bother, right? Beartype < 0.18.0 trusted you against its better judgement. Beartype < 0.18.0 only type-checked the default values of unpassed optional parameters at late function call time; if you always passed optional parameters (or never even called functions that accept optional parameters), @beartype < 0.18.0 never type-checked their defaults. This is why your office luncheons always order take-out that tastes like plastic.

Beartype 0.18.0 conveniently overlooks the abject failings of the distant past by embracing a new normal that you always thought was happening. Now, it is. All default values are now type-checked at early @beartype decoration time – with one prominent exception we're about to get to.

Behold! Type-check defaults at decoration time or go home, @beartype 0.18.0:

from beartype import beartype

@beartype
def beartype_i_am_your_code_father(
    nooooooooooooo: int = 'Oh, you will be. You will be.') -> None: ...

Despite the offending (and clearly offensive) beartype_i_am_your_code_father() function not being called, the @beartype decorator now raises the expected type-checking violation at decoration time:

beartype.roar.BeartypeDecorHintParamDefaultViolation: Function
__main__.beartype_i_am_your_code_father() parameter "nooooooooooooo"
default value 'Oh, you will be. You will be.' violates type hint
<class 'int'>, as str 'Oh, you will be. You will be.' not instance of int.

Above, we wrote that:

All default values are now type-checked at early @beartype decoration time – with one prominent exception we're about to get to.

What "prominent exception," @beartype? What bald-faced lies are you trying to sell us now, @beartype?!

The prominent exception is forward references. When the type hint annotating an optional parameter contains one or more unresolvable forward references (i.e., references to types that have yet to be defined), the @beartype decorator just issues a non-fatal warning rather than raising a fatal exception. After all, there might be a real problem there – but there might also not be a real problem there. @beartype can't tell, because the type is undefined. So, @beartype just notifies you...

Read more

Beartype 0.17.2: Boring Patch Release Is Boring

14 Feb 06:47
Compare
Choose a tag to compare

Beartype 0.17.2 nervously skitters about on thin ice. Cracks form, yet beartype 0.17.2 fails to return to shore. "What are you even doing!?", the crowd exclaims. Verily, it is best not to ask questions:

pip install --upgrade beartype

This patch release comes courtesy these proud GitHub Sponsors, without whom @leycec's cats would currently be eating grasshoppers:

Thanks so much, masters of fintech.

This Release Kinda Sucks, Huh?

Alright, alright. You found us out already.

Beartype 0.17.2 is an extremely minor patch release that exists purely to relax the bad assumption that all Python 3.9 releases unconditionally define the standard typing.ForwardRef.__forward_module__ dunder attribute, resolving issue #324 kindly submitted by stone-cold typonista @jvesely (Jan Vesely). Although Python ≥ 3.9.18 definitively defines this attribute, an unknown range of older Python 3.9 patch releases fail to do so.

Beartype 0.17.2 resolves this by naively pretending that all Python 3.9 releases fail to do so. Although kinda non-ideal, it's unclear whether this attribute is even used (i.e., set to a string) under Python 3.9. In fact, it's unclear whether this attribute is even used anywhere, ever. It probably will be under Python ≥ 3.13, but that's putting the proverbial cart before the horse. Anyyyyyyway.

We now return to your regularly scheduled Python hackathon.

Beartype 0.17.1: Bully Maguire Bullies Bugs

10 Feb 07:06
Compare
Choose a tag to compare

Beartype 0.17.1 gently descends from the heavens on a golden dragon made of rainbows. "How can this be!?", the crowd exclaims. Verily, it is best not to ask questions:

pip install --upgrade beartype

This patch release comes courtesy these proud GitHub Sponsors, without whom @leycec's cats would currently be eating grasshoppers:

Thanks so much, masters of fintech.

Who Let the Bugs Out?

This patch release adds explicit support for typing.NamedTuple subclasses under PEP 563 (i.e., from __future__ import annotations), resolving issue #318 kindly submitted by the cosmically rare-earth GitHub element @kasium. For unknown reasons (which probably reduce to "Guido was tired that day."), the typing.NamedTuple superclass exhibits high strangeness.

Specifically, for each typing.NamedTuple subclass named {MuhTuple}, the typing.NamedTuple superclass dynamically generates a {MuhTuple}.__new__() dunder method whose:

  • __annotations__ dunder attribute wraps all stringified type hints inside typing.ForwardRef(...) objects. Why? No reason.
  • __module__ dunder attribute claims that method was defined in a fake module named named_{MuhTuple}. Why? Nobody knows.

For example:

from __future__ import annotations  # <-- PEP 563: it makes kittens cry
import typing

# When you said this...
class MuhTuple(typing.NamedTuple):  # <-- very reasonable
    muh_field: int                  # <-- makes sense, huh?

# ...what "typing.NamedTuple" heard you say was this:
class MuhTuple(typing.NamedTuple):
    def __new__(cls, muh_field: ForwardRef('int')) -> None:  # <-- wut
        self.muh_field = muh_field
MuhTuple.__new__.__module__ = 'named_MuhTuple'  # <-- lolbro

Why does typing.NamedTuple do these sad things? Because it is crazy. This is the official answer. Cray classes gonna cray.

@beartype now responds with a mountain of code that took us two weeks. Was that worth it? Probably not. Probably should have just implemented deep type-checking already. Instead, this is all we got.

Mo Money Means Mo Code

@beartype 0.17.0 advised everybody to donate money to charitable causes. Instead, everybody donated more money to @beartype. Reverse psychology surely is the path of righteousness.

These monocled code aristocrats graciously filled the money trough, which the cats are now sleeping on against our wishes:

  • @DylanModesitt. @beartype now proudly markets you and everything you do. We're Team @DylanModesitt over here. Also, your GitHub Avatar is the boss. Feast your eyes, everybody!

    big boss dylan modesitt
    the eyes follow my fingers as i type my password

  • @zhiyuanshi. Thanks to you, I have money. More importantly, I now know about spacemacs: Emacs + Vim key bindings. Urge... to... switch... IDEs... rising. My danger sense is tingling.

Lastly, @beartype thanks Bully Maguire for saving New York City with sassy hair, emo eye shadow, and impromptu cafe street dancing.


@beartype make a man feel like this, sometimes

Beartype 0.17.0: Ultrabear vs. Mecha-Bugbear

25 Jan 08:06
Compare
Choose a tag to compare

Team Tokyo Bear presents... Ultrabear vs. Mecha-Bugbear, the titanic struggle of ultimate opposites. On the left, @beartype 0.17.0 in the hybrid static-runtime type-checking corner. On the right, the voracious bugs proliferating throughout your codebase in adorable collectable card format.

vs.
a @leycec in the paw is worth two in the mouth of mecha bear

There can be only one victor in your git log.

Wait. What's Happening Here?

@beartype 0.17.0 is a-go-go:

pip install --upgrade beartype

@beartype 0.17.0 descends like Ultraman King german-suplexing Absolute Tartarus onto Tokyo Tower for only like the fifth time. How many times can society rebuild Tokyo Tower before learning to accept that that thing's just a Kaiju magnet for dark monster forces from a mirror pocket universe? Some buildings are better left un-built.

Wait. What were we debating again? Incoherent monologues about Ultraman power levels can only mean one thing:


when you're straddling a giant fish head in the canadian rockies and conehead sumo baby just wanna play

But first...

A Round of Applause for the Homies

We give thanks. I'm humbly and hugely grateful to everyone who's ever financially supported @beartype via GitHub Sponsors. I'm especially grateful to our generous lifetime donors who almost gave a kidney for @beartype. These are @beartype's Three Biggest Fat Bear-cats:

  • @langfield, may their beatific username go down in online fame. May the poets (so, hip hop artists) sing their virtues before a rapt audience of Bay Area techno-futurologists and ChatGPT-embodied automatons. @langfield generously donated more to @beartype than I thought human(e)ly possible. The worst part is that I never gave @langfield what they wanted: deep type-checking. 2024 is the year that @beartype makes good on its promises to @langfield.
  • @patrick-kidger, the extreme scuba-diving Google X globetrotter and likely Thunderball remake stunt double who quietly nominated @beartype for a Google Open Source Peer Bonus award. Shock twist: @beartype won. This is why I now rep @patrick-kidger merch. jaxtyping support? We do that. Equinox support? That too. If it's a @patrick-kidger byproduct, @beartype probably now hawks it on Etsy.
  • @KyleKing, one of @beartype's longest-running GitHub sponsors. He wore glorious glasses that sparkle with the fury of a thousand suns. He's also helped immensely over the years – both financially and across our issue tracker. May @KyleKing achieve his dreams of delivering AI-fuelled nanobots directly into the bloodstreams of millions of Americans in a well-regulated legislative environment that guarantees safety through the power of federal bureaucracy. Hideo Kojima knows where that road goes... and it goes somewhere awesome.

@beartype supporters fight for you. Their username is legend.


@langfield is... Some Dude in a Skintight Rubber Suite.
also featuring @patrick-kidger (left) and @KyleKing (right)
also featuring all your codebase bugs (kaiju gettin rocked)

pytest-beartype: It's a Steaming Hot Thing, Now

Devtools superstar Tushar Sadhwani (@tusharsadhwani) saves everyone's QA bacon with pytest-beartype, @beartype's newest official package. If you always wanted to test-drive @beartype but were too afraid to risk becoming homeless when the whole thing backfired on your last working production server, let pytest-beartype confine @beartype to just your pytest-based test suite. Who cares if pytest burns down, am I right? Anyone?

Let's begin:

  1. Install this steaming hot thing:

    pip install --upgrade beartype
  2. Configure this still-steaming hot thing before it goes lukewarm. You have two choices here, depending on whether you prefer passing temporary command-line options or writing permanent configuration files:

    • Pass the new --beartype-packages='{package_name1},...{{package_nameN}' command-line option to the pytest command, where --beartype-packages is a comma-delimited list of all package names to be infested polluted sullied throttled type-checked by @beartype:

      pytest --beartype-packages='final_doom,u_wut_mate,strawberry.pancakes'  # <-- feels surprisingly good
    • Modify your existing top-level pyproject.toml configuration file with a new [tool.pytest.ini_options] section resembling:

      # In your "pyproject.toml" file...
      [tool.pytest.ini_options]
      beartype_packages = 'final_doom,u_wut_mate,strawberry.pancakes'  # <-- just. do. it.

For those who love CLI warrioring but hate POSIX-compliant shell syntax, bash, u make me hurt inside also check out @tusharsadhwani's zxpy: a Python + bash mashup that basically throws out the entirety of bash. Okay. So, it's more a beatdown than a mashup, really. Bash that bash up, Python!


pytest-beartype surveys all it has done. conclusion: "this is fine"

Beartype: Phase I: Roman Numerals Means Things Just Got Serious

@beartype 0.17.0 hallmarks the end of Beartype: Phase I. The central theme here was shallow type-checking (i.e., type-checking that objects are of the expected types without recursively type-checking any items contained in those objects).

Let's recap in slow-mo. Like that inevitable filler ep where your favourite TV show reboots itself after a five-year gap with all new child actors and a reprehensible script seemingly authored by lizzid people, @beartype wasn't always this good decent acceptable.

@beartype once raised exceptions when confronted with complex, non-standard, or otherwise disreputable type hints. Now, with @beartype 0.17.0, @beartype either passively accepts literally anything you can throw at it by doing nothing or generates shallow or deep type-checking code validating that thing. @beartype no longer explodes. Instead, @beartype permissively tolerates a QA-breaking world full of strife and typing monstrosities it can never fully comprehend.

@beartype is now a Jack-of-All-QA-Trades. @beartype didn't know jack before. Now, @beartype know jack.


@beartype 0.17.0: "Extruded alien protein chunks in my dinner?"

Beartype: Phase II: Roman Numerals Embiggen

@beartype 0.17.0 also hallmarks the beginning of Beartype: Phase II. The central theme here is deep type-checking (i.e., type-checking both that objects are of the expected types and recursively type-checking some or all items contained in those objects). Now that @beartype shallowly type-checks almost everything, it's time to dive into the deep end. Over the course of 2024, @beartype will gradually roll out:

  • Deep type-checking of all type hints in O(1) constant time.
  • Deep type-checking of some type hints in O(n) constant time. When we do this, we'll couple this to an actual deadline scheduler preventing @beartype from consuming more than some preconfigured ratio of wall-clock time.

You may now be thinking:

"But does @beartype 0.17.0 actually do anything?"

...heh. Let's begin.


@beartype 0.17.0: "Mutated alien alligators ain't no thang."

Beartype 0.17.0: The Interquel We All Deserve

@beartype 0.17.0 massively increases the configurability of @beartype. Because everybody always wanted to:

  • Emit non-fatal warnings on type-checking violations? Yup. We got that. Grep violation_*type, then win.
  • Raise custom exception types on type-checking violations? We got that, too. violation_*type grepping intensifies.
  • Raise custom exception messages on type-checking violations? Got that. __instancecheck_str() enters the chat emboldened and swaggering.
  • Modify the verbosity of type-checking violation messages? Got that. violation_verbosity + BeartypeVerbosity is snickering in the back.
  • Reduce complex type hints to simple type aliases in type-checking violations? That is a thing now. type {name} = {hard_stuff} | {moar_stuff}.
  • Blatantly lie about the types your API expects by instructing @beartype to internally transform source to target type hints matching various patterns with type hint overrides? You know we even got that. hint_overrides + BeartypeHintOverrides. It's best not to question this stuff.

These improvements were made possible only by the code-bending thaumaturgy of Montreal API snow wizard @felixchenier (Félix Chénier), who exhaustedly pushed numerous pull requests (PRs) across the git finish line. @beartype is now something actually usable by living humans that breathe oxygen. As a token of our gratitude, please accept this animated Ultraman GIF.


@felixchenier (right) threatens bugs (offscreen) as @leycec (left) supports

To exhibit the fearsome level-up that is @beartype 0.17.0, we now present...

The Flux Beartyper

Like everyone, I used to h...

Read more

Beartype 0.16.4

21 Oct 04:52
Compare
Choose a tag to compare

This patch release resolves all the bad things that have quietly gone unnoticed by both man and Maine Coon alike... until now. Fellow Ontarian and ML superstar @MaximilienLC (Maximilien Le Cleï) seriously, what is up with that "ï" quietly called our attention to a bevy (pretty sure that means "alot") of outstanding badness riddling the @beartype codebase.

This patch release resolves that badness. This means:

  • beartype.claw + methods + PEP 526. Previously, beartype.claw silently failed to type-check PEP 526-compliant annotated variable assignments in methods. Now, beartype.claw does so: e.g.,

    # In "{your_sagacious_package}.__init__":
    from beartype import beartype_this_package
    beartype_this_package()
    
    # In "{your_sagacious_package}...{your_bodacious_module}":
    class SoMuchClass(object):
        def so_much_method(self) -> None:
            # "beartype.claw" now raises an exception on this violation. Yah!
            so_much_local: int = 'You no longer fool @beartype, local."
    
            # "beartype.claw" also raises an exception on this violation. Go!
            self.so_much_var: int = 'You too are known to @beartype, variable."
  • @beartype 0.16.3 inheritance regression. @beartype's prior stable release (i.e., @beartype 0.16.3) introduced a critical regression with respect to inheritance and type-checking. Notably, the @beartype decorator silently failed to type-check subclass methods overriding superclass methods under @beartype 0.16.3. Now, it does. I implore you all to believe that this never happened... Believe!

Much thanks to @MaximilienLC for his all-seeing eye, which sees all @beartype's typing failures as plainly as I see the blinding glare off my bald and malding head. (Pretty itsy-bitsy nitty-gritty, innit?)