Skip to content

Commit

Permalink
**Beartype 0.17.0:** Ultrabear vs. Mecha-Bugbear
Browse files Browse the repository at this point in the history
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.

![](https://wikizilla.org/w/images/0/04/Cyber-Bear.png?20170106001251)
**vs.**
![](https://static.wikia.nocookie.net/lil-alchemist/images/2/26/Mecha_Bear.png/revision/latest?cb=20150531014124)
<sup>a @leycec in the paw is worth two in the mouth of mecha bear</sup>

There can be only one victor in your `git` log.

## Wait. What's Happening Here?

**@beartype 0.17.0** is a-go-go:

```bash
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:

![](https://media1.tenor.com/m/f8tqq33LZ34AAAAC/ultraman-fight.gif)
<sup>when you're straddling a giant fish head in the canadian rockies
and conehead sumo baby just wanna play</sup>

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](https://github.com/sponsors/leycec). I'm especially grateful
to our generous lifetime donors who almost gave a kidney for @beartype.
These are @beartype's Three Biggest Fat 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**](https://opensource.google/documentation/reference/growing/peer-bonus).
  Shock twist: @beartype won. This is why I now rep @patrick-kidger
  merch. [`jaxtyping`](https://github.com/google/jaxtyping) support? We
  do that. [Equinox](https://github.com/patrick-kidger/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.

![](https://media1.tenor.com/m/bCPUaLNx5E0AAAAC/ultra-galaxy-fight-the-destined-crossroad-ultra-galaxy-fight.gif)
<sup>@langfield is... *Some Dude in a Skintight Rubber Suite.*</sup>
<sup>also featuring @patrick-kidger (left) and @KyleKing (right)</sup>
<sup>also featuring all your codebase bugs (kaiju gettin rocked)</sup>

## `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:

   ```bash
   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:

     ```bash
     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:

     ```toml
     # 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,
<sup>`bash`, u make me hurt inside</sup> also check out
@tusharsadhwani's [`zxpy`](https://github.com/tusharsadhwani/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!

![](https://media1.tenor.com/m/dBCaK76vhpkAAAAd/tokusatsu-ultraman.gif)
<sup>`pytest-beartype` surveys all it has done. conclusion: "this is
fine"</sup>

## 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.

![](https://media1.tenor.com/m/BozVxUTt3ZwAAAAd/storium-beam-storium.gif)
<sup>@beartype 0.17.0: "Extruded alien protein chunks in *my* dinner?"</sup>

## 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.

![](https://media1.tenor.com/m/4AuZaaGLYAIAAAAC/ultraman-alligator.gif)
<sup>@beartype 0.17.0: "Mutated alien alligators ain't no thang."</sup>

## 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.

![](https://media1.tenor.com/m/zDq3QV45LB8AAAAd/ultra-galaxy-fight-the-destined-crossroad-ultraman.gif)
<sup>@felixchenier (right) threatens bugs (offscreen) as @leycec (left) supports</sup>

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

## The Flux Beartyper

Like everyone, I used to hate [the universal
`beartype.claw.beartype_all()` import
hook](https://beartype.readthedocs.io/en/latest/api_claw/#beartype.claw.beartype_all)
up until five minutes ago. By default, `beartype.claw.beartype_all()`
dangerously raises fatal exceptions on type-checking violations that
occur *anywhere* in your full app stack – including in code you do not
own, have no control over, and mostly could care less about. But what if
you could configure `beartype.claw.beartype_all()` to instead emit
**non-fatal warnings** rather than destroy your entire app due to
somebody else's sins?

Thankfully, it happened. I slipped off a toilet while hanging a clock
shaped like a hibernating bear, banged my head on a towel rack shaped
like a spawning salmon, and... *I saw it there.* The **Flux Beartyper**:

```python
# In your "{your_package}.__init__":
from beartype import BeartypeConf
from beartype.claw import beartype_this_package, beartype_all

beartype_this_package()  # <-------------------------------------- raise exceptions for your package
beartype_all(conf=BeartypeConf(violation_type=UserWarning))  # <-- emit warnings for everyone else's
```

That's it. That's the Flux Beartyper. This K-k-k-killer Combo compels
@beartype to:

* **Enforce** type hints across the **current package** by raising fatal
  exceptions on type-checking violations in this package.
* **Complain** about (but do *not* enforce) type hints across all
  **other packages** and the standard library itself by emitting
  non-fatal warnings on type-checking violations in those packages.

The Flux Beartyper is thus the superset of mypy and `pyright`: it does
everything those guys do (complain about everything), while also doing
something those guys can never do (actually enforce something).
Moreover, it selectively enforces those things only on the one thing you
have under your total control: your own codebase.

![](https://media1.tenor.com/m/7p_BMVaF41QAAAAC/ultra-galaxy-fight-the-destined-crossroad-ugf-tdc.gif)
<sup>in the endless struggle of bad versus good code, only roundhouse
chops to the scaled carapace will decide the fate of your investment
portfolio</sup>

## `BeartypeConf` Explodes with Greasy New Possibilities

@beartype configurations just got a whole lot embiggened. Since the
lesson of my childhood is that bigger is always better, I feel happy
about this startling explosion of unmaintainable technical debt and
bewildering code complexity.

![](https://media1.tenor.com/m/7ZsiupwO3CEAAAAd/ultraman-kamen-rider.gif)
<sup>is that what our lives have come to</sup>

### `violation_*type`: When You Know Better, You Better Tell @beartype

By default, @beartype raises thoughtful but eyebrow-raising
type-checking violations with exception types like
`beartype.roar.BeartypeCallHintParamViolation` and
`beartype.roar.BeartypeCallHintReturnViolation`. Fine-grained
granularity. That's just great... *isn't it?*

But what if you hate that? What if you love coarse-grained generality
instead? What if you really just want @beartype to raise `TypeError`
exceptions on type-checking violations like everything else in the
bloody runtime type-checking community already? Previously, those users
had to grit their teeth until grinding their molars down into stubs. You
know, what does "grit teeth" even mean? Why can you grit teeth but not
anything else? I've always wanted to grit my toes. Can't do it. Grit my
lips? It's right out.

For those who are about to grit their keyboards, @beartype 0.17.0
introduces a new secret brotherhood of `BeartypeConf` options governing
the types of violations it produces:

* **(Recommended)** `violation_type`, the default type of exception
  raised by @beartype when a type-checking violation occurs – *any*
  type-checking violation, including:
  * When an object passed to `die_if_unbearable()` violates a
    type-check.
  * When a parameter of a `@beartype`-decorated callable violates a
    type-check.
  * When a return of a `@beartype`-decorated callable violates a
    type-check.

Most users who want to configure violations want to pass this option.
Defaults to `None`, in which case @beartype preserves backward
compatibility by just doing what it currently does – which is perfectly
fine, of course. No shade on @beartype defaults. Obsessive-compulsives
such as myself may also enjoy fine-tuning:

* `violation_door_type`, the type of exception raised by @beartype when
  an object passed to `die_if_unbearable()` violates the passed type
  hint. Since @beartype type-checks PEP 526-compliant **annotated
  variable assignments** (e.g., `godzilla: Sequence[KaijuThatHateTokyo]
  = Gojira('RAAAR!')`) by internally calling `die_if_unbearable()`, this
  is also the type of exception raised when an annotated variable
  violates its type hint. Defaults to
  `beartype.roar.BeartypeDoorHintViolation`.
* `violation_param_type`, the type of exception raised by @beartype when
  a parameter violates its type hint. Defaults to
  `beartype.roar.BeartypeCallHintParamViolation`.
* `violation_return_type`, the type of exception raised by @beartype
  when a return violates its type hint. Defaults to
  `beartype.roar.BeartypeCallHintReturnViolation`.

`violation_type` is merely a convenience enabling users to trivially
control the ``violation_door_type``, ``violation_param_type``, and
``violation_return_type`` parameters *without* having to explicitly pass
all three of those parameters.

Pretend that @beartype is normal. It feels good and @beartype can no
longer complain:

```python
from beartype import BeartypeConf
from beartype.claw import beartype_this_package

# My spirit guide says that normalcy is a state of mind. Yet, you disagree.
beartype_this_package(conf=BeartypeConf(
    violation_type=AttributeError,     # <-- actually, never pass "AttributeError"
    violation_door_type=RuntimeError,  # <-- ..................or "RuntimeError"
    violation_param_type=TypeError,    # <-- Okay. Fine. This is okay.
    violation_return_type=ValueError,  # <-- passing "ValueError": not a great idea
))
```

![](https://media1.tenor.com/m/7UHSHSVKAYsAAAAC/ultra-galaxy-fight-the-destined-crossroad-ugf-tdc.gif)
<sup>does that dude in the back have drills for arms? really? so
coll</sup>

### `violation_*type`: When Exceptions Are Too Scary for the Slumber Party

Warnings are exceptions in Python. I know, right? Who knew. All these
years. The builtin `Warning` class subclasses the builtin `Exception`
class. Oddly, this implies that warnings are technically raisable as
exceptions. They are, but you shouldn't. Warnings should only be emitted
with `warnings.warn()`.

You know that – *but does @beartype*? Does @beartype acknowledge this
distinction? Imagine me now saying: "Nope. @beartype sucks. It just
raises warnings like exceptions." That... would be a pretty bad look.
Even Ultrabear would frown. That is why I am now instead saying the
opposite.

@beartype rules! When you pass a `Warning` subclass as a
`violation_*type` option, @beartype detects that as your attempt to emit
non-fatal warnings from type-checking violations and then does so by
dynamically generating type-checking code that calls `warnings.warn()`
rather than `raise`.

Is there a real-world application? There are so many I cannot count them
all on my vestigial drill hands. Pretending that @beartype is mypy is
one. This is another: **gradual adoption.**

Imagine a monolithic codebase named `FuglyBugs` that hates you. That
codebase is a sprawling million-line ghetto of badly typed spaghetti
whose most inventive feature is single-letter attribute names in the
[Unicode Tertiary Ideographic
Plane](https://en.wikipedia.org/wiki/Plane_(Unicode)#Tertiary_Ideographic_Plane).
You're the new guy next to the gurgling water cooler that leaks
suspicious fluid all over the floor according to a Poisson distribution
with a high λ. It's do or die. The garbage is piling up in the corridor.
Your grizzled landlady is hissing about "overdue rent" or something. Who
cares, landlady? But the cats are hissing as well. You can't throw
@beartype directly at that codebase without destroying your nascent life
story. So what a somber devops goin' do?

You gradually adopt a QA bear cub today, the @beartype way:

```python
# In your "your_package.__init__" submodule:
from beartype import BeartypeConf
from beartype.claw import beartype_this_package

# Emit non-fatal warnings on type-checking violations from your own package.
# The monolithic codebase that you preserve might just be named `FuglyBugs`.
beartype_this_package(conf=BeartypeConf(violation_type=UserWarning))
```

Of course, you can pass an app-specific `UserWarning` subclass rather
than `UserWarning`. And... *you should probably do that.*

![](https://media1.tenor.com/m/Nx_ehaoUlNQAAAAC/ultra-galaxy-fight-the-destined-crossroad-ultra-galaxy-fight.gif)
<sup>`FuglyBugs`! spit it! who did this 2 u!?</sup>

## `violation_verbosity` + `BeartypeVerbosity`: Massage Your Brain with Beartype

Let us breathe out and then back in and then... actually please keep
doing that. Let it never be said that @beartype gives bad advice.
*Wait.* What is this, a yoga class in our release notes? What were we
talking about again? Which is an appropriate lead-in to...

**Verbosity.** Prior versions of @beartype were verbose (like this
changelog). Type-checking violation messages included the full contents
of the current beartype configuration, which now contains an infinite
"wealth" of options.

@beartype 0.17.0 curtails that insanity by dialing down on the prolix
nebulosity. Beartype configurations are no longer embedded in violations
by default, because your sanity is our personal responsibility. Somebody
hates this change and is now thinking: "But I *like* the old way. I like
parking tickets, too."

@beartype 0.17.0 is here for that somebody, introducing a new
`violation_verbosity` option that governs violation verbosity. The value
of this option is one of the following members of our new
`beartype.BeartypeVerbosity` integer enumeration:

* `BeartypeViolationVerbosity.MINIMUM`, intended for end users
  potentially lacking core expertise in Python. Babies, in other words.
  This is for babies.
* `BeartypeViolationVerbosity.DEFAULT`, intended for a general developer
  audience assumed to be fluent in Python but vengeful on GitHub.
  *tentatively raises hand*
* `BeartypeViolationVerbosity.MAXIMUM`, extending the default verbosity
  with additional metadata intended for inadvisable all-nighter
  debugging sessions that end in shaking, weeping, and puffy cheeks.
  This includes:
  * A partial diff of the beartype configuration under which this
    violation occurred. By "partial diff," I mean only the subset of
    configuration options explicitly set by you that differ from their
    default values.  Previously, violations unnecessarily described
    *all* options -- even those *not* explicitly set by you that
    defaulted to their default values. Awful.

`violation_verbosity` defaults to `BeartypeViolationVerbosity.DEFAULT`,
because your brain is a precious quantity. But you know better.

```python
# In your "{your_package}.__init__":
from beartype import BeartypeConf, BeartypeVerbosity
from beartype.claw import beartype_this_package

beartype_this_package(conf=BeartypeConf(
   violation_verbosity=BeartypeVerbosity.MAXIMAL))  # <-- vomitous output: *ON*
```

![](https://media1.tenor.com/m/jprsLrCg8eAAAAAd/yapool-ultraman.gif)
<sup>never trust a mechanized triceratops named Yapool is all I'm sayin'</sup>

## `hint_overrides` + `BeartypeHintOverrides`: Who You Gonna Believe?

Have you ever wanted to lie to your userbase, static type-checkers,
other runtime type-checkers, and document generators alike? *Now you
can.*

Let's back up. [PEP 484](https://peps.python.org/pep-0484) – the
standard named "Type Hints," so that's probably what it's about –
included this bizarre substandard <sup>*see wut i did there*</sup> named
the [implicit numeric
tower](https://peps.python.org/pep-0484/#the-numeric-tower). The idea
was simple, albeit horrible. Static type-checkers would just globally
replace all:

* `float` types in type hints with `float | int` unions.
* `complex` types in type hints with `complex | float | int` unions.

That's fine. When your significant other says that, it's absolutely
*not* fine. This is like that. Because globally replacing types in type
hints without user consent which then reduces numerical precision isn't
actually that cool. So, @beartype only conditionally supports the
implicit numeric tower. If you want us to do that, that's cool, but you
have to opt in by enabling `is_pep484_tower=True`.

So far, so good. But what about third-party scalars published by
packages like NumPy and SymPy? Third-party scalars don't subclass
builtin scalars (e.g., `numpy.int_` does *not* subclass `int`). But
real-world "tough guy" data science and machine learning mostly uses
third-party scalars rather than builtin scalars. The implicit numeric
tower is thus obsolete for most of us. Sadness overflows my pewter mug
shaped like a grizzly bear.

So... *what now,* PEP 484? Huh? Let @beartype 0.17.0 tell you what now.

@beartype 0.17.0 introduces yet another outrageous new `BeartypeConf`
option: `hint_overrides`, whose value is a
`beartype.BeartypeHintOverrides` instance mapping source to target type
hints. And... `BeartypeHintOverrides` is an in-house **immutable
dictionary type** (i.e., pure-Python @beartype-specific implementation
of a hypothetical `frozendict` builtin), enabling the memoized
`BeartypeConf` dataclass to accept dictionaries while preserving
caching. And... @beartype globally and recursively substitutes all type
hints that are keys of the `hint_overrides` dictionary with their
corresponding values. And... can this get any more complicated? The
answer is: "Yes." You feel very tired.

`hint_overrides` is a generalization of the implicit numeric tower. Like
the implicit numeric tower, you're lying to everybody. Unlike the
implicit numeric tower, your lies are no longer constrained to what PEP
484 fed you; you can now lie about everything. And you should! Lies are
healthy. "@beartype said so."

Crazily, Python has no official frozen dictionary type. @beartype had to
make up its own. I grunt meaningfully and then point back to the
chalkboard, which now resembles a Cthulhian nightmare of random
scribbling from beyond the realm of sleep.

Since `hint_overrides` generalizes the implicit numeric tower, you can
now explicitly express the implicit numeric tower by instead passing:

```python
# Tiresome machinery. Why won't you import yourself, already?
from beartype import BeartypeConf, BeartypeHintOverrides

# This new beartype configuration explicitly does the same thing as...
explicit_numeric_tower = BeartypeConf(hint_overrides=BeartypeHintOverrides({
    float: float | int,
    complex: complex | float | int,
})

# This old beartype configuration.
implicit_numeric_tower = BeartypeConf(is_pep484_tower=True)
```

B-b-but what if you want to actually do something useful? Specifically,
what if you want an API typed as matching only builtin scalars to also
transparently match third-party scalars? Behold! You weave a web of
tangled lies, but it all works out in the end. You boost your
end-of-life karmic score *alot* higher than all those beleaguered
champions who stoically fight for justice:

```python
# Even more machinery. Just import yourself, already!
import numbers
from beartype import BeartypeConf, BeartypeHintOverrides

# Beartowertype: the ultimate @beartype configuration for numerical analysis.
# If you can't count the statistical variance of your lies, neither can I.
beartowertype = BeartypeConf(hint_overrides=BeartypeHintOverrides({
    int: numbers.Integral,
    float: numbers.Real,
    complex: numbers.Complex,
})
```

Users don't understand what `numbers.Integral` means. But users *do*
understand what `int` means. Okay. Not all users. A majority of users.
Okay. Not even that. A few users understan... Okay. *You* understand
what `int` means.

Meanwhile, NumPy, SymPy, and everybody else understands what
`numbers.Integral` means. They register their own third-party scalars
with [PEP 3141-compliant abstract base classes (ABCs) defined by the
standard `numbers` module, also referred to as the "explicit numeric
tower"](https://docs.python.org/3/library/numbers.html).

By instructing @beartype to internally replace all builtin scalar types
like `int` with corresponding ABCs in the explicit numeric tower like
`numbers.Integral`, you have made your own Ultimate Implicit Numeric
Tower: an implicit numeric tower that actually works, because it
actually supports stuff you care about. Because you know best. You do
you. Now, @beartype does too. <sup>*wait, what does that one-liner
actually mean*</sup>

![](https://media1.tenor.com/m/6FUnSuzn_g8AAAAC/ultraman-fight.gif)
<sup>caring means punching a monster in the gut for humanity</sup>

## Beartype Presents... The Félix Chénier Connection

Let's put all of the above together. Courtesy Félix Chénier, the
Université du Québec à Montréal du Canada du Planet Earth du Milky Way
Spiral Galaxy du Material Universe mad lad that made all this possible,
@beartype presents the Big and Tall @beartype configuration:

```python
# In your "{your_package}.__init__":
from beartype import BeartypeConf, BeartypeHintOverrides, BeartypeVerbosity
from beartype.claw import beartype_this_package, beartype_all

beartype_this_package(conf=BeartypeConf(  # <-- This. Is. His. Way.
    violation_type=TypeError,  # <-- what is @beartype to you, a joke?
    violation_verbosity=BeartypeVerbosity.MINIMAL,  # <-- SILENCE, HUMANS!
    hint_overrides=BeartypeHintOverrides({  # <-- NumPy + SymPy = ancient power
        int: numbers.Integral,
        float: numbers.Real,
        complex: numbers.Complex,
    }),
))
beartype_all(conf=BeartypeConf(
    violation_type=UserWarning,  # <-- unexpected Flux Beartyper returns
))
```

Configure @beartype like Félix Chénier would. The feeling of power is
delicious, yet kinda indescribable.

![](https://media1.tenor.com/m/ouHrvz7L1GMAAAAC/ultraman-trigger-new-generation-tiga-ultraman-trigger.gif)
<sup>so this is what feels like when monsters cry</sup>

## Violation Readability: The Tesseract Unfolds

@beartype once raised hair-raising type-checking violations with
messages straight outta the Seventh Circle of Typing Hell. Wince and
cringe as your third eye bleeds from its calcified perch in the pineal
gland!

```python
beartype.roar.BeartypeCallHintParamViolation: @beartyped __main__.f() parameter
x="Array(1, dtype=int32, weak_type=True)" violates type hint <class
'jaxtyping.Float[Array, 'dim1']'>, as <protocol "jaxlib.xla_extension.ArrayImpl">
"Array(1, dtype=int32, weak_type=True)" not instance of <class
"jaxtyping.Float[Array, 'dim1']">.
```

Indeed, the dawn of `typing` prehistory was a dark time. Those days are
long behind us, though. @beartype 0.17.0 now delivers two new extensible
APIs for generating readable messages designed by you, consumed by your
userbase, and complained about relentlessly on your issue tracker.
@beartype is no longer responsible for anything! I'm weeping with joy
here.

![](https://media1.tenor.com/m/eHOAajTpCuAAAAAC/ultra-seven-kaiju.gif)
<sup>@beartype: just some rando in a skin-tight rubber suit after all</sup>

### `__instancecheck_str__()`: Just Do It Yourself, Because Our Way Sucked

@beartype 0.17.0's unleashes our first official plugin API: the
**`__instancecheck_str__()` protocol**, a new double underscore method
accepting a single object that violates the current class and returning
a human-readable substring describing that violation.
`__instancecheck_str__()` intentionally shares a similar name with the
standard `__instancecheck__()` dunder method; both are defined on the
metaclass of a class. Whereas `__instancecheck__()` returns a `bool`,
however, `__instancecheck_str__()` returns a `str`. The full signature
resembles:

```python
    def __instancecheck_str__(cls, obj: Any) -> str:
```

This will soon make sense. Would I lie? This is your final API for
raising human-readable violations:

```python
from beartype import beartype

# Define __instancecheck_str__() on the metaclass.
class MetaclassOfMuhClass(type):
    def __instancecheck_str__(cls, obj: object) -> str:
        return (
            f'{repr(obj)} has disappointed {repr(cls)}... '
            f'for the last time.'
        )

# The actual class is the same as it always was. So boring.
class MuhClass(object, metaclass=MetaclassOfMuhClass):
    pass

# Use that class as a type hint everywhere.
@beartype
def muh_func(muh_obj: MuhClass) -> None:
    pass

# Cheers! You now have all the power while @beartype weeps in the corner.
muh_func("Some strings, you just can't reach.")
```

...which now raises the humane violation:

```python
beartype.roar.BeartypeCallHintParamViolation: Function __main__.muh_func()
parameter muh_obj="Some strings, you just can't reach." violates type hint
<class '__main__.MuhClass'>, as "Some strings, you just can't reach." has
disappointed <class '__main__.MuhClass'>... for the last time.
```

Simple, right? And it actually is. Caveats may apply. Notably, the
string you return from your `__instancecheck_str__()` implementation:

* Should be a sentence fragment whose first character is typically *not*
  capitalized.
* May optionally be suffixed by a trailing period. In either case,
  @beartype intelligently does the right thing and ensures that the
  entire violation message is *always* suffixed by only a single
  trailing period.

`__instancecheck_str__()` is intended to be supported by competing
runtime type-checkers (e.g., `typeguard`, Pydantic) as a
pseudo-standard. Naturally, ain't nobody got the time to write an actual
PEP for that. *Pseudo-standard.*

![](https://media1.tenor.com/m/dKl6k2I2geIAAAAC/ultraman-kaiju.gif)
<sup>just another day at the kaiju office ends on a terrifying footnote</sup>

### PEP 695: Only the Third Time Python Standardized Type Aliases

@beartype 0.17.0 now *sorta* supports [PEP 695-compliant **type
aliases**](https://peps.python.org/pep-0695/#generic-type-alias) (i.e.,
type hints with simple names whose values are *other* more complex type
hints, instantiated by statements of the form ``type {alias_name} =
{alias_value}`` under Python ≥ 3.12). Type aliases are useful for
improving the readability of type-checking violations. Type aliases are
also mostly broken by runtime CPython deficiencies. One out of two ain't
bad.

The `numpy.typing.ArrayLike` union is the canonical use case. Shield
your child's eyes from this abomination beyond from the Chaos Gate:

```python
# What could be simpler? <-- something nobody should ever say
>>> from numpy.typing import ArrayLike
>>> ArrayLike
typing.Union[
    collections.abc.Buffer,
    numpy._typing._array_like._SupportsArray[numpy.dtype[typing.Any]],
    numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[typing.Any]]],
    bool, int, float, complex, str, bytes,
    numpy._typing._nested_sequence._NestedSequence[
        typing.Union[bool, int, float, complex, str, bytes]]
]  # ...so. literally everything is array-like, huh? even bools, huh? *sigh*
```

Now imagine – in the vast, cavernous, and crawling darkness beyond your
eyelids – what happens when you annotate `@beartype`-decorated classes
and callables with `numpy.typing.ArrayLike`. Thankfully, you don't even
have to imagine:

```python
>>> from beartype import beartype
>>> from numpy.typing import ArrayLike
>>> @beartype
... def run_nurgle_run(like_an_array: ArrayLike) -> None: pass
>>> run_nurgle_run(('Blood for the Blood God!', 'Skulls for the Skull Throne!',))
beartype.roar.BeartypeCallHintParamViolation: Function __main__.run_nurgle_run()
parameter like_an_array=('Blood for the Blood God!', 'Skulls for the Skull
Throne!') violates type hint typing.Union[collections.abc.Buffer,
numpy._typing._array_like._SupportsArray[numpy.dtype[typing.Any]],
numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[typing.Any]]],
bool, int, float, complex, str, bytes,
numpy._typing._nested_sequence._NestedSequence[typing.Union[bool, int, float,
complex, str, bytes]]], as tuple ('Blood for the Blood God!', 'Skulls for the
Skull Throne!'):
* Not bool, float, str, <protocol ABC "collections.abc.Buffer">, complex, bytes, or int.
* Not instance of <protocol "numpy._typing._array_like._SupportsArray">.
* Not instance of <protocol "numpy._typing._nested_sequence._NestedSequence">.
* Not instance of <protocol "numpy._typing._nested_sequence._NestedSequence">.
```

Tell me that you don't understand what I'm saying without telling me
that you don't understand what I'm saying, @beartype.

Now consider this human-readable alternative that truncates the above
abnormal outgrowth of code logorrhea into something even Ultrabear's
mother could love:

```python
# Don't try this under Python < 3.12. Just... don't.
>>> from beartype import beartype
>>> from numpy.typing import ArrayLike as _ArrayLike
>>> type ArrayLike = _ArrayLike  # <-- tautological nonesense *or* 4d chess move?
>>> @beartype
... def run_nurgle_run(like_an_array: ArrayLike) -> None: pass
>>> run_nurgle_run(('Blood for the Blood God!', 'Skulls for the Skull Throne!',))
beartype.roar.BeartypeCallHintParamViolation: Function __main__.run_nurgle_run()
parameter like_an_array=('Blood for the Blood God!', 'Skulls for the Skull
Throne!') violates type hint ArrayLike, as tuple ('Blood for the Blood God!',
'Skulls for the Skull Throne!') not tuple ('Blood for the Blood God!', 'Skulls
for the Skull Throne!'):
* Not bool, float, str, <protocol ABC "collections.abc.Buffer">, complex, bytes, or int.
* Not instance of <protocol "numpy._typing._array_like._SupportsArray">.
* Not instance of <protocol "numpy._typing._nested_sequence._NestedSequence">.
* Not instance of <protocol "numpy._typing._nested_sequence._NestedSequence">.
```

Saner. Terser. Arguably, even readable. @beartype still explains the
violation *without* lore-dumping the squalid guts of
`numpy.typing.ArrayLike`, which is now abbreviated to simply
`ArrayLike`.

Caveats apply, because this is @beartype. Due to character flaws beyond
my control (*...video games is what I'm saying*), @beartype currently
only **partially supports** `type` aliases. Notably, @beartype:

* **Fully supports** type aliases containing neither forward references
  *nor* recursion. Bears cheer!

  ```python
  type ChooseYourEpicFate = str | int  # <-- this is fine
  ```

* **Conditionally supports** global type aliases (i.e., defined as
  global attributes at module scope) containing forward references but
  *not* recursion under the proviso that you *only* automatically apply
  @beartype via its `beartype.claw` import hooks. If you manually apply
  @beartype via the `@beartype.beartype` decorator, however, @beartype
  will raise exceptions on encountering *any* type aliases containing
  forward references. Why? Because PEP 695 is fundamentally broken and
  lies about everything. More bears half-heartedly cheering while crying
  at the same time.

  ```python
  type UnseenHorror = ClassOfDoom | ClassOf94  # <-- this is sorta fine...
                                               # <-- if you "beartype.claw";
                                               # <-- else, defly *NOT FINE*.
  ```

* **Cannot support** local type aliases (i.e., defined as local
  attributes in callables) containing forward references. Sadly, *no*
  subsequent @beartype release is expected to support this use case. For
  unknown reasons that would probably bore and anger all of us in equal
  measure, CPython's runtime implementation of local annotation scopes
  is fundamentally, irredeemably, and profoundly broken. Thus, bears
  cry.

  ```python
  def dry_your_tears_on_my_git_stash() -> None:
      type AyyLmao = LocalAreaMan | UniversalAreaGrey  # <-- *NOT FINE*
  ```
* **Does not support** type aliases containing recursion. Unlike the
  prior bullet point, @beartype can theoretically fully support this use
  case. It simply chooses not to at the moment, because it is very tired
  and must now lie down. A subsequent @beartype release is expected to
  fully support recursive type aliases. Unenthusiastic bears roll around
  on your front lawn.

  ```python
  type FurBaby = TerrorCat | DogBreath | list[FurBaby] # <-- *NOT FINE*... yet
  ```

You may now be thinking: "Uhh... how can @beartype support type aliases
containing forward references declared at global but *not* local scope?"
Actually, who am I even kidding? Nobody cares. The audience for `type`
aliases consists of two Capuchin monkeys that mostly just chortle as
they tickle one another and a microdosing banana. For them, allow my
disillusioned younger self to copy-paste himself from @beartype's `git
log`:

> The most problematic and troubling aspect of PEP 695 with respect to
> runtime type-checking is its horrifying, terrifying, and frankly
> shocking **lack of runtime support for forward references.** Although
> PEP 695 repeatedly mic-drops forward references as a central motivation
> for its existence, the actual runtime implementation of PEP 695 lacks
> any support whatsoever for forward references and even goes to elaborate
> and outrageous lengths to prevent runtime type-checkers from resolving
> forward references in PEP 695-compliant type aliases. Yet again, a new
> runtime-hostile PEP arises. Thankfully, this is @beartype. We do what we
> want here. And what we want here is to fully dismantle PEP 695, break
> it, and then bend it to our perfidious will until this Accursed
> Abomination Unto Nuggan does what it was advertised but failed to do at
> runtime. So says the Bear.

**Wait.** I can hear the Capuchin monkeys and microdosing banana
ruminating already: "If PEP 695 lacks runtime support for forward
references, then how does @beartype actually support global type aliases
containing forward references?" Thank you, banana-monkey. I'll take it
from here.

This is where `beartype.claw` import hooks come in. When you apply
import hooks, what you're *really* doing is applying abstract syntax
tree (AST) transformations that transmute your crippled-by-design
CPython code into an entirely new language of our own devising:
**pybearthon.** Pybearthon could mostly care less whether or not CPython
itself is broken, because pybearthon ~~walks~~ slithers its own way. In
this case, pybearthon silently transforms...

```python
# This otherwise broken global type alias...
type UnseenHorror = ClassOfDoom | ClassOf94

# ...into this suddenly worky global type alias!
from beartype._util.hint.pep.proposal.utilpep695 import (
    iter_hint_pep695_forwardref as __iter_hint_pep695_forwardref_beartype__)
type UnseenHorror = ClassOfDoom | ClassOf94
for _ in __iter_hint_pep695_forwardref_beartype__({alias_name}):
    globals()[_.__name_beartype__] = _  # <-- don't ask. srsly. just... don't.
```

Because PEP 695 is fundamentally broken, that same AST transformation
fails at local scope with insane exceptions like:

```python
NameError: cannot access free variable 'ClassOfDoom' where it is not associated
with a value in enclosing scope
```

Ergo, runtime type-checkers can only support *global* type aliases
containing forward references. You now regret your frank line of
questioning, banana-monkey.

An even worse caveat applies, however. Yet again, it's *not* @beartype's
fault. Python ≤ 3.11 hates `type` aliases. By "hates," I mean "Python ≤
3.11 raises non-human-readable `SyntaxError` exceptions at bytecode
generation time on attempting to import *any* module containing even a
single `type` alias regardless of where in that module that `type` alias
is." This is `True` hatred: a new plateau of hate-filled overkill
hitherto unknown to your handlebar mustache-twirling boss.

Even if you try to hide `type` aliases from older Python versions behind
`if` conditionals like `if sys.version_info >= (3, 12):`, your
circumlocution fails. Then, at last, you know @leycec to be an
insufferable oracle of horrible truth. Hiding doesn't work. You either
need to:

* Isolate *all* `type` aliases across your entire codebase to a unique
  submodule conditionally imported only under Python ≥ 3.12.
* Conditionally and dynamically declare `type` aliases with the `exec()`
  builtin hidden behind clever `if` conditionals like `if
  sys.version_info >= (3, 12):`. This is the lazy way. Thus, this is
  what we do below.

You are now thinking: "`type` aliases seriously suck, dude. Seriously."
Allow me to now dispel all your justifiable fears with edgelord code
that should make you cringe. I say, "Embrace the cringe." Let's
*goooooooooooooo*:

```python
# Pretend this means something to you.
from numpy.typing import ArrayLike as _ArrayLike
from sys import version_info
from typing import TYPE_CHECKING, NewType, TypeAlias

# If mypy or pyright, pacify mypy or pyright with... deprecated syntax!?!?
if TYPE_CHECKING:
    ArrayLike: TypeAlias = _ArrayLike
# Else, we are Python.
#
# If we are Python ≥ 3.12, dynamically declare a type alias to avoid
# "SyntaxError" complaints from older Python interpreters.
elif version_info >= (3, 12):
    exec('type ArrayLike = _ArrayLike')  # <-- stupidly clever or just stupid? you decide
# Else, we are obsolete Python. In this case, abuse PEP 484 for justice.
else:
    ArrayLike = NewType('ArrayLike', _ArrayLike)
```

So who is going to use `type` aliases if you can't use them under Python
≤ 3.11 without soul-destroying boilerplate *and* can only use them under
Python ≥ 3.12 subject to a litany of context-sensitive caveats that even
your family lawyer who routinely represents banana-monkeys can't get
right, exactly?

**Nobody.** The answer is nobody.

![](https://media1.tenor.com/m/8wrz4mj39UgAAAAd/ultraman-orb.gif)
<sup>that feeling when you realize you wasted ten minutes of your
life</sup>

## Unrecognized Subscripted Builtin Type Hint: Yeah, We Do That Too

A brief history in futility and the sound of one keyboard clapping.

A decade (but what feels like a lifetime) ago, CPython devs made the
ignominious decision to externalize *all* type hints for the standard
library into a third-party package inaccessible to runtime type-checkers
named [`typeshed`](https://github.com/python/typeshed). According to the
Python mailing list, "Accurate typing is hard!" I am now heaving my
emaciated arms up into the air. You already did the hard work in the
`typeshed`, CPython devs. Can't you literally copy-paste type hints from
the `typeshed` into the standard library? How hard is repeatedly hitting
two key chords on a keyboard? This isn't rocket science or even figuring
out how to bottle-feed a disgusting slurry of processed fish guts to a
vicious Bengal cat with a deplorable attitude stricken by Calicivirus.
*That* was rocket science. This is only disappointment.

To compound matters, CPython, `typeshed`, and `mypy` authors (whose Venn
diagram is a perfect circle) quietly collude to implement non-standard
type hints. The way this nefarious social network works is pretty
simple: <sup>it's absolutely not simple</sup>

1. `typeshed` devs intend to annotate something in the standard library
   for which no standard type hints exist.
1. CPython devs quietly augment an existing type to support subscription
   (i.e., the `__getitem__()` dunder method) *without* documenting
   anything or standardizing the semantic meaning of the resulting
   object.
1. `mypy` devs quietly interpret subscription of that type as a
   non-standard type hint in an obscure and undocumented `mypy`-specific
   manner.
1. `typeshed` devs annotate things in the standard library using those
   non-standard type hints in an obscure and undocumented
   `mypy`-specific manner.

I'm not bitter. I just look bitter. My face is permanently frozen into a
weatherbeaten rictus of crag lines, worry warts, and wrinkle canyons.

The point is that weird undocumented type hints internally used
throughout the CPython community now exist. Is that a problem for us?
Yes. Their avoidance of the PEP standards process makes this our
problem. The @beartype userbase has somehow become aware of and now
wants us to support these weird undocumented type hints – including:

* `weakref.weakref[...]` type hints. Pretty obvious what that
  semantically means, right? `weakref.weakref[str]` is a weak reference
  to a string, for example. Makes sense. But then what about...
* `os.PathLib[...]` type hints. "_uhh wat?_" Yeah. It's undocumented,
  but you can actually subscript the standard `os.PathLib` type by
  another type. The semantic interpretation is *not* at all obvious;
  since nothing is documented, I had to reverse engineer the semantic
  interpretation by grepping the `mypy` issue tracker for a hot minute.
  Surprisingly, this is what `os.PathLib[T]` means:

  ```python
  from typing import Generic, TypeVar, Union

  T = TypeVar('T', bound=Union[str, bytes])

  class PathLike(Generic[T]):
      def __fspath__(self) -> T: ...  # <-- hoh, boy
  ```

The point is that this sucks. Because this sucks, @beartype 0.17.0 now
shallowly type-checks *all* weird undocumented type hints internally
used throughout the CPython community by reducing those hints to their
**origin class** (i.e., by just stripping subscription from those
hints). For example, @beartype now reduces:

* *All* `weakref.weakref[T]` type hints to the `weakref.weakref` class.
* *All* `os.PathLib[T]` type hints to the `os.PathLib` class.

@beartype 0.17.0: we support bad stuff, because we support you. Wait...
That one-liner kinda didn't sound right. *You're* not bad stuff. You're
awesome sauce. But your awesome sauce needs bad stuff. Let's try this
[one more time](https://www.youtube.com/watch?v=FGBhQbmPwH8).

@beartype 0.17.0: all the bad stuff, now in one easy convenient package.

![](https://media1.tenor.com/m/0eMvsNw1S1cAAAAC/ultraman-trigger-new-generation-tiga-ultraman-trigger.gif)
<sup>only a flying water bottle on fire holds the key to planetary
salvation</sup>

## Isomorphic Non-closure Wrapper: Changelog from Hell Continues

*ohmygodswontthischangelogquitalready*

Apparently, this is fine now:

```python
from beartype import beartype
from functools import wraps

def muh_func(muh_arg: int):  # <-- wat!? no @beartype!? but how can this be?
    pass

@beartype  # <-- oh, okay. here's the @beartype. phew. that was close
@wraps(f)  # <-- standard decorator idiom
def muh_wrapper(*args, **kwargs):
    pass
```

When a changelog just needs to stop already, animated Ultraman GIF.

![](https://media1.tenor.com/m/k1wByAC3R74AAAAC/ultra-galaxy-fight-the-destined-crossroad-ultraman.gif)
<sup>Cobra Guy encourages at-risk codebases to try a bit harder</sup>

## @patrick-kidger: If He Didn't Type It, You Shouldn't Use It

Lastly, @beartype 0.17.0 officially:

* Supports @patrick-kidger's
  [Equinox](https://github.com/patrick-kidger/equinox) now. JAX + ML +
  @beartype = *pretty sure you just got a raise.*
* Does *not* support
  [`nptyping`](https://github.com/ramonhagenaars/nptyping), because
  **(A)** `nptyping` is dead and **(B)** `nptyping` is bad. Dead and bad
  are both bad. If you attempt to use `nptyping`-based type hints under
  @beartype ≥ 0.17.0, @beartype will **raise fatal exceptions**
  informing you that you are bad by association: e.g.,

  ```python
  beartype.roar.BeartypeDecorHintPep604Exception: Type hint
  NDArray[Shape['N, N'], Float] inconsistent with respect to repr()
  strings. Since @beartype requires consistency between type hints and
  repr() strings, this hint is unsupported by @beartype. Consider
  reporting this issue to the third-party developer implementing this
  hint: e.g.,
          >>> repr(NDArray[Shape['N, N'], Float])
          NDArray[Shape['N, N'], Float]  # <-- this is fine
          >>> repr(NDArray[Shape['N, N'], Float] | int)
          nptyping.ndarray.NDArray | int  # <-- *THIS IS REALLY SUPER BAD*

          # Ideally, that output should instead resemble:
          >>> repr(NDArray[Shape['N, N'], Float] | int)
          NDArray[Shape['N, N'], Float] | int  # <-- what @beartype wants!
  ```

What @beartype is saying is that **`nptyping` is currently unmaintained,
suffers over 20 severe issues, and emits 7 severe NumPy deprecation
warnings.** `nptyping` is a ticking time bomb about to explode your
codebase into radiating black bodies. Bear bros don't let bear bros
import `nptyping`. *Not even once.*

Thankfully, @patrick-kidger exists. <sup>hard to prove, but likely
true</sup> Everybody wants to transition from `nptyping` to
@patrick-kidger's [Google-adjacent `jaxtyping`
package](https://github.com/google/jaxtyping) already. Unlike
`nptyping`, `jaxtyping` provides well-maintained type hints covering
NumPy, JAX, PyTorch, and TensorFlow. It's kinda intense. It's also
@beartype's [official FAQ recommendation for type-checking NumPy
arrays](https://beartype.readthedocs.io/en/latest/faq/#numpy-arrays).

The data science pipeline you save might just be your own. It's probably
too late, though.

![](https://media1.tenor.com/m/q7TrSkO7jMQAAAAd/ultraman-1966.gif)
<sup>your codebase when you realize you used `nptyping` everywhere</sup>

## Biosecurity Tickets: No Longer Something I Grovel on the Floor For

Previously, I publicly begged for [GitHub
Sponsors](https://github.com/sponsors/leycec) with a flashy logo
believed to be reminiscent of sketchy underground raves – which, of
course, none of us know anything about or have ever attended.
<sup>*awkward collar tugging*</sup>

Instead, I now implore you to donate that same money to local charities,
food banks, animal shelters, homeless shelters, and every other
institution that does tangible real-world good. Humanity isn't doing so
h0t in 2024. We don't talk about that, because we're supposed to do fun
here. Coding is our wheelhouse.

But it's largely institutions – both corporate and governmental – that
probably should have supported open-source initiatives like @beartype.
That should never have fallen on the heavy shoulders of individuals. As
actual persons, our responsibilities are mostly to the local: local
lives, local families, and local communities.

I'm not closing my [GitHub
Sponsors](https://github.com/sponsors/leycec), because I put too much
work into that flashy logo and now I'm emotionally invested. But I am
beginning to moulder and stew in my brain sauces and think:

> "What next? How do we positively incentivize open-source volunteerism
> without disproportionately burdening the individuals that already bear
> up too much?"

I don't know. I'm just a gawping code monkey that loves Ultraman. But I
do know that the solution almost certainly involves gifting turn-based
strategy and role-playing and Yakuza videogames on Steam to @leycec.

![](https://media1.tenor.com/m/fvq9y6sTwmIAAAAd/ultra-galaxy-fight-the-destined-crossroad-ultraman.gif)
<sup>@beartype userbase: make a better world through glowing orbs</sup>

## To End a Changelog: Greets to the Greatest

Thanks so much, everybody. These bear bros went above and beyond the
mating call of Spring to deliver a better QA UX for us all:

@langfield, @patrick-kidger, @KyleKing, @felixchenier, @posita, @wesselb,
@justinchuby, @EtaoinWu, @kaparoo, @kasium, @peske, @tvdboom, @MaximilienLC,
@fleimgruber, @alexoshin, @AdrienPensart, @uriyasama, @sunildkumar,
@mentalisttraceur, and @skeggse, @reikdas, @mentalisttraceur, and
@tusharsadhwan – may your usernames reign supreme and then lord that supremacy
over all of us.

These GitHubbers hugged @beartype by starring it recently. Little did
they know, but they were inviting a disastrous chain of consequences
culminating in my now pinging them:

@Vol0kin, @alimoezzi, @phsilva, @shyamsn97, @antoniomdk, @procore, @hbakri,
@dcharatan, @motherwort, @jxu, @doraut, @joaoapel, @AntoineD, @double-thinker,
@tcl326, @Guiforge, @Valendrew, @jeffswt, @lxdlam, @padraic-shafer, @bzczb,
@xhiroga, @justincase-jp, @thapecroth, @ZachariahPang, @axrn, @mjwen, @calebj,
@Holocor, @anagri, @nhanarT, @dfundingsland, @DavidHernandez21, @namurphy,
@makaronma, @urimandujano, @damtien444, @deutschmn, @Fizzadar, @AnjieCheng,
@Bullish-Design, @ericfeunekes, @cameronraysmith, @sfrieds3, @garthk,
@LiamBrenner, @abecciu, and @moddyz – may @beartype 0.17.0 give you everything
you've always wanted except deep type-checking of dictionaries.

It's my birthday tomorrow. I will be eating cake covered in ice cream
and playing video games all day. Thank you. May @beartype bless your
codebase.

![](https://media1.tenor.com/m/t4NwisgU--kAAAAd/fake-ultraman-agul-smile.gif)
<sup>@beartype feels that feeling, too</sup>
  • Loading branch information
leycec committed Jan 25, 2024
1 parent e75565b commit 7d9051f
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 14 deletions.
22 changes: 13 additions & 9 deletions beartype/_check/forward/fwdmain.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@

# ....................{ RESOLVERS }....................
#FIXME: Unit test us up, please.
#FIXME: Docstring us up, please -- especially with respect to
#"BeartypeDecorHintForwardRefException" error conditions.
def resolve_hint(
# Mandatory parameters.
hint: str,
Expand Down Expand Up @@ -75,7 +73,7 @@ def resolve_hint(
exception message. Defaults to the empty string.
Returns
----------
-------
object
Either:
Expand All @@ -84,11 +82,16 @@ def resolve_hint(
* Else, this hint as is unmodified.
Raises
----------
------
exception_cls
If either:
...
If attempting to dynamically evaluate this stringified type hint into a
non-string type hint against both the global and local scopes of the
decorated callable raises an exception, typically due to this
stringified type hint being syntactically invalid.
BeartypeDecorHintPep604Exception
If the active Python interpreter is Python <= 3.9 and this stringified
type hint is a :pep:`604`-compliant new-style union, which requires
Python >= 3.10.
'''
assert isinstance(hint, str), f'{repr(hint)} not stringified type hint.'
assert isinstance(bear_call, BeartypeCall), (
Expand Down Expand Up @@ -583,8 +586,9 @@ def resolve_hint(
f'(i.e., {repr(exception)}).'
)

# If the beartype configuration associated with the decorated callable
# enabled debugging, append debug-specific metadata to this message.
# If the beartype configuration associated with the decorated
# callable enabled debugging, append debug-specific metadata to this
# message.
if bear_call.conf.is_debug:
exception_message += (
f' Composite global and local scope enclosing this hint:\n\n'
Expand Down
6 changes: 1 addition & 5 deletions doc/RELEASE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,7 @@ Beartype is releasable to all supported platforms as follows:
``{version}`` is the current value of the ``beartype.__version__`` global.
* Next line lists all GitHub Sponsors at the Papa Bear tier and higher.
**THIS IS CRITICALLY VITAL. DO _NOT_ NEGLECT THIS WONDERFUL USERBASE.** As
of now, relevant Sponsors include:

* [**ZeroGuard:** The Modern Threat Hunting
Platform](https://zeroguard.com).

of now, relevant Sponsors include... *nobody*, sadly! We've failed money.
* Remaining lines are a changelog synopsizing the significant changes
implemented by this release -- ideally in GitHub-flavoured Markdown (GHFM)
format, as depicted below. Note that this format requires enabling the
Expand Down

0 comments on commit 7d9051f

Please sign in to comment.