Like Types¶
bearshape has two broad input-contract families:
Liketypes such asF32Like[N, C]ScalarLiketypes such asU8ScalarLike
Use them when your API accepts values that will be converted, normalized, or range-checked before real work begins.
Basic usage¶
Like types accept scalars, backend arrays, NumPy arrays, and nested sequences.
They must always be subscripted.
import numpy as np
from beartype import beartype
from bearshape import N, C
from bearshape.numpy import F32, F32Like
@beartype
def to_array(x: F32Like[...]) -> np.ndarray:
return np.asarray(x, dtype=np.float32)
to_array(3.14) # scalar
to_array([1.0, 2.0, 3.0]) # 1D list
to_array([[1.0, 2.0], [3.0, 4.0]]) # 2D nested list
to_array(np.ones((3, 4))) # ndarray
to_array([[[[[[1.0]]]]]]) # arbitrarily deep nesting
@beartype
def process(x: F32Like[N, C]) -> F32[N, C]:
return np.asarray(x, dtype=np.float32)
Use [...] to mean "any rank" or a full dimension spec when the input shape
itself matters.
All built-in Like aliases are created with
make_array_like_type(..., casting="same_kind"), so dtype compatibility follows
NumPy's "same_kind" casting rules by default. For example, int32 can flow
into F32Like[...], but complex128 cannot.
Built-in Like aliases¶
NumPy exports the broadest set:
- concrete aliases such as
BoolLike,I8Like,F32Like,C128Like - category aliases such as
IntLike,FloatLike,NumLike,ShapedLike
JAX, PyTorch, and CuPy export parallel Like families with backend-specific
conversion behavior.
That default matters in practice:
F32Like[...]accepts integer inputs that can be cast tofloat32under"same_kind"F32Like[...]rejects complex inputs, because complex-to-float is not"same_kind"IntLike[...]accepts integer-like inputs but not floating-point values under the same rule
ScalarLike types (range-validated scalars)¶
ScalarLike types validate individual scalar values. There is no shape
component, only value- and dtype-family constraints.
from beartype import beartype
from bearshape.numpy import U8ScalarLike
@beartype
def clamp_pixel(value: U8ScalarLike) -> int:
return int(value)
clamp_pixel(128) # OK
clamp_pixel(256) # Raises
clamp_pixel(-1) # Raises
!!! warning "Boolean exclusion" Numeric scalar aliases (I8ScalarLike,
F32ScalarLike, NumScalarLike, etc.) reject bool and np.bool_ values.
Python bool is a subclass of int, but bearshape treats booleans as
non-numeric. Use BoolScalarLike for boolean scalars.
Available families include:
- concrete aliases:
BoolScalarLike,I8ScalarLikethroughI64ScalarLike,U8ScalarLikethroughU64ScalarLike,F16ScalarLikethroughF128ScalarLike,C64ScalarLike,C128ScalarLike,C256ScalarLike - category aliases:
IntScalarLike,FloatScalarLike,RealScalarLike,NumScalarLike,ShapedScalarLike, and others StringLikeforstr | np.str_
Backend modules re-export these NumPy-defined scalar types:
from bearshape.numpy import U8ScalarLike
from bearshape.jax import U8ScalarLike
from bearshape.torch import U8ScalarLike
from bearshape.cupy import U8ScalarLike
!!! note Backend-native 0-D arrays such as jnp.array(1.0) or
torch.tensor(1.0) are not ScalarLike. Use a Like alias with Scalar, for
example F32Like[Scalar].
Backend-specific conversion behavior¶
The Like family is intentionally backend-aware:
bearshape.numpyslow-path conversion usesnp.asarraybearshape.jaxslow-path conversion usesjnp.asarray, so objects implementing__jax_array__are acceptedbearshape.torchslow-path conversion usestorch.as_tensorbearshape.cupyslow-path conversion usescupy.asarray
Static type checkers only see the backend array type, not the broader runtime acceptance of scalars and nested sequences.
Custom ScalarLike types¶
Use make_scalar_like_type when the built-in scalar families are close but not
quite right for your API:
import numpy as np
from bearshape.numpy import make_scalar_like_type
F32ScalarDefault = make_scalar_like_type(np.float32) # same_kind
F32ScalarStrict = make_scalar_like_type(np.float32, casting="no")
F32ScalarSafe = make_scalar_like_type(np.float32, casting="safe")
F32ScalarUnsafe = make_scalar_like_type(np.float32, casting="unsafe")
Useful interpretations:
casting="no"means "exact target dtype only"casting="safe"means "no information loss"casting="same_kind"means "same numeric family" and is the defaultcasting="unsafe"is the most permissive option and should be used deliberately
target_dtype may be passed as a NumPy scalar type, a dtype object, or a
canonical dtype string such as "float32".
Numeric ScalarLike factories still reject booleans by design:
U8Scalar = make_scalar_like_type(np.uint8)
BoolScalar = make_scalar_like_type(np.bool_)
# U8Scalar rejects True / False
# BoolScalar accepts True / False
make_scalar_like_type is intentionally documented on backend modules such as
bearshape.numpy; it is not part of the lightweight root bearshape import
surface.
Casting rules¶
Both make_array_like_type and make_scalar_like_type use NumPy casting
semantics:
| Casting | Meaning | Example for target float32 | | ------------- |
--------------------- | ---------------------------- | | "no" | Exact dtype
only | only float32 | | "equiv" | Same kind and size | float32 but not
float64 | | "safe" | No information loss | int16 yes, float64 no | |
"same_kind" | Same-kind conversion | int32 yes, complex64 no | |
"unsafe" | Any cast NumPy allows | very permissive |
Default used by built-in Like aliases¶
The built-in aliases such as F32Like, I64Like, IntLike, FloatLike, and
NumLike all use:
That is the library default for make_array_like_type(...), and it is the
behavior you get unless you build a custom alias yourself.
If you need stricter or looser input acceptance, make a custom alias instead of relying on the built-ins:
from bearshape import make_array_like_type
from bearshape._dtypes import FLOAT32
F32Exact = make_array_like_type(FLOAT32, casting="no", name="F32Exact")
F32Unsafe = make_array_like_type(FLOAT32, casting="unsafe", name="F32Unsafe")
ArrayLike template¶
bearshape.numpy.ArrayLike is a public recursive type alias for custom static
typing combinations:
import numpy as np
from bearshape.numpy import ArrayLike
type MyInputType = ArrayLike[float, np.float32]
That template is most useful when you want your own checker-friendly alias but still follow bearshape's "scalar or nested sequence or array" model.