#!/usr/bin/env python3
# --------------------( LICENSE )--------------------
# Copyright (c) 2014-2024 Beartype authors.
# See "LICENSE" for further details.
'''
Beartype **configuration enumerations** (i.e., public enumerations whose members
may be passed as initialization-time parameters to the
:meth:`beartype._conf.confcls.BeartypeConf.__init__` constructor to configure
:mod:`beartype` with optional runtime type-checking behaviours).
Most of the public attributes defined by this private submodule are explicitly
exported to external users in our top-level :mod:`beartype.__init__` submodule.
This private submodule is *not* intended for direct importation by downstream
callers.
'''
# ....................{ IMPORTS }....................
from enum import (
Enum,
IntEnum,
auto as next_enum_member_value,
unique as die_unless_enum_member_values_unique,
)
# ....................{ ENUMERATIONS }....................
@die_unless_enum_member_values_unique
class BeartypeDecorationPosition(Enum):
'''
Enumeration of all kinds of **import hook decorator positions** (i.e.,
competing locations to which the :func:`beartype.beartype` decorator will be
implicitly injected into existing chains of one or more decorators
decorating classes and callables defined by modules imported under
:mod:`beartype.claw` import hooks, each with concomitant tradeoffs with
respect to decorator interoperability and quality assurance).
Attributes
----------
FIRST : EnumMemberType
**First (i.e., bottom-most) decorator position**, configuring
:mod:`beartype.claw` import hooks to inject the
:func:`beartype.beartype` decorator as the first (i.e., bottom-most)
decorator in relevant decorator chains.
Note that this position is *not* the default (and thus need be
explicitly passed anywhere). Why? Various hand-wavy reasons, the most
compelling of which is that this position ignores standard decorators
and **thus violates PEP standards.** Notably, this position ignores:
* The :pep:`484`-compliant :func:`typing.no_type_check` decorator, which
then erroneously instructs :func:`beartye.beartype` to type-check
classes and callables that should *not* be type-checked.
* The :pep:`557`-compliant :func:`dataclasses.dataclass` decorator,
which then prevents :func:`beartye.beartype` from type-checking
dataclasses.
* Explicitly configured :func:`beartype.beartype` decorators (e.g.,
``@beartype(conf=BeartypeConf(...))``), which then instructs
:func:`beartye.beartype` to type-check classes and callables under
differing configurations.
When this position is used, implicit :func:`beartype.beartype`
decorators injected by :mod:`beartype.claw` import hooks assume
precedence over *all* other decorators (including those listed above),
with predictably catastrophic results. Since this is almost never what
anyone wants, this is *not* the default: e.g.,
.. code-block:: python
# Registering this import hook...
from beartype import beartype, BeartypeConf, BeartypeDecorationPosition
from beartype.claw import beartype_this_package
beartype_this_package(conf=BeartypeConf(
claw_decoration_position_types=BeartypeDecorationPosition.FIRST))
# ...transforms chains of class decorators like this...
from dataclasses import dataclass
@beartype(conf=BeartypeConf(is_debug=True))
@dataclass
class ClassyData(object):
integral_datum: int
# ...into chains of class decorators like this.
from dataclasses import dataclass
@beartype(conf=BeartypeConf(is_debug=True)) # <-- *IGNORED*
@dataclass # <-- *IGNORED* by the @beartype decorator injected below
@beartype # <-- @beartype now ignores all of the above decorators!!
class ClassyData(object):
integral_datum: int
In the above example, the default :func:`beartype.beartype` decorator
injected by the :func:`beartype.claw.beartype_this_package` silently
fails to type-check the :func:`dataclasses.dataclass` decorator and then
overwrites the ``@beartype(conf=BeartypeConf(is_debug=True))`` decorator
manually configured by the author of that third-party package.
Consequently, caveats apply to usage of this position:
* This position should only be applied to codebases that avoid
explicitly decorating classes and/or callables with standard
decorators, including:
* The :pep:`484`-compliant :func:`typing.no_type_check` decorator.
* The :pep:`557`-compliant :func:`dataclasses.dataclass` decorator.
* The :func:`beartype.beartype` decorator itself.
* Equivalently, this position should only be applied to codebases that
implicitly decorate *all* classes and callables with
:mod:`beartype.claw` import hooks.
* Equivalently, if a codebase explicitly decorates even a single class
or callable with the :func:`typing.no_type_check`,
:func:`dataclasses.dataclass`, or :func:`beartype.beartype`
decorators, this position should *not* be used.
* Consequently, this position should *not* be applied to other packages
outside your direct control.
* In particular, this position should *not* be applied to all packages
with the :func:`beartype.claw.beartype_all` import hook: e.g.,
.. code-block:: python
# Never do this. Srsly. Never do this. Srsly! Read this and weep.
from beartype import BeartypeConf, BeartypeDecorationPosition
from beartype.claw import beartype_all
beartype_all(conf=BeartypeConf(
claw_decoration_position_types=BeartypeDecorationPosition.FIRST))
LAST : EnumMemberType
**Last (i.e., top-most) decorator position**, configuring
:mod:`beartype.claw` import hooks to inject the
:func:`beartype.beartype` decorator as the last (i.e., top-most)
decorator in relevant decorator chains.
Note that this position is already the default (and thus need *not* be
explicitly passed anywhere). Why? Various hand-wavy reasons, the most
compelling of which is that this position respects explicitly configured
:func:`beartype.beartype` decorations (e.g.,
``@beartype(conf=BeartypeConf(...))``). When this position is used,
explicit :func:`beartype.beartype` decorations assume precedence over
implicit :func:`beartype.beartype` decorations injected by
:mod:`beartype.claw` import hooks. Since that is almost always what
everyone wants, this is the default position: e.g.,
.. code-block:: python
# Registering this import hook...
from beartype import beartype, BeartypeConf, BeartypeDecorationPosition
from beartype.claw import beartype_this_package
beartype_this_package(conf=BeartypeConf(
claw_decoration_position_funcs=BeartypeDecorationPosition.LAST))
# ...transforms chains of function decorators like this...
from functools import cache
@cache
@beartype(conf=BeartypeConf(is_debug=True))
def chad_func() -> int:
return 42
# ...into chains of function decorators like this.
from functools import cache
@beartype # <-- @beartype decorates last rather than first! \\o/
@cache
@beartype(conf=BeartypeConf(is_debug=True))
def chad_func() -> int:
return 42
In the above example, the default :func:`beartype.beartype` decorator
injected by the :func:`beartype.claw.beartype_this_package` import hook
is silently ignored in favour of the non-default
``@beartype(conf=BeartypeConf(is_debug=True))`` decorator manually
configured by the author of that third-party package.
'''
FIRST = next_enum_member_value()
LAST = next_enum_member_value()
[docs]
@die_unless_enum_member_values_unique
class BeartypeStrategy(Enum):
'''
Enumeration of all kinds of **type-checking strategies** (i.e., competing
procedures for type-checking objects passed to or returned from
:func:`beartype.beartype`-decorated callables, each with concomitant
tradeoffs with respect to runtime complexity and quality assurance).
Strategies are intentionally named according to `conventional Big O
notation <Big O_>`__ (e.g., :attr:`BeartypeStrategy.On` enables the
``O(n)`` strategy). Strategies are established per-decoration at the
fine-grained level of callables decorated by the :func:`beartype.beartype`
decorator by setting the :attr:`beartype.BeartypeConf.strategy` parameter of
the :class:`beartype.BeartypeConf` object passed as the optional ``conf``
parameter to that decorator.
Strategies enforce their corresponding runtime complexities (e.g., ``O(n)``)
across *all* type-checks performed for callables enabling those strategies.
For example, a callable configured by the :attr:`BeartypeStrategy.On`
strategy will exhibit linear ``O(n)`` complexity as its overhead for
type-checking each nesting level of each container passed to and returned
from that callable.
.. _Big O:
https://en.wikipedia.org/wiki/Big_O_notation
Attributes
----------
O0 : EnumMemberType
**No-time strategy** (i.e, disabling type-checking for a decorated
callable by reducing :func:`beartype.beartype` to the identity
decorator for that callable). Although seemingly useless, this strategy
enables users to selectively blacklist (prevent) callables from being
type-checked by our as-yet-unimplemented import hook. When implemented,
that hook will type-check all callables within a package or module
*except* those callables explicitly decorated by this strategy.
O1 : EnumMemberType
**Constant-time strategy** (i.e., the default ``O(1)`` strategy,
type-checking a single randomly selected item of each container). As the
default, this strategy need *not* be explicitly enabled.
Ologn : EnumMemberType
**Logarithmic-time strategy** (i.e., the ``O(log n)`` strategy,
type-checking a randomly selected number of items ``log(len(obj))`` of
each container ``obj``). This strategy is **currently unimplemented.**
(*To be implemented by a future beartype release.*)
On : EnumMemberType
**Linear-time strategy** (i.e., the ``O(n)`` strategy, type-checking
*all* items of a container). This strategy is **currently
unimplemented.** (*To be implemented by a future beartype release.*)
'''
O0 = next_enum_member_value()
O1 = next_enum_member_value()
Ologn = next_enum_member_value()
On = next_enum_member_value()
@die_unless_enum_member_values_unique
class BeartypeViolationVerbosity(IntEnum):
'''
Enumeration of all kinds of **violation verbosities** (i.e., positive
integers in the inclusive range ``[1, 5]`` governing the verbosity of
exception messages raised by type-checking wrappers generated by the
:func:`beartype.beartype` decorator when either receiving parameters *or*
returning values violating their annotated type hints).
Verbosities transparently reduce to integers and can thus be used wherever
integers are used (e.g., ``BeartypeViolationVerbosity.DEFAULT + 1`` is the next
level of verbosity beyond that of the default). Verbosities are established
per-decoration at the fine-grained level of callables decorated by the
:func:`beartype.beartype` decorator by setting the
:attr:`beartype.BeartypeConf.violation_verbosity` parameter of the
:class:`beartype.BeartypeConf` object passed as the optional ``conf``
parameter to that decorator.
Attributes
----------
MINIMAL : EnumMemberType
**Minimal verbosity,** intended for end users potentially lacking core
expertise in Python.
DEFAULT : EnumMemberType
**Default verbosity,** intended for a general developer audience assumed
to be fluent in Python.
MAXIMAL : EnumMemberType
**Maximum verbosity,** extending the default verbosity with additional
contextual metadata intended for debugging violations. This includes:
* A machine-readable representation of the beartype configuration under
which the current violation occurred.
'''
MINIMAL = next_enum_member_value()
DEFAULT = next_enum_member_value()
MAXIMAL = next_enum_member_value()