mrkeyoor.com_
Sun 20 Sept 11:46 UTC
PyPIUtilsupdated 20 Sept 2026

beartype review

beartype turns Python annotations into checks that run when your code runs. Put @beartype on a callable, enable a package through beartype.claw, or use beartype.door to test an arbitrary object against a hint. Its default container strategy samples an item instead of walking the whole collection, which keeps checks cheap but cannot prove that every member is valid. Version 0.22.9 adds official PyInstaller handling and limited compatibility work for Astral's ty checker. Our Python 3.12 import worked, and the distribution includes py.typed metadata.

Verdict

beartype 0.22.9 installed in 0.2 seconds as a single 6 MB package in our sandbox, imported in 0.45 seconds, and produced 0 audit findings. It is a useful runtime tripwire for annotated Python, but its default container strategy samples an item rather than checking every member.

We installed it

Lab card: what happened when we installed beartypeScreenshot of beartype documentation
Install✓ · 0.2s1 package on disk · 6 MB
Importimport beartype in 0.45s · pure Python · py.typed · requires Python >=3.10
Known vulns0(pip-audit)

Answers from our run

Does beartype install cleanly?

Yes. In a fresh container with an empty cache, pip install beartype finished in 0.2s, leaving 1 package and 6 MB on disk. pip-audit reported no known vulnerabilities.

What does beartype need to run?

Python >=3.10, and nothing compiled: it is pure Python. In our run import beartype succeeded in 0.45s, and the package ships py.typed for type checkers.

beartype or typeguard: which should you use?

typeguard: Choose it when exhaustive collection checking matters more than constant per-call work. beartype 0.22.9 installed in 0.2 seconds as a single 6 MB package in our sandbox, imported in 0.45 seconds, and produced 0 audit findings.

When should you not use beartype?

Every collection element must be checked. The documented default samples one item, while the Ologn and On strategies remain unimplemented in the strategy enum

API stability4/5The project still centers on the long-standing @beartype decorator, BeartypeConf, claw import hooks, and door object checks. Compatibility aliases soften some renames, but the package remains on a 0.x version and newer surfaces such as hint inference have moved between namespaces. Pin the minor version and run annotation-heavy tests before an upgrade.
Docs3/5ReadTheDocs has dedicated material for the decorator, configuration, import hooks, door checks, supported PEPs, and the constant-time strategy. Examples are plentiful and unusually candid. The comic writing style makes operational constraints slower to locate, and the missing Ologn and On implementations are clearer in source than in the first-run path.
Maintenance5/5The repository is not archived and GitHub records a push on August 22, 2026. Release 0.22.9 added PyInstaller support and ty compatibility work rather than only metadata churn. GitHub lists 115 open issues and pull requests together, which is a backlog to inspect but not evidence of abandonment beside current repository activity.
Ecosystem4/5The supplied registry figure is 19,554,635 weekly downloads, and GitHub reports 3,486 stars. The documentation covers NumPy, JAX, PyTorch, pandas, and modern typing constructs, while py.typed metadata supports typed consumers. It remains a specialist runtime checker, so static analysis and input-model tooling still sit beside it.

Use it if

  • Your functions already have useful annotations and bad runtime values are reaching them from plugins, files, or network boundaries
  • You want to enable runtime checking across one package through an import hook instead of adding a decorator to every callable
  • You need isinstance-style questions for parameterized hints such as list[dict[str, int]], which built-in isinstance cannot accept
  • A sampled check is preferable to scanning every item in a large collection on every call
Skip it if

Setup reality

Our clean Python 3.12 install of beartype 0.22.9 finished in 0.2 seconds. The environment contained one package using 6 MB, and pip-audit reported no known vulnerabilities. The measurement recorded 99 direct dependencies in package metadata. The distribution is pure Python, requires Python 3.10 or newer, includes py.typed, and uses the MIT License. import beartype succeeded in 0.45 seconds.

The decorator needs no credentials or config file. Package-wide checking does have an ordering requirement: call beartype_this_package() near the top of your package init.py, before importing the modules you expect it to cover. A module already loaded in sys.modules is outside that hook. This matters in notebooks, test runners, and plugin hosts that import application code early.

The normal O1 strategy keeps call cost bounded by testing a sampled member of a container. It can therefore miss one wrong item inside a mostly valid list. Use the result as a tripwire for common shape mistakes, not as proof that an entire payload was inspected. Custom Annotated validators also execute at runtime, so expensive regex compilation, I/O, or database work does not belong inside their predicate.

Turning on beartype_all() can expose bad annotations in dependencies you do not own. The README's safer split is to raise for your package and configure third-party violations as warnings. Postponed or forward annotations must still resolve to names available at runtime. Version 0.22.9 handles PyInstaller explicitly; its ty support is described by the release itself as superficial, so keep static-checker changes under test.

Patterns

Reject a wrong argument at the function boundary check-callable

from beartype import beartype

@beartype
def resize(width: int, height: int) -> tuple[int, int]:
    return width, height

resize(640, 480)

Only annotated parameters and returns are checked. A wrong argument raises a BeartypeCallHintParamViolation.

Enable checks for modules imported later check-package

# acme/__init__.py
from beartype.claw import beartype_this_package

beartype_this_package()

from acme import api

Place the hook before package imports. It does not revisit modules that Python has already loaded.

Ask whether an object matches a parameterized hint inspect-object

from beartype.door import is_bearable

payload = [{'count': 2}]
if not is_bearable(payload, list[dict[str, int]]):
    raise ValueError('bad payload')

Container checks use the configured beartype strategy. The default may sample rather than inspect every item.

Raise when an object misses its hint assert-object

from beartype.door import die_if_unbearable

die_if_unbearable({'port': 5432}, dict[str, int])

This raises BeartypeDoorHintViolation and is useful outside a decorated function signature.

Require a port inside a valid range constrain-annotated-value

from typing import Annotated
from beartype import beartype
from beartype.vale import Is

Port = Annotated[int, Is[lambda value: 1 <= value <= 65535]]

@beartype
def listen(port: Port) -> None:
    pass

The predicate runs during the call. Keep it deterministic and cheap.

Map violations to an application exception change-violation-type

from beartype import BeartypeConf, beartype

class InputError(ValueError):
    pass

@beartype(conf=BeartypeConf(violation_param_type=InputError))
def ingest(rows: list[str]) -> None:
    pass

Parameter and return exception classes can be configured separately.

Warn when code outside your package violates a hint warn-on-dependencies

from beartype import BeartypeConf
from beartype.claw import beartype_all

beartype_all(conf=BeartypeConf(violation_type=UserWarning))

A global hook can be noisy. Use warning filters for known dependency problems and keep your own package policy separate.

Make a decorator that performs no checks disable-checks

from beartype import BeartypeConf, BeartypeStrategy, beartype

unchecked = beartype(conf=BeartypeConf(strategy=BeartypeStrategy.O0))

@unchecked
def compute(values: list[float]) -> float:
    return sum(values)

O0 reduces decoration to the identity path, which is useful when production policy disables runtime checks.

Separate caller mistakes from bad return values catch-call-error

from beartype.roar import (
    BeartypeCallHintParamViolation,
    BeartypeCallHintReturnViolation,
)

try:
    result = build_report(request)
except BeartypeCallHintParamViolation as error:
    return {'error': str(error)}, 400
except BeartypeCallHintReturnViolation:
    raise

A return violation points to the decorated implementation, while a parameter violation normally belongs at the caller boundary.

Check imports made inside one context scope-import-hook

from beartype.claw import beartyping

with beartyping():
    import vendor_plugin

The context affects imports performed inside it. Importing vendor_plugin earlier prevents the hook from seeing it.

Compare the breadth of two hints compare-type-hints

from beartype.door import is_subhint

assert is_subhint(list[int], list[object])
assert not is_subhint(int | str, int)

This is useful in registries that rank handlers by how specific their accepted hint is.

Print generated checking code debug-generated-wrapper

from beartype import BeartypeConf, beartype

@beartype(conf=BeartypeConf(is_debug=True))
def normalize(names: list[str]) -> list[str]:
    return [name.strip() for name in names]

Debug mode exposes the generated wrapper, which helps explain an unexpected check during tests.

Alternatives

PackageRegistryPick it when
typeguardPyPIChoose it when exhaustive collection checking matters more than constant per-call work
jaxtypingPyPIChoose it for array shape and dtype annotations around JAX, NumPy, PyTorch, or TensorFlow code
pydanticPyPIChoose it when external input must be parsed, converted, and stored as a model

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.