optype


Nameoptype JSON
Version 0.7.3 PyPI version JSON
download
home_pageNone
SummaryBuilding blocks for precise & flexible type hints
upload_time2024-11-30 16:29:59
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseBSD-3-Clause
keywords numpy type type hints typing
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <h1 align="center">optype</h1>

<p align="center">
    Building blocks for precise & flexible type hints.
</p>

<p align="center">
    <a href="https://pypi.org/project/optype/">
        <img
            alt="optype - PyPI"
            src="https://img.shields.io/pypi/v/optype?style=flat"
        />
    </a>
    <a href="https://anaconda.org/conda-forge/optype">
        <img
            alt="optype - conda-forge"
            src="https://anaconda.org/conda-forge/optype/badges/version.svg"
        />
    </a>
    <a href="https://github.com/jorenham/optype">
        <img
            alt="optype - Python Versions"
            src="https://img.shields.io/pypi/pyversions/optype?style=flat"
        />
    </a>
    <a href="https://scientific-python.org/specs/spec-0000/">
        <img
            alt="optype - SPEC 0 — minimum supported dependencies"
            src="https://img.shields.io/badge/SPEC-0-green?style=flat&labelColor=%23004811&color=%235CA038"
        />
    </a>
    <a href="https://github.com/jorenham/optype">
        <img
            alt="optype - license"
            src="https://img.shields.io/github/license/jorenham/optype?style=flat"
        />
    </a>
</p>
<p align="center">
    <a href="https://github.com/jorenham/optype/actions?query=workflow%3ACI">
        <img
            alt="optype - CI"
            src="https://github.com/jorenham/optype/workflows/CI/badge.svg"
        />
    </a>
    <a href="https://github.com/pre-commit/pre-commit">
        <img
            alt="optype - pre-commit"
            src="https://img.shields.io/badge/pre--commit-enabled-orange?logo=pre-commit"
        />
    </a>
    <a href="https://github.com/KotlinIsland/basedmypy">
        <img
            alt="optype - basedmypy"
            src="https://img.shields.io/badge/basedmypy-checked-fd9002"
        />
    </a>
    <a href="https://detachhead.github.io/basedpyright">
        <img
            alt="optype - basedpyright"
            src="https://img.shields.io/badge/basedpyright-checked-42b983"
        />
    </a>
    <a href="https://github.com/astral-sh/ruff">
        <img
            alt="optype - code style: ruff"
            src="https://img.shields.io/endpoint?style=flat&url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/format.json"
        />
    </a>
</p>

---

## Installation

### PyPI

Optype is available as [`optype`][PYPI] on PyPI:

```shell
pip install optype
```

For optional [NumPy][NUMPY] support, it is recommended to use the
`numpy` extra.
This ensures that the installed `numpy` version is compatible with
`optype`, following [NEP 29][NEP29] and [SPEC 0][SPEC0].

```shell
pip install "optype[numpy]"
```

See the [`optype.numpy` docs](#optypenumpy) for more info.

### Conda

Optype can also be installed as with `conda` from the [`conda-forge`][CONDA] channel:

```shell
conda install conda-forge::optype
```

[PYPI]: https://pypi.org/project/optype/
[CONDA]: https://anaconda.org/conda-forge/optype
[NUMPY]: https://github.com/numpy/numpy

## Example

Let's say you're writing a `twice(x)` function, that evaluates `2 * x`.
Implementing it is trivial, but what about the type annotations?

Because `twice(2) == 4`, `twice(3.14) == 6.28` and `twice('I') = 'II'`, it
might seem like a good idea to type it as `twice[T](x: T) -> T: ...`.
However, that wouldn't include cases such as `twice(True) == 2` or
`twice((42, True)) == (42, True, 42, True)`, where the input- and output types
differ.
Moreover, `twice` should accept *any* type with a custom `__rmul__` method
that accepts `2` as argument.

This is where `optype` comes in handy, which has single-method protocols for
*all* the builtin special methods.
For `twice`, we can use `optype.CanRMul[T, R]`, which, as the name suggests,
is a protocol with (only) the `def __rmul__(self, lhs: T) -> R: ...` method.
With this, the `twice` function can written as:

<table>
<tr>
<th width="415px">Python 3.10</th>
<th width="415px">Python 3.12+</th>
</tr>
<tr>
<td>

```python
from typing import Literal
from typing import TypeAlias, TypeVar
from optype import CanRMul

R = TypeVar("R")
Two: TypeAlias = Literal[2]
RMul2: TypeAlias = CanRMul[Two, R]


def twice(x: RMul2[R]) -> R:
    return 2 * x
```

</td>
<td>

```python
from typing import Literal
from optype import CanRMul

type Two = Literal[2]
type RMul2[R] = CanRMul[Two, R]


def twice[R](x: RMul2[R]) -> R:
    return 2 * x
```

</td>
</tr>
</table>

But what about types that implement `__add__` but not `__radd__`?
In this case, we could return `x * 2` as fallback (assuming commutativity).
Because the `optype.Can*` protocols are runtime-checkable, the revised
`twice2` function can be compactly written as:

<table>
<tr>
<th width="415px">Python 3.10</th>
<th width="415px">Python 3.12+</th>
</tr>
<tr>
<td>

```python
from optype import CanMul

Mul2: TypeAlias = CanMul[Two, R]
CMul2: TypeAlias = Mul2[R] | RMul2[R]


def twice2(x: CMul2[R]) -> R:
    if isinstance(x, CanRMul):
        return 2 * x
    else:
        return x * 2
```

</td>
<td>

```python
from optype import CanMul

type Mul2[R] = CanMul[Two, R]
type CMul2[R] = Mul2[R] | RMul2[R]


def twice2[R](x: CMul2[R]) -> R:
    if isinstance(x, CanRMul):
        return 2 * x
    else:
        return x * 2
```

</td>
</tr>
</table>

See [`examples/twice.py`](examples/twice.py) for the full example.

## Reference

The API of `optype` is flat; a single `import optype as opt` is all you need
(except for `optype.numpy`).

<!-- TOC start (generated with https://github.com/derlin/bitdowntoc) -->

- [`optype`](#optype)
    - [Builtin type conversion](#builtin-type-conversion)
    - [Rich relations](#rich-relations)
    - [Binary operations](#binary-operations)
    - [Reflected operations](#reflected-operations)
    - [Inplace operations](#inplace-operations)
    - [Unary operations](#unary-operations)
    - [Rounding](#rounding)
    - [Callables](#callables)
    - [Iteration](#iteration)
    - [Awaitables](#awaitables)
    - [Async Iteration](#async-iteration)
    - [Containers](#containers)
    - [Attributes](#attributes)
    - [Context managers](#context-managers)
    - [Descriptors](#descriptors)
    - [Buffer types](#buffer-types)
- [`optype.copy`](#optypecopy)
- [`optype.dataclasses`](#optypedataclasses)
- [`optype.inspect`](#optypeinspect)
- [`optype.json`](#optypejson)
- [`optype.pickle`](#optypepickle)
- [`optype.string`](#optypestring)
- [`optype.typing`](#optypetyping)
    - [`Any*` type aliases](#any-type-aliases)
    - [`Empty*` type aliases](#empty-type-aliases)
    - [Literal types](#literal-types)
    - [`Just*` types](#just-types) (experimental)
- [`optype.dlpack`](#optypedlpack)
- [`optype.numpy`](#optypenumpy)
    - [Shape-typing with `Array`](#shape-typing-with-array)
    - [Array-likes](#array-likes)
    - [`DType`](#dtype)
    - [`Scalar`](#scalar)
    - [`UFunc`](#ufunc)
    - [`Any*Array` and `Any*DType`](#anyarray-and-anydtype)
    - [Low-level interfaces](#low-level-interfaces)

<!-- TOC end -->

### `optype`

There are four flavors of things that live within `optype`,

-
    `optype.Can{}` types describe *what can be done* with it.
    For instance, any `CanAbs[T]` type can be used as argument to the `abs()`
    builtin function with return type `T`. Most `Can{}` implement a single
    special method, whose name directly matched that of the type. `CanAbs`
    implements `__abs__`, `CanAdd` implements `__add__`, etc.
-
    `optype.Has{}` is the analogue of `Can{}`, but for special *attributes*.
    `HasName` has a `__name__` attribute, `HasDict` has a `__dict__`, etc.
-
    `optype.Does{}` describe the *type of operators*.
    So `DoesAbs` is the type of the `abs({})` builtin function,
    and `DoesPos` the type of the `+{}` prefix operator.
-
    `optype.do_{}` are the correctly-typed implementations of `Does{}`. For
    each `do_{}` there is a `Does{}`, and vice-versa.
    So `do_abs: DoesAbs` is the typed alias of `abs({})`,
    and `do_pos: DoesPos` is a typed version of `operator.pos`.
    The `optype.do_` operators are more complete than `operators`,
    have runtime-accessible type annotations, and have names you don't
    need to know by heart.

The reference docs are structured as follows:

All [typing protocols][PC] here live in the root `optype` namespace.
They are [runtime-checkable][RC] so that you can do e.g.
`isinstance('snail', optype.CanAdd)`, in case you want to check whether
`snail` implements `__add__`.

Unlike`collections.abc`, `optype`'s protocols aren't abstract base classes,
i.e. they don't extend `abc.ABC`, only `typing.Protocol`.
This allows the `optype` protocols to be used as building blocks for `.pyi`
type stubs.

[PC]: https://typing.readthedocs.io/en/latest/spec/protocol.html
[RC]: https://typing.readthedocs.io/en/latest/spec/protocol.html#runtime-checkable-decorator-and-narrowing-types-by-isinstance

#### Builtin type conversion

The return type of these special methods is *invariant*. Python will raise an
error if some other (sub)type is returned.
This is why these `optype` interfaces don't accept generic type arguments.

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>complex(_)</code></td>
        <td><code>do_complex</code></td>
        <td><code>DoesComplex</code></td>
        <td><code>__complex__</code></td>
        <td><code>CanComplex</code></td>
    </tr>
    <tr>
        <td><code>float(_)</code></td>
        <td><code>do_float</code></td>
        <td><code>DoesFloat</code></td>
        <td><code>__float__</code></td>
        <td><code>CanFloat</code></td>
    </tr>
    <tr>
        <td><code>int(_)</code></td>
        <td><code>do_int</code></td>
        <td><code>DoesInt</code></td>
        <td><code>__int__</code></td>
        <td><code>CanInt[R: int = int]</code></td>
    </tr>
    <tr>
        <td><code>bool(_)</code></td>
        <td><code>do_bool</code></td>
        <td><code>DoesBool</code></td>
        <td><code>__bool__</code></td>
        <td><code>CanBool[R: bool = bool]</code></td>
    </tr>
    <tr>
        <td><code>bytes(_)</code></td>
        <td><code>do_bytes</code></td>
        <td><code>DoesBytes</code></td>
        <td><code>__bytes__</code></td>
        <td><code>CanBytes[R: bytes = bytes]</code></td>
    </tr>
    <tr>
        <td><code>str(_)</code></td>
        <td><code>do_str</code></td>
        <td><code>DoesStr</code></td>
        <td><code>__str__</code></td>
        <td><code>CanStr[R: str = str]</code></td>
    </tr>
</table>

> [!NOTE]
> The `Can*` interfaces of the types that can used as `typing.Literal`
> accept an optional type parameter `R`.
> This can be used to indicate a literal return type,
> for surgically precise typing, e.g. `None`, `True`, and `42` are
> instances of `CanBool[Literal[False]]`, `CanInt[Literal[1]]`, and
> `CanStr[Literal['42']]`, respectively.

These formatting methods are allowed to return instances that are a subtype
of the `str` builtin. The same holds for the `__format__` argument.
So if you're a 10x developer that wants to hack Python's f-strings, but only
if your type hints are spot-on; `optype` is you friend.

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>repr(_)</code></td>
        <td><code>do_repr</code></td>
        <td><code>DoesRepr</code></td>
        <td><code>__repr__</code></td>
        <td><code>CanRepr[R: str = str]</code></td>
    </tr>
    <tr>
        <td><code>format(_, x)</code></td>
        <td><code>do_format</code></td>
        <td><code>DoesFormat</code></td>
        <td><code>__format__</code></td>
        <td><code>CanFormat[T: str = str, R: str = str]</code></td>
    </tr>
</table>

Additionally, `optype` provides protocols for types with (custom) *hash* or
*index* methods:

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>hash(_)</code></td>
        <td><code>do_hash</code></td>
        <td><code>DoesHash</code></td>
        <td><code>__hash__</code></td>
        <td><code>CanHash</code></td>
    </tr>
    <tr>
        <td>
            <code>_.__index__()</code>
            (<a href="https://docs.python.org/3/reference/datamodel.html#object.__index__">docs</a>)
        </td>
        <td><code>do_index</code></td>
        <td><code>DoesIndex</code></td>
        <td><code>__index__</code></td>
        <td><code>CanIndex[R: int = int]</code></td>
    </tr>
</table>

#### Rich relations

The "rich" comparison special methods often return a `bool`.
However, instances of any type can be returned (e.g. a numpy array).
This is why the corresponding `optype.Can*` interfaces accept a second type
argument for the return type, that defaults to `bool` when omitted.
The first type parameter matches the passed method argument, i.e. the
right-hand side operand, denoted here as `x`.

<table>
    <tr>
        <th colspan="4" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <td>reflected</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>_ == x</code></td>
        <td><code>x == _</code></td>
        <td><code>do_eq</code></td>
        <td><code>DoesEq</code></td>
        <td><code>__eq__</code></td>
        <td><code>CanEq[T = object, R = bool]</code></td>
    </tr>
    <tr>
        <td><code>_ != x</code></td>
        <td><code>x != _</code></td>
        <td><code>do_ne</code></td>
        <td><code>DoesNe</code></td>
        <td><code>__ne__</code></td>
        <td><code>CanNe[T = object, R = bool]</code></td>
    </tr>
    <tr>
        <td><code>_ < x</code></td>
        <td><code>x > _</code></td>
        <td><code>do_lt</code></td>
        <td><code>DoesLt</code></td>
        <td><code>__lt__</code></td>
        <td><code>CanLt[T, R = bool]</code></td>
    </tr>
    <tr>
        <td><code>_ <= x</code></td>
        <td><code>x >= _</code></td>
        <td><code>do_le</code></td>
        <td><code>DoesLe</code></td>
        <td><code>__le__</code></td>
        <td><code>CanLe[T, R = bool]</code></td>
    </tr>
    <tr>
        <td><code>_ > x</code></td>
        <td><code>x < _</code></td>
        <td><code>do_gt</code></td>
        <td><code>DoesGt</code></td>
        <td><code>__gt__</code></td>
        <td><code>CanGt[T, R = bool]</code></td>
    </tr>
    <tr>
        <td><code>_ >= x</code></td>
        <td><code>x <= _</code></td>
        <td><code>do_ge</code></td>
        <td><code>DoesGe</code></td>
        <td><code>__ge__</code></td>
        <td><code>CanGe[T, R = bool]</code></td>
    </tr>
</table>

#### Binary operations

In the [Python docs][NT], these are referred to as "arithmetic operations".
But the operands aren't limited to numeric types, and because the
operations aren't required to be commutative, might be non-deterministic, and
could have side-effects.
Classifying them "arithmetic" is, at the very least, a bit of a stretch.

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>_ + x</code></td>
        <td><code>do_add</code></td>
        <td><code>DoesAdd</code></td>
        <td><code>__add__</code></td>
        <td><code>CanAdd[T, R]</code></td>
    </tr>
    <tr>
        <td><code>_ - x</code></td>
        <td><code>do_sub</code></td>
        <td><code>DoesSub</code></td>
        <td><code>__sub__</code></td>
        <td><code>CanSub[T, R]</code></td>
    </tr>
    <tr>
        <td><code>_ * x</code></td>
        <td><code>do_mul</code></td>
        <td><code>DoesMul</code></td>
        <td><code>__mul__</code></td>
        <td><code>CanMul[T, R]</code></td>
    </tr>
    <tr>
        <td><code>_ @ x</code></td>
        <td><code>do_matmul</code></td>
        <td><code>DoesMatmul</code></td>
        <td><code>__matmul__</code></td>
        <td><code>CanMatmul[T, R]</code></td>
    </tr>
    <tr>
        <td><code>_ / x</code></td>
        <td><code>do_truediv</code></td>
        <td><code>DoesTruediv</code></td>
        <td><code>__truediv__</code></td>
        <td><code>CanTruediv[T, R]</code></td>
    </tr>
    <tr>
        <td><code>_ // x</code></td>
        <td><code>do_floordiv</code></td>
        <td><code>DoesFloordiv</code></td>
        <td><code>__floordiv__</code></td>
        <td><code>CanFloordiv[T, R]</code></td>
    </tr>
    <tr>
        <td><code>_ % x</code></td>
        <td><code>do_mod</code></td>
        <td><code>DoesMod</code></td>
        <td><code>__mod__</code></td>
        <td><code>CanMod[T, R]</code></td>
    </tr>
    <tr>
        <td><code>divmod(_, x)</code></td>
        <td><code>do_divmod</code></td>
        <td><code>DoesDivmod</code></td>
        <td><code>__divmod__</code></td>
        <td><code>CanDivmod[T, R]</code></td>
    </tr>
    <tr>
        <td>
            <code>_ ** x</code><br/>
            <code>pow(_, x)</code>
        </td>
        <td><code>do_pow/2</code></td>
        <td><code>DoesPow</code></td>
        <td><code>__pow__</code></td>
        <td>
            <code>CanPow2[T, R]</code><br/>
            <code>CanPow[T, None, R, Never]</code>
        </td>
    </tr>
    <tr>
        <td><code>pow(_, x, m)</code></td>
        <td><code>do_pow/3</code></td>
        <td><code>DoesPow</code></td>
        <td><code>__pow__</code></td>
        <td>
            <code>CanPow3[T, M, R]</code><br/>
            <code>CanPow[T, M, Never, R]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ << x</code></td>
        <td><code>do_lshift</code></td>
        <td><code>DoesLshift</code></td>
        <td><code>__lshift__</code></td>
        <td><code>CanLshift[T, R]</code></td>
    </tr>
    <tr>
        <td><code>_ >> x</code></td>
        <td><code>do_rshift</code></td>
        <td><code>DoesRshift</code></td>
        <td><code>__rshift__</code></td>
        <td><code>CanRshift[T, R]</code></td>
    </tr>
    <tr>
        <td><code>_ & x</code></td>
        <td><code>do_and</code></td>
        <td><code>DoesAnd</code></td>
        <td><code>__and__</code></td>
        <td><code>CanAnd[T, R]</code></td>
    </tr>
    <tr>
        <td><code>_ ^ x</code></td>
        <td><code>do_xor</code></td>
        <td><code>DoesXor</code></td>
        <td><code>__xor__</code></td>
        <td><code>CanXor[T, R]</code></td>
    </tr>
    <tr>
        <td><code>_ | x</code></td>
        <td><code>do_or</code></td>
        <td><code>DoesOr</code></td>
        <td><code>__or__</code></td>
        <td><code>CanOr[T, R]</code></td>
    </tr>
</table>

> [!NOTE]
> Because `pow()` can take an optional third argument, `optype`
> provides separate interfaces for `pow()` with two and three arguments.
> Additionally, there is the overloaded intersection type
> `CanPow[T, M, R, RM] =: CanPow2[T, R] & CanPow3[T, M, RM]`, as interface
> for types that can take an optional third argument.

#### Reflected operations

For the binary infix operators above, `optype` additionally provides
interfaces with *reflected* (swapped) operands, e.g. `__radd__` is a reflected
`__add__`.
They are named like the original, but prefixed with `CanR` prefix, i.e.
`__name__.replace('Can', 'CanR')`.

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>x + _</code></td>
        <td><code>do_radd</code></td>
        <td><code>DoesRAdd</code></td>
        <td><code>__radd__</code></td>
        <td><code>CanRAdd[T, R]</code></td>
    </tr>
    <tr>
        <td><code>x - _</code></td>
        <td><code>do_rsub</code></td>
        <td><code>DoesRSub</code></td>
        <td><code>__rsub__</code></td>
        <td><code>CanRSub[T, R]</code></td>
    </tr>
    <tr>
        <td><code>x * _</code></td>
        <td><code>do_rmul</code></td>
        <td><code>DoesRMul</code></td>
        <td><code>__rmul__</code></td>
        <td><code>CanRMul[T, R]</code></td>
    </tr>
    <tr>
        <td><code>x @ _</code></td>
        <td><code>do_rmatmul</code></td>
        <td><code>DoesRMatmul</code></td>
        <td><code>__rmatmul__</code></td>
        <td><code>CanRMatmul[T, R]</code></td>
    </tr>
    <tr>
        <td><code>x / _</code></td>
        <td><code>do_rtruediv</code></td>
        <td><code>DoesRTruediv</code></td>
        <td><code>__rtruediv__</code></td>
        <td><code>CanRTruediv[T, R]</code></td>
    </tr>
    <tr>
        <td><code>x // _</code></td>
        <td><code>do_rfloordiv</code></td>
        <td><code>DoesRFloordiv</code></td>
        <td><code>__rfloordiv__</code></td>
        <td><code>CanRFloordiv[T, R]</code></td>
    </tr>
    <tr>
        <td><code>x % _</code></td>
        <td><code>do_rmod</code></td>
        <td><code>DoesRMod</code></td>
        <td><code>__rmod__</code></td>
        <td><code>CanRMod[T, R]</code></td>
    </tr>
    <tr>
        <td><code>divmod(x, _)</code></td>
        <td><code>do_rdivmod</code></td>
        <td><code>DoesRDivmod</code></td>
        <td><code>__rdivmod__</code></td>
        <td><code>CanRDivmod[T, R]</code></td>
    </tr>
    <tr>
        <td>
            <code>x ** _</code><br/>
            <code>pow(x, _)</code>
        </td>
        <td><code>do_rpow</code></td>
        <td><code>DoesRPow</code></td>
        <td><code>__rpow__</code></td>
        <td><code>CanRPow[T, R]</code></td>
    </tr>
    <tr>
        <td><code>x << _</code></td>
        <td><code>do_rlshift</code></td>
        <td><code>DoesRLshift</code></td>
        <td><code>__rlshift__</code></td>
        <td><code>CanRLshift[T, R]</code></td>
    </tr>
    <tr>
        <td><code>x >> _</code></td>
        <td><code>do_rrshift</code></td>
        <td><code>DoesRRshift</code></td>
        <td><code>__rrshift__</code></td>
        <td><code>CanRRshift[T, R]</code></td>
    </tr>
    <tr>
        <td><code>x & _</code></td>
        <td><code>do_rand</code></td>
        <td><code>DoesRAnd</code></td>
        <td><code>__rand__</code></td>
        <td><code>CanRAnd[T, R]</code></td>
    </tr>
    <tr>
        <td><code>x ^ _</code></td>
        <td><code>do_rxor</code></td>
        <td><code>DoesRXor</code></td>
        <td><code>__rxor__</code></td>
        <td><code>CanRXor[T, R]</code></td>
    </tr>
    <tr>
        <td><code>x | _</code></td>
        <td><code>do_ror</code></td>
        <td><code>DoesROr</code></td>
        <td><code>__ror__</code></td>
        <td><code>CanROr[T, R]</code></td>
    </tr>
</table>

> [!NOTE]
> `CanRPow` corresponds to `CanPow2`; the 3-parameter "modulo" `pow` does not
> reflect in Python.
>
> According to the relevant [python docs][RPOW]:
> > Note that ternary `pow()` will not try calling `__rpow__()` (the coercion
> > rules would become too complicated).

[RPOW]: https://docs.python.org/3/reference/datamodel.html#object.__rpow__

#### Inplace operations

Similar to the reflected ops, the inplace/augmented ops are prefixed with
`CanI`, namely:

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>types</th>
    </tr>
    <tr>
        <td><code>_ += x</code></td>
        <td><code>do_iadd</code></td>
        <td><code>DoesIAdd</code></td>
        <td><code>__iadd__</code></td>
        <td>
            <code>CanIAdd[T, R]</code><br>
            <code>CanIAddSelf[T]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ -= x</code></td>
        <td><code>do_isub</code></td>
        <td><code>DoesISub</code></td>
        <td><code>__isub__</code></td>
        <td>
            <code>CanISub[T, R]</code><br>
            <code>CanISubSelf[T]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ *= x</code></td>
        <td><code>do_imul</code></td>
        <td><code>DoesIMul</code></td>
        <td><code>__imul__</code></td>
        <td>
            <code>CanIMul[T, R]</code><br>
            <code>CanIMulSelf[T]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ @= x</code></td>
        <td><code>do_imatmul</code></td>
        <td><code>DoesIMatmul</code></td>
        <td><code>__imatmul__</code></td>
        <td>
            <code>CanIMatmul[T, R]</code><br>
            <code>CanIMatmulSelf[T]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ /= x</code></td>
        <td><code>do_itruediv</code></td>
        <td><code>DoesITruediv</code></td>
        <td><code>__itruediv__</code></td>
        <td>
            <code>CanITruediv[T, R]</code><br>
            <code>CanITruedivSelf[T]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ //= x</code></td>
        <td><code>do_ifloordiv</code></td>
        <td><code>DoesIFloordiv</code></td>
        <td><code>__ifloordiv__</code></td>
        <td>
            <code>CanIFloordiv[T, R]</code><br>
            <code>CanIFloordivSelf[T]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ %= x</code></td>
        <td><code>do_imod</code></td>
        <td><code>DoesIMod</code></td>
        <td><code>__imod__</code></td>
        <td>
            <code>CanIMod[T, R]</code><br>
            <code>CanIModSelf[T]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ **= x</code></td>
        <td><code>do_ipow</code></td>
        <td><code>DoesIPow</code></td>
        <td><code>__ipow__</code></td>
        <td>
            <code>CanIPow[T, R]</code><br>
            <code>CanIPowSelf[T]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ <<= x</code></td>
        <td><code>do_ilshift</code></td>
        <td><code>DoesILshift</code></td>
        <td><code>__ilshift__</code></td>
        <td>
            <code>CanILshift[T, R]</code><br>
            <code>CanILshiftSelf[T]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ >>= x</code></td>
        <td><code>do_irshift</code></td>
        <td><code>DoesIRshift</code></td>
        <td><code>__irshift__</code></td>
        <td>
            <code>CanIRshift[T, R]</code><br>
            <code>CanIRshiftSelf[T]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ &= x</code></td>
        <td><code>do_iand</code></td>
        <td><code>DoesIAnd</code></td>
        <td><code>__iand__</code></td>
        <td>
            <code>CanIAnd[T, R]</code><br>
            <code>CanIAndSelf[T]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ ^= x</code></td>
        <td><code>do_ixor</code></td>
        <td><code>DoesIXor</code></td>
        <td><code>__ixor__</code></td>
        <td>
            <code>CanIXor[T, R]</code><br>
            <code>CanIXorSelf[T]</code>
        </td>
    </tr>
    <tr>
        <td><code>_ |= x</code></td>
        <td><code>do_ior</code></td>
        <td><code>DoesIOr</code></td>
        <td><code>__ior__</code></td>
        <td>
            <code>CanIOr[T, R]</code><br>
            <code>CanIOrSelf[T]</code>
        </td>
    </tr>
</table>

These inplace operators usually return itself (after some in-place mutation).
But unfortunately, it currently isn't possible to use `Self` for this (i.e.
something like `type MyAlias[T] = optype.CanIAdd[T, Self]` isn't allowed).
So to help ease this unbearable pain, `optype` comes equipped with ready-made
aliases for you to use. They bear the same name, with an additional `*Self`
suffix, e.g. `optype.CanIAddSelf[T]`.

#### Unary operations

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>types</th>
    </tr>
    <tr>
        <td><code>+_</code></td>
        <td><code>do_pos</code></td>
        <td><code>DoesPos</code></td>
        <td><code>__pos__</code></td>
        <td>
            <code>CanPos[R]</code><br>
            <code>CanPosSelf</code>
        </td>
    </tr>
    <tr>
        <td><code>-_</code></td>
        <td><code>do_neg</code></td>
        <td><code>DoesNeg</code></td>
        <td><code>__neg__</code></td>
        <td>
            <code>CanNeg[R]</code><br>
            <code>CanNegSelf</code>
        </td>
    </tr>
    <tr>
        <td><code>~_</code></td>
        <td><code>do_invert</code></td>
        <td><code>DoesInvert</code></td>
        <td><code>__invert__</code></td>
        <td>
            <code>CanInvert[R]</code><br>
            <code>CanInvertSelf</code>
        </td>
    </tr>
    <tr>
        <td><code>abs(_)</code></td>
        <td><code>do_abs</code></td>
        <td><code>DoesAbs</code></td>
        <td><code>__abs__</code></td>
        <td>
            <code>CanAbs[R]</code><br>
            <code>CanAbsSelf</code>
        </td>
    </tr>
</table>

#### Rounding

The `round()` built-in function takes an optional second argument.
From a typing perspective, `round()` has two overloads, one with 1 parameter,
and one with two.
For both overloads, `optype` provides separate operand interfaces:
`CanRound1[R]` and `CanRound2[T, RT]`.
Additionally, `optype` also provides their (overloaded) intersection type:
`CanRound[T, R, RT] = CanRound1[R] & CanRound2[T, RT]`.

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>round(_)</code></td>
        <td><code>do_round/1</code></td>
        <td><code>DoesRound</code></td>
        <td><code>__round__/1</code></td>
        <td><code>CanRound1[T = int]</code><br/></td>
    </tr>
    <tr>
        <td><code>round(_, n)</code></td>
        <td><code>do_round/2</code></td>
        <td><code>DoesRound</code></td>
        <td><code>__round__/2</code></td>
        <td><code>CanRound2[T = int, RT = float]</code><br/></td>
    </tr>
    <tr>
        <td><code>round(_, n=...)</code></td>
        <td><code>do_round</code></td>
        <td><code>DoesRound</code></td>
        <td><code>__round__</code></td>
        <td><code>CanRound[T = int, R = int, RT = float]</code></td>
    </tr>
</table>

For example, type-checkers will mark the following code as valid (tested with
pyright in strict mode):

```python
x: float = 3.14
x1: CanRound1[int] = x
x2: CanRound2[int, float] = x
x3: CanRound[int, int, float] = x
```

Furthermore, there are the alternative rounding functions from the
[`math`][MATH] standard library:

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>math.trunc(_)</code></td>
        <td><code>do_trunc</code></td>
        <td><code>DoesTrunc</code></td>
        <td><code>__trunc__</code></td>
        <td><code>CanTrunc[R = int]</code></td>
    </tr>
    <tr>
        <td><code>math.floor(_)</code></td>
        <td><code>do_floor</code></td>
        <td><code>DoesFloor</code></td>
        <td><code>__floor__</code></td>
        <td><code>CanFloor[R = int]</code></td>
    </tr>
    <tr>
        <td><code>math.ceil(_)</code></td>
        <td><code>do_ceil</code></td>
        <td><code>DoesCeil</code></td>
        <td><code>__ceil__</code></td>
        <td><code>CanCeil[R = int]</code></td>
    </tr>
</table>

Almost all implementations use `int` for `R`.
In fact, if no type for `R` is specified, it will default in `int`.
But technially speaking, these methods can be made to return anything.

[MATH]: https://docs.python.org/3/library/math.html
[NT]: https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types

#### Callables

Unlike `operator`, `optype` provides the operator for callable objects:
`optype.do_call(f, *args. **kwargs)`.

`CanCall` is similar to `collections.abc.Callable`, but is runtime-checkable,
and doesn't use esoteric hacks.

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>_(*args, **kwargs)</code></td>
        <td><code>do_call</code></td>
        <td><code>DoesCall</code></td>
        <td><code>__call__</code></td>
        <td><code>CanCall[**Pss, R]</code></td>
    </tr>
</table>

> [!NOTE]
> Pyright (and probably other typecheckers) tend to accept
> `collections.abc.Callable` in more places than `optype.CanCall`.
> This could be related to the lack of co/contra-variance specification for
> `typing.ParamSpec` (they should almost always be contravariant, but
> currently they can only be invariant).
>
> In case you encounter such a situation, please open an issue about it, so we
> can investigate further.

#### Iteration

The operand `x` of `iter(_)` is within Python known as an *iterable*, which is
what `collections.abc.Iterable[V]` is often used for (e.g. as base class, or
for instance checking).

The `optype` analogue is `CanIter[R]`, which as the name suggests,
also implements `__iter__`. But unlike `Iterable[V]`, its type parameter `R`
binds to the return type of `iter(_) -> R`. This makes it possible to annotate
the specific type of the *iterable* that `iter(_)` returns. `Iterable[V]` is
only able to annotate the type of the iterated value. To see why that isn't
possible, see [python/typing#548](https://github.com/python/typing/issues/548).

The `collections.abc.Iterator[V]` is even more awkward; it is a subtype of
`Iterable[V]`. For those familiar with `collections.abc` this might come as a
surprise, but an iterator only needs to implement `__next__`, `__iter__` isn't
needed. This means that the `Iterator[V]` is unnecessarily restrictive.
Apart from that being theoretically "ugly", it has significant performance
implications, because the time-complexity of `isinstance` on a
`typing.Protocol` is $O(n)$, with the $n$ referring to the amount of members.
So even if the overhead of the inheritance and the `abc.ABC` usage is ignored,
`collections.abc.Iterator` is twice as slow as it needs to be.

That's one of the (many) reasons that `optype.CanNext[V]` and
`optype.CanNext[V]` are the better alternatives to `Iterable` and `Iterator`
from the abracadabra collections. This is how they are defined:

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>next(_)</code></td>
        <td><code>do_next</code></td>
        <td><code>DoesNext</code></td>
        <td><code>__next__</code></td>
        <td><code>CanNext[V]</code></td>
    </tr>
    <tr>
        <td><code>iter(_)</code></td>
        <td><code>do_iter</code></td>
        <td><code>DoesIter</code></td>
        <td><code>__iter__</code></td>
        <td><code>CanIter[R: CanNext[object]]</code></td>
    </tr>
</table>

For the sake of compatibility with `collections.abc`, there is
`optype.CanIterSelf[V]`, which is a protocol whose `__iter__` returns
`typing.Self`, as well as a `__next__` method that returns `T`.
I.e. it is equivalent to `collections.abc.Iterator[V]`, but without the `abc`
nonsense.

#### Awaitables

The `optype` is almost the same as `collections.abc.Awaitable[R]`, except
that `optype.CanAwait[R]` is a pure interface, whereas `Awaitable` is
also an abstract base class (making it absolutely useless when writing stubs).

<table>
    <tr>
        <th align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>await _</code></td>
        <td><code>__await__</code></td>
        <td><code>CanAwait[R]</code></td>
    </tr>
</table>

#### Async Iteration

Yes, you guessed it right; the abracadabra collections made the exact same
mistakes for the async iterablors (or was it "iteramblers"...?).

But fret not; the `optype` alternatives are right here:

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>anext(_)</code></td>
        <td><code>do_anext</code></td>
        <td><code>DoesANext</code></td>
        <td><code>__anext__</code></td>
        <td><code>CanANext[V]</code></td>
    </tr>
    <tr>
        <td><code>aiter(_)</code></td>
        <td><code>do_aiter</code></td>
        <td><code>DoesAIter</code></td>
        <td><code>__aiter__</code></td>
        <td><code>CanAIter[R: CanAnext[object]]</code></td>
    </tr>
</table>

But wait, shouldn't `V` be a `CanAwait`? Well, only if you don't want to get
fired...
Technically speaking, `__anext__` can return any type, and `anext` will pass
it along without nagging (instance checks are slow, now stop bothering that
liberal). For details, see the discussion at [python/typeshed#7491][AN].
Just because something is legal, doesn't mean it's a good idea (don't eat the
yellow snow).

Additionally, there is `optype.CanAIterSelf[R]`, with both the
`__aiter__() -> Self` and the `__anext__() -> V` methods.

[AN]: https://github.com/python/typeshed/pull/7491

#### Containers

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>len(_)</code></td>
        <td><code>do_len</code></td>
        <td><code>DoesLen</code></td>
        <td><code>__len__</code></td>
        <td><code>CanLen[R: int = int]</code></td>
    </tr>
    <tr>
        <td>
            <code>_.__length_hint__()</code>
            (<a href="https://docs.python.org/3/reference/datamodel.html#object.__length_hint__">docs</a>)
        </td>
        <td><code>do_length_hint</code></td>
        <td><code>DoesLengthHint</code></td>
        <td><code>__length_hint__</code></td>
        <td><code>CanLengthHint[R: int = int]</code></td>
    </tr>
    <tr>
        <td><code>_[k]</code></td>
        <td><code>do_getitem</code></td>
        <td><code>DoesGetitem</code></td>
        <td><code>__getitem__</code></td>
        <td><code>CanGetitem[K, V]</code></td>
    </tr>
    <tr>
        <td>
            <code>_.__missing__()</code>
            (<a href="https://docs.python.org/3/reference/datamodel.html#object.__missing__">docs</a>)
        </td>
        <td><code>do_missing</code></td>
        <td><code>DoesMissing</code></td>
        <td><code>__missing__</code></td>
        <td><code>CanMissing[K, D]</code></td>
    </tr>
    <tr>
        <td><code>_[k] = v</code></td>
        <td><code>do_setitem</code></td>
        <td><code>DoesSetitem</code></td>
        <td><code>__setitem__</code></td>
        <td><code>CanSetitem[K, V]</code></td>
    </tr>
    <tr>
        <td><code>del _[k]</code></td>
        <td><code>do_delitem</code></td>
        <td><code>DoesDelitem</code></td>
        <td><code>__delitem__</code></td>
        <td><code>CanDelitem[K]</code></td>
    </tr>
    <tr>
        <td><code>k in _</code></td>
        <td><code>do_contains</code></td>
        <td><code>DoesContains</code></td>
        <td><code>__contains__</code></td>
        <td><code>CanContains[K = object]</code></td>
    </tr>
    <tr>
        <td><code>reversed(_)</code></td>
        <td><code>do_reversed</code></td></td>
        <td><code>DoesReversed</code></td>
        <td><code>__reversed__</code></td>
        <td>
            <code>CanReversed[R]</code>, or<br>
            <code>CanSequence[I, V, N = int]</code>
        </td>
    </tr>
</table>

Because `CanMissing[K, D]` generally doesn't show itself without
`CanGetitem[K, V]` there to hold its hand, `optype` conveniently stitched them
together as `optype.CanGetMissing[K, V, D=V]`.

Similarly, there is `optype.CanSequence[K: CanIndex | slice, V]`, which is the
combination of both `CanLen` and `CanItem[I, V]`, and serves as a more
specific and flexible `collections.abc.Sequence[V]`.

#### Attributes

<table>
    <tr>
        <th colspan="3" align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <th>function</th>
        <th>type</th>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td>
            <code>v = _.k</code> or<br/>
            <code>v = getattr(_, k)</code>
        </td>
        <td><code>do_getattr</code></td>
        <td><code>DoesGetattr</code></td>
        <td><code>__getattr__</code></td>
        <td><code>CanGetattr[K: str = str, V = object]</code></td>
    </tr>
    <tr>
        <td>
            <code>_.k = v</code> or<br/>
            <code>setattr(_, k, v)</code>
        </td>
        <td><code>do_setattr</code></td>
        <td><code>DoesSetattr</code></td>
        <td><code>__setattr__</code></td>
        <td><code>CanSetattr[K: str = str, V = object]</code></td>
    </tr>
    <tr>
        <td>
            <code>del _.k</code> or<br/>
            <code>delattr(_, k)</code>
        </td>
        <td><code>do_delattr</code></td>
        <td><code>DoesDelattr</code></td>
        <td><code>__delattr__</code></td>
        <td><code>CanDelattr[K: str = str]</code></td>
    </tr>
    <tr>
        <td><code>dir(_)</code></td>
        <td><code>do_dir</code></td>
        <td><code>DoesDir</code></td>
        <td><code>__dir__</code></td>
        <td><code>CanDir[R: CanIter[CanIterSelf[str]]]</code></td>
    </tr>
</table>

#### Context managers

Support for the `with` statement.

<table>
    <tr>
        <th align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <td>method(s)</td>
        <th>type(s)</th>
    </tr>
    <tr>
        <td></td>
        <td><code>__enter__</code></td>
        <td>
            <code>CanEnter[C]</code>, or
            <code>CanEnterSelf</code>
        </td>
    </tr>
    <tr>
        <td></td>
        <td><code>__exit__</code></td>
        <td>
            <code>CanExit[R = None]</code>
        </td>
    </tr>
    <tr>
        <td><code>with _ as c:</code></td>
        <td>
            <code>__enter__</code>, and <br>
            <code>__exit__</code>
        </td>
        <td>
            <code>CanWith[C, R=None]</code>, or<br>
            <code>CanWithSelf[R=None]</code>
        </td>
    </tr>
</table>

`CanEnterSelf` and `CanWithSelf` are (runtime-checkable) aliases for
`CanEnter[Self]` and `CanWith[Self, R]`, respectively.

For the `async with` statement the interfaces look very similar:

<table>
    <tr>
        <th align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <td>method(s)</td>
        <th>type(s)</th>
    </tr>
    <tr>
        <td></td>
        <td><code>__aenter__</code></td>
        <td>
            <code>CanAEnter[C]</code>, or<br>
            <code>CanAEnterSelf</code>
        </td>
    </tr>
    <tr>
        <td></td>
        <td><code>__aexit__</code></td>
        <td><code>CanAExit[R=None]</code></td>
    </tr>
    <tr>
        <td><code>async with _ as c:</code></td>
        <td>
            <code>__aenter__</code>, and<br>
            <code>__aexit__</code>
        </td>
        <td>
            <code>CanAsyncWith[C, R=None]</code>, or<br>
            <code>CanAsyncWithSelf[R=None]</code>
        </td>
    </tr>
</table>

#### Descriptors

Interfaces for [descriptors](https://docs.python.org/3/howto/descriptor.html).

<table>
    <tr>
        <th align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td>
            <code>v: V = T().d</code><br/>
            <code>vt: VT = T.d</code>
        </td>
        <td><code>__get__</code></td>
        <td><code>CanGet[T: object, V, VT = V]</code></td>
    </tr>
    <tr>
        <td><code>T().k = v</code></td>
        <td><code>__set__</code></td>
        <td><code>CanSet[T: object, V]</code></td>
    </tr>
    <tr>
        <td><code>del T().k</code></td>
        <td><code>__delete__</code></td>
        <td><code>CanDelete[T: object]</code></td>
    </tr>
    <tr>
        <td><code>class T: d = _</code></td>
        <td><code>__set_name__</code></td>
        <td><code>CanSetName[T: object, N: str = str]</code></td>
    </tr>
</table>

#### Buffer types

Interfaces for emulating buffer types using the [buffer protocol][BP].

<table>
    <tr>
        <th align="center">operator</th>
        <th colspan="2" align="center">operand</th>
    </tr>
    <tr>
        <td>expression</td>
        <td>method</td>
        <th>type</th>
    </tr>
    <tr>
        <td><code>v = memoryview(_)</code></td>
        <td><code>__buffer__</code></td>
        <td><code>CanBuffer[T: int = int]</code></td>
    </tr>
    <tr>
        <td><code>del v</code></td>
        <td><code>__release_buffer__</code></td>
        <td><code>CanReleaseBuffer</code></td>
    </tr>
</table>

[BP]: https://docs.python.org/3/reference/datamodel.html#python-buffer-protocol

### `optype.copy`

For the [`copy`][CP] standard library, `optype.copy` provides the following
runtime-checkable interfaces:

<table>
    <tr>
        <th align="center"><code>copy</code> standard library</th>
        <th colspan="2" align="center"><code>optype.copy</code></th>
    </tr>
    <tr>
        <td>function</td>
        <th>type</th>
        <th>method</th>
    </tr>
    <tr>
        <td><code>copy.copy(_) -> R</code></td>
        <td><code>__copy__() -> R</code></td>
        <td><code>CanCopy[R]</code></td>
    </tr>
    <tr>
        <td><code>copy.deepcopy(_, memo={}) -> R</code></td>
        <td><code>__deepcopy__(memo, /) -> R</code></td>
        <td><code>CanDeepcopy[R]</code></td>
    </tr>
    <tr>
        <td>
            <code>copy.replace(_, /, **changes: V) -> R</code>
            <sup>[1]</sup>
        </td>
        <td><code>__replace__(**changes: V) -> R</code></td>
        <td><code>CanReplace[V, R]</code></td>
    </tr>
</table>

<sup>[1]</sup> *`copy.replace` requires `python>=3.13`
(but `optype.copy.CanReplace` doesn't)*

In practice, it makes sense that a copy of an instance is the same type as the
original.
But because `typing.Self` cannot be used as a type argument, this difficult
to properly type.
Instead, you can use the `optype.copy.Can{}Self` types, which are the
runtime-checkable equivalents of the following (recursive) type aliases:

```python
type CanCopySelf = CanCopy[CanCopySelf]
type CanDeepcopySelf = CanDeepcopy[CanDeepcopySelf]
type CanReplaceSelf[V] = CanReplace[V, CanReplaceSelf[V]]
```

[CP]: https://docs.python.org/3/library/copy.html

### `optype.dataclasses`

For the [`dataclasses`][DC] standard library, `optype.dataclasses` provides the
`HasDataclassFields[V: Mapping[str, Field]]` interface.
It can conveniently be used to check whether a type or instance is a
dataclass, i.e. `isinstance(obj, HasDataclassFields)`.

[DC]: https://docs.python.org/3/library/dataclasses.html

### `optype.inspect`

A collection of functions for runtime inspection of types, modules, and other
objects.

<table width="415px">
    <tr>
        <th>Function</th>
        <th>Description</th>
    </tr>
        <tr>
        <td><code>get_args(_)</code></td>
<td>

A better alternative to [`typing.get_args()`][GET_ARGS], that

- unpacks `typing.Annotated` and Python 3.12 `type _` alias types
  (i.e. `typing.TypeAliasType`),
- recursively flattens unions and nested `typing.Literal` types, and
- raises `TypeError` if not a type expression.

Return a `tuple[type | object, ...]` of type arguments or parameters.

To illustrate one of the (many) issues with `typing.get_args`:

```pycon
>>> from typing import Literal, TypeAlias, get_args
>>> Falsy: TypeAlias = Literal[None] | Literal[False, 0] | Literal["", b""]
>>> get_args(Falsy)
(typing.Literal[None], typing.Literal[False, 0], typing.Literal['', b''])
```

But this is in direct contradiction with the
[official typing documentation][LITERAL-DOCS]:

> When a Literal is parameterized with more than one value, it’s treated as
> exactly equivalent to the union of those types.
> That is, `Literal[v1, v2, v3]` is equivalent to
> `Literal[v1] | Literal[v2] | Literal[v3]`.

So this is why `optype.inspect.get_args` should be used

```pycon
>>> import optype as opt
>>> opt.inspect.get_args(Falsy)
(None, False, 0, '', b'')
```

Another issue of `typing.get_args` is with Python 3.12 `type _ = ...` aliases,
which are meant as a replacement for `_: typing.TypeAlias = ...`, and should
therefore be treated equally:

```pycon
>>> import typing
>>> import optype as opt
>>> type StringLike = str | bytes
>>> typing.get_args(StringLike)
()
>>> opt.inspect.get_args(StringLike)
(<class 'str'>, <class 'bytes'>)
```

Clearly, `typing.get_args` fails misarably here; it would have been better
if it would have raised an error, but it instead returns an empty tuple,
hiding the fact that it doesn't support the new `type _ = ...` aliases.
But luckily, `optype.inspect.get_args` doesn't have this problem, and treats
it just like it treats `typing.Alias` (and so do the other `optype.inspect`
functions).

</td>
    </tr>
    <tr>
        <td><code>get_protocol_members(_)</code></td>
<td>

A better alternative to [`typing.get_protocol_members()`][PROTO_MEM], that

- doesn't require Python 3.13 or above,
- supports [PEP 695][PEP695] `type _` alias types on Python 3.12 and above,
- unpacks unions of `typing.Literal` ...
- ... and flattens them if nested within another `typing.Literal`,
- treats `typing.Annotated[T]` as `T`, and
- raises a `TypeError` if the passed value isn't a type expression.

Returns a `frozenset[str]` with member names.

</td>
    </tr>
    <tr>
        <td><code>get_protocols(_)</code></td>
<td>

Returns a `frozenset[type]` of the public protocols within the passed module.
Pass `private=True` to also return the private protocols.

</td>
    </tr>
    <tr>
        <td><code>is_iterable(_)</code></td>
<td>

Check whether the object can be iterated over, i.e. if it can be used in a
`for` loop, without attempting to do so.
If `True` is returned, then the object is a `optype.typing.AnyIterable`
instance.

</td>
    </tr>
    <tr>
        <td><code>is_final(_)</code></td>
<td>

Check if the type, method / classmethod / staticmethod / property, is
decorated with [`@typing.final`][@FINAL].

Note that a `@property` won't be recognized unless the `@final` decorator is
placed *below* the `@property` decorator.
See the function docstring for more information.

</td>
    </tr>
    <tr>
        <td><code>is_protocol(_)</code></td>
<td>

A backport of [`typing.is_protocol`][IS_PROTO] that was added in Python 3.13,
a re-export of [`typing_extensions.is_protocol`][IS_PROTO_EXT].

</td>
    </tr>
    <tr>
        <td><code>is_runtime_protocol(_)</code></td>
<td>

Check if the type expression is a *runtime-protocol*, i.e. a
`typing.Protocol` *type*, decorated with `@typing.runtime_checkable` (also
supports `typing_extensions`).

</td>
    </tr>
    <tr>
        <td><code>is_union_type(_)</code></td>
<td>

Check if the type is a [`typing.Union`][UNION] type, e.g. `str | int`.

Unlike `isinstance(_, types.Union)`, this function also returns `True` for
unions of user-defined `Generic` or `Protocol` types (because those are
different union types for some reason).

</td>
    </tr>
    <tr>
        <td><code>is_generic_alias(_)</code></td>
<td>

Check if the type is a *subscripted* type, e.g. `list[str]` or
`optype.CanNext[int]`, but not `list`, `CanNext`.

Unlike `isinstance(_, typing.GenericAlias)`, this function also returns `True`
for user-defined `Generic` or `Protocol` types (because those are
use a different generic alias for some reason).

Even though technically `T1 | T2` is represented as `typing.Union[T1, T2]`
(which is a (special) generic alias), `is_generic_alias` will returns `False`
for such union types, because calling `T1 | T2` a subscripted type just
doesn't make much sense.

</td>
    </tr>
</table>

> [!NOTE]
> All functions in `optype.inspect` also work for Python 3.12 `type _` aliases
> (i.e. `types.TypeAliasType`) and with `typing.Annotated`.

[UNION]: https://docs.python.org/3/library/typing.html#typing.Union
[LITERAL-DOCS]: https://typing.readthedocs.io/en/latest/spec/literal.html#shortening-unions-of-literals
[@FINAL]: https://docs.python.org/3/library/typing.html#typing.Literal
[GET_ARGS]: https://docs.python.org/3/library/typing.html#typing.get_args
[IS_PROTO]: https://docs.python.org/3.13/library/typing.html#typing.is_protocol
[IS_PROTO_EXT]: https://typing-extensions.readthedocs.io/en/latest/#typing_extensions.is_protocol
[PROTO_MEM]: https://docs.python.org/3.13/library/typing.html#typing.get_protocol_members

### `optype.json`

Type aliases for the `json` standard library:

<table>
    <tr>
        <td><code>Value</code></td>
        <td><code>AnyValue</code></td>
    </tr>
    <tr>
        <th><code>json.load(s)</code> return type</th>
        <th><code>json.dumps(s)</code> input type</th>
    </tr>
    <tr>
        <td><code>Array[V: Value = Value]</code></td>
        <td><code>AnyArray[V: AnyValue = AnyValue]</code></td>
    </tr>
    <tr>
        <td><code>Object[V: Value = Value]</code></td>
        <td><code>AnyObject[V: AnyValue = AnyValue]</code></td>
    </tr>
</table>

The `(Any)Value` can be any json input, i.e. `Value | Array | Object` is
equivalent to `Value`.
It's also worth noting that `Value` is a subtype of `AnyValue`, which means
that `AnyValue | Value` is equivalent to `AnyValue`.

### `optype.pickle`

For the [`pickle`][PK] standard library, `optype.pickle` provides the following
interfaces:

[PK]: https://docs.python.org/3/library/pickle.html

<table>
    <tr>
        <th>method(s)</th>
        <th>signature (bound)</th>
        <th>type</th>
    </tr>
    <tr>
        <td><code>__reduce__</code></td>
        <td><code>() -> R</code></td>
        <td><code>CanReduce[R: str | tuple = ...]</code></td>
    </tr>
    <tr>
        <td><code>__reduce_ex__</code></td>
        <td><code>(CanIndex) -> R</code></td>
        <td><code>CanReduceEx[R: str | tuple = ...]</code></td>
    </tr>
    <tr>
        <td><code>__getstate__</code></td>
        <td><code>() -> S</code></td>
        <td><code>CanGetstate[S]</code></td>
    </tr>
    <tr>
        <td><code>__setstate__</code></td>
        <td><code>(S) -> None</code></td>
        <td><code>CanSetstate[S]</code></td>
    </tr>
    <tr>
        <td>
            <code>__getnewargs__</code><br>
            <code>__new__</code>
        </td>
        <td>
            <code>() -> tuple[V, ...]</code><br>
            <code>(V) -> Self</code><br>
        </td>
        <td><code>CanGetnewargs[V]</code></td>
    </tr>
    <tr>
        <td>
            <code>__getnewargs_ex__</code><br>
            <code>__new__</code>
        </td>
        <td>
            <code>() -> tuple[tuple[V, ...], dict[str, KV]]</code><br>
            <code>(*tuple[V, ...], **dict[str, KV]) -> Self</code><br>
        </td>
        <td><code>CanGetnewargsEx[V, KV]</code></td>
    </tr>
</table>

### `optype.string`

The [`string`](https://docs.python.org/3/library/string.html) standard
library contains practical constants, but it has two issues:

- The constants contain a collection of characters, but are represented as
  a single string. This makes it practically impossible to type-hint the
  individual characters, so typeshed currently types these constants as a
  `LiteralString`.
- The names of the constants are inconsistent, and doesn't follow
  [PEP 8](https://peps.python.org/pep-0008/#constants).

So instead, `optype.string` provides an alternative interface, that is
compatible with `string`, but with slight differences:

- For each constant, there is a corresponding `Literal` type alias for
  the *individual* characters. Its name matches the name of the constant,
  but is singular instead of plural.
- Instead of a single string, `optype.string` uses a `tuple` of characters,
  so that each character has its own `typing.Literal` annotation.
  Note that this is only tested with (based)pyright / pylance, so it might
  not work with mypy (it has more bugs than it has lines of codes).
- The names of the constant are consistent with PEP 8, and use a postfix
  notation for variants, e.g. `DIGITS_HEX` instead of `hexdigits`.
- Unlike `string`, `optype.string` has a constant (and type alias) for
  binary digits `'0'` and `'1'`; `DIGITS_BIN` (and `DigitBin`). Because
  besides `oct` and `hex` functions in `builtins`, there's also the
  `builtins.bin` function.

<table>
    <tr>
        <th colspan="2"><code>string._</code></th>
        <th colspan="2"><code>optype.string._</code></th>
    </tr>
    <tr>
        <th>constant</th>
        <th>char type</th>
        <th>constant</th>
        <th>char type</th>
    </tr>
    <tr>
        <td colspan="2" align="center"><i>missing</i></td>
        <td><code>DIGITS_BIN</code></td>
        <td><code>DigitBin</code></td>
    </tr>
    <tr>
        <td><code>octdigits</code></td>
        <td rowspan="9"><code>LiteralString</code></td>
        <td><code>DIGITS_OCT</code></td>
        <td><code>DigitOct</code></td>
    </tr>
    <tr>
        <td><code>digits</code></td>
        <td><code>DIGITS</code></td>
        <td><code>Digit</code></td>
    </tr>
    <tr>
        <td><code>hexdigits</code></td>
        <td><code>DIGITS_HEX</code></td>
        <td><code>DigitHex</code></td>
    </tr>
    <tr>
        <td><code>ascii_letters</code></td>
        <td><code>LETTERS</code></td>
        <td><code>Letter</code></td>
    </tr>
    <tr>
        <td><code>ascii_lowercase</code></td>
        <td><code>LETTERS_LOWER</code></td>
        <td><code>LetterLower</code></td>
    </tr>
    <tr>
        <td><code>ascii_uppercase</code></td>
        <td><code>LETTERS_UPPER</code></td>
        <td><code>LetterUpper</code></td>
    </tr>
    <tr>
        <td><code>punctuation</code></td>
        <td><code>PUNCTUATION</code></td>
        <td><code>Punctuation</code></td>
    </tr>
    <tr>
        <td><code>whitespace</code></td>
        <td><code>WHITESPACE</code></td>
        <td><code>Whitespace</code></td>
    </tr>
    <tr>
        <td><code>printable</code></td>
        <td><code>PRINTABLE</code></td>
        <td><code>Printable</code></td>
    </tr>
</table>

Each of the `optype.string` constants is exactly the same as the corresponding
`string` constant (after concatenation / splitting), e.g.

```pycon
>>> import string
>>> import optype as opt
>>> "".join(opt.string.PRINTABLE) == string.printable
True
>>> tuple(string.printable) == opt.string.PRINTABLE
True
```

Similarly, the values within a constant's `Literal` type exactly match the
values of its constant:

```pycon
>>> import optype as opt
>>> from optype.inspect import get_args
>>> get_args(opt.string.Printable) == opt.string.PRINTABLE
True
```

The `optype.inspect.get_args` is a non-broken variant of `typing.get_args`
that correctly flattens nested literals, type-unions, and PEP 695 type aliases,
so that it matches the official typing specs.
*In other words; `typing.get_args` is yet another fundamentally broken
python-typing feature that's useless in the situations where you need it
most.*

### `optype.typing`

#### `Any*` type aliases

Type aliases for anything that can *always* be passed to
`int`, `float`, `complex`, `iter`, or `typing.Literal`

<table>
    <tr>
        <th>Python constructor</th>
        <th><code>optype.typing</code> alias</th>
    </tr>
    <tr>
        <td><code>int(_)</code></td>
        <td><code>AnyInt</code></td>
    </tr>
    <tr>
        <td><code>float(_)</code></td>
        <td><code>AnyFloat</code></td>
    </tr>
    <tr>
        <td><code>complex(_)</code></td>
        <td><code>AnyComplex</code></td>
    </tr>
    <tr>
        <td><code>iter(_)</code></td>
        <td><code>AnyIterable</code></td>
    </tr>
    <tr>
        <td><code>typing.Literal[_]</code></td>
        <td><code>AnyLiteral</code></td>
    </tr>
</table>

> [!NOTE]
> Even though *some* `str` and `bytes` can be converted to `int`, `float`,
> `complex`, most of them can't, and are therefore not included in these
> type aliases.

#### `Empty*` type aliases

These are builtin types or collections that are empty, i.e. have length 0 or
yield no elements.

<table>
    <tr>
        <th>instance</th>
        <th><code>optype.typing</code> type</th>
    </tr>
    <tr>
        <td><code>''</code></td>
        <td><code>EmptyString</code></td>
    </tr>
    <tr>
        <td><code>b''</code></td>
        <td><code>EmptyBytes</code></td>
    </tr>
    <tr>
        <td><code>()</code></td>
        <td><code>EmptyTuple</code></td>
    </tr>
    <tr>
        <td><code>[]</code></td>
        <td><code>EmptyList</code></td>
    </tr>
    <tr>
        <td><code>{}</code></td>
        <td><code>EmptyDict</code></td>
    </tr>
    <tr>
        <td><code>set()</code></td>
        <td><code>EmptySet</code></td>
    </tr>
    <tr>
        <td><code>(i for i in range(0))</code></td>
        <td><code>EmptyIterable</code></td>
    </tr>
</table>

#### Literal types

<table>
    <tr>
        <th>Literal values</th>
        <th><code>optype.typing</code> type</th>
        <th>Notes</th>
    </tr>
    <tr>
        <td><code>{False, True}</code></td>
        <td><code>LiteralFalse</code></td>
        <td>
            Similar to <code>typing.LiteralString</code>, but for
            <code>bool</code>.
        </td>
    </tr>
    <tr>
        <td><code>{0, 1, ..., 255}</code></td>
        <td><code>LiteralByte</code></td>
        <td>
            Integers in the range 0-255, that make up a <code>bytes</code>
            or <code>bytearray</code> objects.
        </td>
    </tr>
</table>

#### `Just` types

> [!WARNING]
> This is experimental, and is likely to change in the future.

The `JustInt` type can be used to *only* accept instances of type `int`. Subtypes
like `bool` will be rejected. This works with recent versions of mypy and pyright.

```pyi
import optype.typing as opt

def only_int_pls(x: opt.JustInt, /) -> None: ...

f(42)  # accepted
f(True)  # rejected
```

The `Just` type is a generic variant of `JustInt`. At the moment of writing, pyright
doesn't support this yet, but it will soon (after the bundled typeshed is updated).

```pyi
import optype.typing as opt

class A: ...
class B(A): ...

def must_have_type_a(a: opt.Just[A]) -> None: ...

must_have_type_a(A())  # accepted
must_have_type_a(B())  # rejected (at least with mypy)
```

### `optype.dlpack`

A collection of low-level types for working [DLPack](DOC-DLPACK).

#### Protocols

<table>
    <tr>
        <th>type signature</th>
        <th>bound method</th>
    </tr>
    <tr>
<td>

```plain
CanDLPack[
    +T = int,
    +D: int = int,
]
```

</td>
<td>

```python
def __dlpack__(
    *,
    stream: int | None = ...,
    max_version: tuple[int, int] | None = ...,
    dl_device: tuple[T, D] | None = ...,
    copy: bool | None = ...,
) -> types.CapsuleType: ...
```

</td>
    </tr>
    <tr></tr>
    <tr>
<td>

```plain
CanDLPackDevice[
    +T = int,
    +D: int = int,
]
```

</td>
<td>

```python
def __dlpack_device__() -> tuple[T, D]: ...
```

</td>
    </tr>
</table>

The `+` prefix indicates that the type parameter is *co*variant.

#### Enums

There are also two convenient
[`IntEnum`](https://docs.python.org/3/library/enum.html#enum.IntEnum)s
in `optype.dlpack`: `DLDeviceType` for the device types, and `DLDataTypeCode` for the
internal type-codes of the `DLPack` data types.

<table>

### `optype.numpy`

Optype supports both NumPy 1 and 2.
The current minimum supported version is `1.24`,
following [NEP 29][NEP29] and [SPEC 0][SPEC0].

When using `optype.numpy`, it is recommended to install `optype` with the
`numpy` extra, ensuring version compatibility:

```shell
pip install "optype[numpy]"
```

> [!NOTE]
> For the remainder of the `optype.numpy` docs, assume that the following
> import aliases are available.
>
> ```python
> from typing import Any, Literal
> import numpy as np
> import numpy.typing as npt
> import optype.numpy as onp
> ```
>
> For the sake of brevity and readability, the [PEP 695][PEP695] and
> [PEP 696][PEP696] type parameter syntax will be used, which is supported
> since Python 3.13.

#### Shape-typing with `Array`

Optype provides the generic `onp.Array` type alias for `np.ndarray`.
It is similar to `npt.NDArray`, but includes two (optional) type parameters:
one that matches the *shape type* (`ND: tuple[int, ...]`),
and one that matches the *scalar type* (`ST: np.generic`).

When put the definitions of `npt.NDArray` and `onp.Array` side-by-side,
their differences become clear:

<table>
<tr>
<th>

`numpy.typing.NDArray`[^1]

</th>
<th>

`optype.numpy.Array`

</th>
<th>

`optype.numpy.ArrayND`

</th>
</tr>
<tr>
<td>

```python
type NDArray[
    # no shape type
    ST: generic,  # no default
] = ndarray[Any, dtype[ST]]
```

</td>
<td>

```python
type Array[
    ND: (int, ...) = (int, ...),
    ST: generic = generic,
] = ndarray[ND, dtype[ST]]
```

</td>
<td>

```python
type ArrayND[
    ST: generic = generic,
    ND: (int, ...) = (int, ...),
] = ndarray[ND, dtype[ST]]
```

</td>
</tr>
</table>

Additionally, there are the three `Array{0,1,2,3}D[ST: generic]` aliases, which are
equivalent to `Array` with `tuple[()]`, `tuple[int]`, `tuple[int, int]` and
`tuple[int, int, int]` as shape-type, respectively.

[^1]: Since `numpy>=2.2` the `NDArray` alias uses `tuple[int, ...]` as shape-type
    instead of `Any`.

> [!TIP]
> Before NumPy 2.1, the shape type parameter of `ndarray` (i.e. the type of
> `ndarray.shape`) was invariant. It is therefore recommended to not use `Literal`
> within shape types on `numpy<2.1`. So with `numpy>=2.1` you can use
> `tuple[Literal[3], Literal[3]]` without problem, but with `numpy<2.1` you should use
> `tuple[int, int]` instead.
>
> See [numpy/numpy#25729](https://github.com/numpy/numpy/issues/25729) and
> [numpy/numpy#26081](https://github.com/numpy/numpy/pull/26081) for details.

With `onp.Array`, it becomes possible to type the *shape* of arrays.

A *shape* is nothing more than a tuple of (non-negative) integers, i.e.
an instance of `tuple[int, ...]` such as `(42,)`, `(480, 720, 3)` or `()`.
The length of a shape is often referred to as the *number of dimensions*
or the *dimensionality* of the array or scalar.
For arrays this is accessible through the `np.ndarray.ndim`, which is
an alias for `len(np.ndarray.shape)`.

> [!NOTE]
> Before NumPy 2, the maximum number of dimensions was `32`, but has since
> been increased to `ndim <= 64`.

To make typing the shape of an array easier, optype provides two families of
shape type aliases: `AtLeast{N}D` and `AtMost{N}D`.
The `{N}` should be replaced by the number of dimensions, which currently
is limited to `0`, `1`, `2`, and `3`.

Both of these families are generic, and their (optional) type parameters must
be either `int` (default), or a literal (non-negative) integer, i.e. like
`typing.Literal[N: int]`.

The names `AtLeast{N}D` and `AtMost{N}D` are pretty much as self-explanatory:

- `AtLeast{N}D` is a `tuple[int, ...]` with `ndim >= N`
- `AtMost{N}D` is a `tuple[int, ...]` with `ndim <= N`

The shape aliases are roughly defined as:

<table>
<tr>
<th align="center" colspan="2"><code>AtLeast{N}D</code></th>
<th align="center" colspan="2"><code>AtMost{N}D</code></th>
</tr>
<tr>
<th>type signature</th>
<th>alias type</th>
<th>type signature</th>
<th>type alias</th>
</tr>
<tr>
<td colspan="4"></td>
</tr>
<tr>
<td>

```python
type AtLeast0D[
    Ds: int = int,
] = _
```

</td>
<td>

```python
tuple[Ds, ...]
```

</td>
<td>

```python
type AtMost0D = _
```

</td>
<td>

```python
tuple[()]
```

</td>
</tr>
<tr><td colspan="4"></td></tr>
<tr>
<td>

```python
type AtLeast1D[
    D0: int = int,
    Ds: int = int,
] = _
```

</td>
<td>

```python
tuple[
    D0,
    *tuple[Ds, ...],
]
```

</td>
<td>

```python
type AtMost1D[
    D0: int = int,
] = _
```

</td>
<td>

```python
tuple[D0] | AtMost0D
```

</td>
</tr>
<tr><td colspan="4"></td></tr>
<tr>
<td>

```python
type AtLeast2D[
    D0: int = int,
    D1: int = int,
    Ds: int = int,
] = _
```

</td>
<td>

```python
tuple[
    D0,
    D1,
    *tuple[Ds, ...],
]
```

</td>
<td>

```python
type AtMost2D[
    D0: int = int,
    D1: int = int,
] = _
```

</td>
<td>

<!-- blacken-docs:off -->
```python
(
    tuple[D0, D1]
    | AtMost1D[D0]
)
```
<!-- blacken-docs:on -->

</td>
</tr>
<tr><td colspan="4"></td></tr>
<tr>
<td>

```python
type AtLeast3D[
    D0: int = int,
    D1: int = int,
    D2: int = int,
    Ds: int = int,
] = _
```

</td>
<td>

```python
tuple[
    D0,
    D1,
    D2,
    *tuple[Ds, ...],
]
```

</td>
<td>

```python
type AtMost3D[
    D0: int = int,
    D1: int = int,
    D2: int = int,
] = _
```

</td>
<td>

<!-- blacken-docs:off -->
```python
(
    tuple[D0, D1, D2]
    | AtMost2D[D0, D1]
)
```
<!-- blacken-docs:on -->

</td>
</tr>
</table>

#### Array-likes

Similar to the `numpy._typing._ArrayLike{}_co` *coercible array-like* types,
`optype.numpy` provides the `optype.numpy.To{}ND`. Unlike the ones in `numpy`, these
don't accept "bare" scalar types (the `__len__` method is required).
Additionally, there are the `To{}1D`, `To{}2D`, and `To{}3D` for vector-likes,
matrix-likes, and cuboid-likes, and the `To{}` aliases for "bare" scalar types.

<table>
<tr>
    <th align="center" colspan="2">scalar types</th>
    <th align="center">scalar-like</th>
    <th align="center"><code>{1,2,3}</code>-d array-like</th>
    <th align="center"><code>*</code>-d array-like</th>
</tr>
<tr>
    <th align="left">
        <code>builtins</code> /<br>
        <a href="#optypetyping"><code>optype.typing</code></a>
    </th>
    <th align="left"><code>numpy</code></th>
    <th align="center" colspan="4"><code>optype.numpy</code></th>
</tr>
<tr><td colspan="5"></td></tr>
<tr>
    <td align="left"><code>bool</code></td>
    <td align="left"><code>bool_</code></td>
    <td align="left"><code>ToBool</code></td>
    <td align="left"><code>ToBool[strict]{1,2,3}D</code></td>
    <td align="left"><code>ToBoolND</code></td>
</tr>
<tr><td colspan="6"></td></tr>
<tr>
    <td align="left">
        <a href="#just-types"><code>JustInt</code><a>
    </td>
    <td align="left">
        <code>integer</code>
    </td>
    <td align="left"><code>ToJustInt</code></td>
    <td align="left"><code>ToJustInt[strict]{1,2,3}D</code></td>
    <td align="left"><code>ToJustIntND</code></td>
</tr>
<tr><td colspan="6"></td></tr>
<tr>
    <td align="left"><code>int</code></td>
    <td align="left">
        <code>integer</code><br>
        <code>| bool_</code>
    </td>
    <td align="left"><code>ToInt</code></td>
    <td align="left"><code>ToInt[strict]{1,2,3}D</code></td>
    <td align="left"><code>ToIntND</code></td>
</tr>
<tr><td colspan="6"></td></tr>
<tr>
    <td align="left">
        <code>float</code><br>
        <code>| int</code>
    </td>
    <td align="left">
        <code>floating</code><br>
        <code>| integer</code><br>
        <code>| bool_</code>
    </td>
    <td align="left"><code>ToFloat</code></td>
    <td align="left"><code>ToFloat[strict]{1,2,3}D</code></td>
    <td align="left"><code>ToFloatND</code></td>
</tr>
<tr><td colspan="6"></td></tr>
<tr>
    <td align="left">
        <code>complex</code><br>
        <code>| float</code><br>
        <code>| int</code>
    </td>
    <td align="left">
        <code>number</code><br>
        <code>| bool_</code>
    </td>
    <td align="left"><code>ToComplex</code></td>
    <td align="left"><code>ToComplex[strict]{1,2,3}D</code></td>
    <td align="left"><code>ToComplexND</code></td>
</tr>
<tr><td colspan="6"></td></tr>
<tr>
    <td align="left">
        <code>bytes</code><br>
        <code>| str</code><br>
        <code>| complex</code><br>
        <code>| float</code><br>
        <code>| int</code>
    </td>
    <td align="left"><code>generic</code></td>
    <td align="left"><code>ToScalar</code></td>
    <td align="left"><code>ToArray[strict]{1,2,3}D</code></td>
    <td align="left"><code>ToArrayND</code></td>
</tr>
</table>

> [!NOTE]
> The `To*Strict{1,2,3}D` aliases were added in `optype 0.7.3`.
>
> These array-likes with *strict shape-type* require the shape-typed input to be
> shape-typed.
> This means that e.g. `ToFloat1D` and `ToFloat2D` are disjoint (non-overlapping),
> and makes them suitable to overload array-likes of a particular dtype for different
> numbers of dimensions.

Source code: [`optype/numpy/_to.py`][CODE-NP-TO]

#### `DType`

In NumPy, a *dtype* (data type) object, is an instance of the
`numpy.dtype[ST: np.generic]` type.
It's commonly used to convey metadata of a scalar type, e.g. within arrays.

Because the type parameter of `np.dtype` isn't optional, it could be more
convenient to use the alias `optype.numpy.DType`, which is defined as:

```python
type DType[ST: np.generic = np.generic] = np.dtype[ST]
```

Apart from the "CamelCase" name, the only difference with `np.dtype` is that
the type parameter can be omitted, in which case it's equivalent to
`np.dtype[np.generic]`, but shorter.

#### `Scalar`

The `optype.numpy.Scalar` interface is a generic runtime-checkable protocol,
that can be seen as a "more specific" `np.generic`, both in name, and from
a typing perspective.

Its type signature looks roughly like this:

```python
type Scalar[
    # The "Python type", so that `Scalar.item() -> PT`.
    PT: object,
    # The "N-bits" type (without having to deal with `npt.NBitBase`).
    # It matches the `itemsize: NB` property.
    NB: int = int,
] = ...
```

It can be used as e.g.

```python
are_birds_real: Scalar[bool, Literal[1]] = np.bool_(True)
the_answer: Scalar[int, Literal[2]] = np.uint16(42)
alpha: Scalar[float, Literal[8]] = np.float64(1 / 137)
```

> [!NOTE]
> The second type argument for `itemsize` can be omitted, which is equivalent
> to setting it to `int`, so `Scalar[PT]` and `Scalar[PT, int]` are equivalent.

#### `UFunc`

A large portion of numpy's public API consists of *universal functions*, often
denoted as [ufuncs][DOC-UFUNC], which are (callable) instances of
[`np.ufunc`][REF_UFUNC].

> [!TIP]
> Custom ufuncs can be created using [`np.frompyfunc`][REF_FROMPY], but also
> through a user-defined class that implements the required attributes and
> methods (i.e., duck typing).
>
But `np.ufunc` has a big issue; it accepts no type parameters.
This makes it very difficult to properly annotate its callable signature and
its literal attributes (e.g. `.nin` and `.identity`).

This is where `optype.numpy.UFunc` comes into play:
It's a runtime-checkable generic typing protocol, that has been thoroughly
type- and unit-tested to ensure compatibility with all of numpy's ufunc
definitions.
Its generic type signature looks roughly like:

```python
type UFunc[
    # The type of the (bound) `__call__` method.
    Fn: CanCall = CanCall,
    # The types of the `nin` and `nout` (readonly) attributes.
    # Within numpy these match either `Literal[1]` or `Literal[2]`.
    Nin: int = int,
    Nout: int = int,
    # The type of the `signature` (readonly) attribute;
    # Must be `None` unless this is a generalized ufunc (gufunc), e.g.
    # `np.matmul`.
    Sig: str | None = str | None,
    # The type of the `identity` (readonly) attribute (used in `.reduce`).
    # Unless `Nin: Literal[2]`, `Nout: Literal[1]`, and `Sig: None`,
    # this should always be `None`.
    # Note that `complex` also includes `bool | int | float`.
    Id: complex | bytes | str | None = float | None,
] = ...
```

> [!NOTE]
> Unfortunately, the extra callable methods of `np.ufunc` (`at`, `reduce`,
> `reduceat`, `accumulate`, and `outer`), are incorrectly annotated (as `None`
> *attributes*, even though at runtime they're methods that raise a
> `ValueError` when called).
> This currently makes it impossible to properly type these in
> `optype.numpy.UFunc`; doing so would make it incompatible with numpy's
> ufuncs.

#### `Any*Array` and `Any*DType`

The `Any{Scalar}Array` type aliases describe array-likes that are coercible to an
`numpy.ndarray` with specific [dtype][REF-DTYPES].

Unlike `numpy.typing.ArrayLike`, these `optype.numpy` aliases **don't**
accept "bare" scalar types such as `float` and `np.float64`. However, arrays of
"zero dimensions" like `onp.Array[tuple[()], np.float64]` will be accepted.
This is in line with the behavior of [`numpy.isscalar`][REF-ISSCALAR] on `numpy >= 2`.

```py
import numpy.typing as npt
import optype.numpy as onp

v_np: npt.ArrayLike = 3.14  # accepted
v_op: onp.AnyArray = 3.14  # rejected

sigma1_np: npt.ArrayLike = [[0, 1], [1, 0]]  # accepted
sigma1_op: onp.AnyArray = [[0, 1], [1, 0]]  # accepted
```

> [!NOTE]
> The [`numpy.dtypes` docs][REF-DTYPES] exists since NumPy 1.25, but its
> type annotations were incorrect before NumPy 2.1 (see
> [numpy/numpy#27008](https://github.com/numpy/numpy/pull/27008))

See the [docs][REF-SCT] for more info on the NumPy scalar type hierarchy.

[REF-SCT]: https://numpy.org/doc/stable/reference/arrays.scalars.html
[REF-DTYPES]: https://numpy.org/doc/stable/reference/arrays.dtypes.html
[REF-ISSCALAR]: https://numpy.org/doc/stable/reference/generated/numpy.isscalar.html

##### Abstract types

<table>
    <tr>
        <th align="center" colspan="2"><code>numpy._</code></th>
        <th align="center" colspan="2"><code>optype.numpy._</code></th>
    </tr>
    <tr>
        <th>scalar</th>
        <th>scalar base</th>
        <th>array-like</th>
        <th>dtype-like</th>
    </tr>
    <tr>
        <td><code>generic</code></td>
        <td></td>
        <td><code>AnyArray</code></td>
        <td><code>AnyDType</code></td>
    </tr>
    <tr>
        <td><code>number</code></td>
        <td><code>generic</code></td>
        <td><code>AnyNumberArray</code></td>
        <td><code>AnyNumberDType</code></td>
    </tr>
    <tr>
        <td><code>integer</code></td>
        <td rowspan="2"><code>number</code></td>
        <td><code>AnyIntegerArray</code></td>
        <td><code>AnyIntegerDType</code></td>
    </tr>
    <tr>
        <td><code>inexact</code></td>
        <td><code>AnyInexactArray</code></td>
        <td><code>AnyInexactDType</code></td>
    </tr>
    <tr>
        <td><code>unsignedinteger</code></td>
        <td rowspan="2"><code>integer</code></td>
        <td><code>AnyUnsignedIntegerArray</code></td>
        <td><code>AnyUnsignedIntegerDType</code></td>
    </tr>
    <tr>
        <td><code>signedinteger</code></td>
        <td><code>AnySignedIntegerArray</code></td>
        <td><code>AnySignedIntegerDType</code></td>
    </tr>
    <tr>
        <td><code>floating</code></td>
        <td rowspan="2"><code>inexact</code></td>
        <td><code>AnyFloatingArray</code></td>
        <td><code>AnyFloatingDType</code></td>
    </tr>
    <tr>
        <td><code>complexfloating</code></td>
        <td><code>AnyComplexFloatingArray</code></td>
        <td><code>AnyComplexFloatingDType</code></td>
    </tr>
</table>

##### Unsigned integers

<table>
    <tr>
        <th align="center" colspan="2"><code>numpy._</code></th>
        <th align="center"><code>numpy.dtypes._</code></th>
        <th align="center" colspan="2"><code>optype.numpy._</code></th>
    </tr>
    <tr>
        <th>scalar</th>
        <th>scalar base</th>
        <th>dtype</th>
        <th>array-like</th>
        <th>dtype-like</th>
    </tr>
    <tr>
        <td><code>uint8</code>, <code>ubyte</code></td>
        <td rowspan="8"><code>unsignedinteger</code></td>
        <td><code>UInt8DType</code></td>
        <td><code>AnyUInt8Array</code></td>
        <td><code>AnyUInt8DType</code></td>
    </tr>
    <tr>
        <td><code>uint16</code>, <code>ushort</code></td>
        <td><code>UInt16DType</code></td>
        <td><code>AnyUInt16Array</code></td>
        <td><code>AnyUInt16DType</code></td>
    </tr>
    <tr>
<td>

`uint32`[^5]

</td>
        <td><code>UInt32DType</code></td>
        <td><code>AnyUInt32Array</code></td>
        <td><code>AnyUInt32DType</code></td>
    </tr>
    <tr>
        <td><code>uint64</code></td>
        <td><code>UInt64DType</code></td>
        <td><code>AnyUInt64Array</code></td>
        <td><code>AnyUInt64DType</code></td>
    </tr>
    <tr>
<td>

`uintc`[^5]

</td>
        <td><code>UIntDType</code></td>
        <td><code>AnyUIntCArray</code></td>
        <td><code>AnyUIntCDType</code></td>
    </tr>
    <tr>
<td>

`uintp`, `uint_` [^7]

</td>
        <td></td>
        <td><code>AnyUIntPArray</code></td>
        <td><code>AnyUIntPDType</code></td>
    </tr>
    <tr>
<td>

`ulong`[^6]

</td>
        <td><code>ULongDType</code></td>
        <td><code>AnyULongArray</code></td>
        <td><code>AnyULongDType</code></td>
    </tr>
    <tr>
        <td><code>ulonglong</code></td>
        <td><code>ULongLongDType</code></td>
        <td><code>AnyULongLongArray</code></td>
        <td><code>AnyULongLongDType</code></td>
    </tr>
</table>

##### Signed integers

<table>
    <tr>
        <th align="center" colspan="2"><code>numpy._</code></th>
        <th align="center"><code>numpy.dtypes._</code></th>
        <th align="center" colspan="2"><code>optype.numpy._</code></th>
    </tr>
    <tr>
        <th>scalar</th>
        <th>scalar base</th>
        <th>dtype</th>
        <th>array-like</th>
        <th>dtype-like</th>
    </tr>
    <tr>
        <td><code>int8</code></td>
        <td rowspan="8"><code>signedinteger</code></td>
        <td><code>Int8DType</code></td>
        <td><code>AnyInt8Array</code></td>
        <td><code>AnyInt8DType</code></td>
    </tr>
    <tr>
        <td><code>int16</code></td>
        <td><code>Int16DType</code></td>
        <td><code>AnyInt16Array</code></td>
        <td><code>AnyInt16DType</code></td>
    </tr>
    <tr>
<td>

`int32`[^5]

</td>
        <td><code>Int32DType</code></td>
        <td><code>AnyInt32Array</code></td>
        <td><code>AnyInt32DType</code></td>
    </tr>
    <tr>
        <td><code>int64</code></td>
        <td><code>Int64DType</code></td>
        <td><code>AnyInt64Array</code></td>
        <td><code>AnyInt64DType</code></td>
    </tr>
    <tr>
<td>

`intc`[^5]

</td>
        <td><code>IntDType</code></td>
        <td><code>AnyIntCArray</code></td>
        <td><code>AnyIntCDType</code></td>
    </tr>
    <tr>
<td>

`intp`, `int_` [^7]

</td>
        <td></td>
        <td><code>AnyIntPArray</code></td>
        <td><code>AnyIntPDType</code></td>
    </tr>
    <tr>
<td>

`long`[^6]

</td>
        <td><code>LongDType</code></td>
        <td><code>AnyLongArray</code></td>
        <td><code>AnyLongDType</code></td>
    </tr>
    <tr>
        <td><code>longlong</code></td>
        <td><code>LongLongDType</code></td>
        <td><code>AnyLongLongArray</code></td>
        <td><code>AnyLongLongDType</code></td>
    </tr>
</table>

[^5]: On unix-based platforms `np.[u]intc` are aliases for `np.[u]int32`.
[^6]: On NumPy 1 `np.uint` and `np.int_` are what in NumPy 2 are now the `np.ulong` and `np.long` types, respectively.
[^7]: Since NumPy 2, `np.uint` and `np.int_` are aliases for `np.uintp` and `np.intp`, respectively.

##### Floats

<table>
    <tr>
        <th align="center" colspan="2"><code>numpy._</code></th>
        <th align="center"><code>numpy.dtypes._</code></th>
        <th align="center" colspan="2"><code>optype.numpy._</code></th>
    </tr>
    <tr>
        <th>scalar</th>
        <th>scalar base</th>
        <th>dtype</th>
        <th>array-like</th>
        <th>dtype-like</th>
    </tr>
    <tr>
        <td>
            <code>float16</code>,<br>
            <code>half</code>
        </td>
        <td rowspan="2"><code>np.floating</code></td>
        <td><code>Float16DType</code></td>
        <td><code>AnyFloat16Array</code></td>
        <td><code>AnyFloat16DType</code></td>
    </tr>
    <tr>
        <td>
            <code>float32</code>,<br>
            <code>single</code>
        </td>
        <td><code>Float32DType</code></td>
        <td><code>AnyFloat32Array</code></td>
        <td><code>AnyFloat32DType</code></td>
    </tr>
    <tr>
        <td>
            <code>float64</code>,<br>
            <code>double</code>
        </td>
        <td>
            <code>np.floating &</code><br>
            <code>builtins.float</code>
        </td>
        <td><code>Float64DType</code></td>
        <td><code>AnyFloat64Array</code></td>
        <td><code>AnyFloat64DType</code></td>
    </tr>
    <tr>
<td>

`longdouble`[^13]

</td>
        <td><code>np.floating</code></td>
        <td><code>LongDoubleDType</code></td>
        <td><code>AnyLongDoubleArray</code></td>
        <td><code>AnyLongDoubleDType</code></td>
    </tr>
</table>

[^13]: Depending on the platform, `np.longdouble` is (almost always) an alias for **either** `float128`,
    `float96`, or (sometimes) `float64`.

##### Complex numbers

<table>
    <tr>
        <th align="center" colspan="2"><code>numpy._</code></th>
        <th align="center"><code>numpy.dtypes._</code></th>
        <th align="center" colspan="2"><code>optype.numpy._</code></th>
    </tr>
    <tr>
        <th>scalar</th>
        <th>scalar base</th>
        <th>dtype</th>
        <th>array-like</th>
        <th>dtype-like</th>
    </tr>
    <tr>
        <td>
            <code>complex64</code>,<br>
            <code>csingle</code>
        </td>
        <td><code>complexfloating</code></td>
        <td><code>Complex64DType</code></td>
        <td><code>AnyComplex64Array</code></td>
        <td><code>AnyComplex64DType</code></td>
    </tr>
    <tr>
        <td>
            <code>complex128</code>,<br>
            <code>cdouble</code>
        </td>
        <td>
            <code>complexfloating &</code><br>
            <code>builtins.complex</code>
        </td>
        <td><code>Complex128DType</code></td>
        <td><code>AnyComplex128Array</code></td>
        <td><code>AnyComplex128DType</code></td>
    </tr>
    <tr>
<td>

`clongdouble`[^16]

</td>
        <td><code>complexfloating</code></td>
        <td><code>CLongDoubleDType</code></td>
        <td><code>AnyCLongDoubleArray</code></td>
        <td><code>AnyCLongDoubleDType</code></td>
    </tr>
</table>

[^16]: Depending on the platform, `np.clongdouble` is (almost always) an alias for **either** `complex256`,
    `complex192`, or (sometimes) `complex128`.

##### "Flexible"

Scalar types with "flexible" length, whose values have a (constant) length
that depends on the specific `np.dtype` instantiation.

<table>
    <tr>
        <th align="center" colspan="2"><code>numpy._</code></th>
        <th align="center"><code>numpy.dtypes._</code></th>
        <th align="center" colspan="2"><code>optype.numpy._</code></th>
    </tr>
    <tr>
        <th>scalar</th>
        <th>scalar base</th>
        <th>dtype</th>
        <th>array-like</th>
        <th>dtype-like</th>
    </tr>
    <tr>
        <td><code>bytes_</code></td>
        <td rowspan="2"><code>character</code></td>
        <td><code>BytesDType</code></td>
        <td><code>AnyBytesArray</code></td>
        <td><code>AnyBytesDType</code></td>
    </tr>
    <tr>
        <td><code>str_</code></td>
        <td><code>StrDType</code></td>
        <td><code>AnyStrArray</code></td>
        <td><code>AnyStrDType</code></td>
    </tr>
    <tr>
        <td><code>void</code></td>
        <td><code>flexible</code></td>
        <td><code>VoidDType</code></td>
        <td><code>AnyVoidArray</code></td>
        <td><code>AnyVoidDType</code></td>
    </tr>
</table>

##### Other types

<table>
    <tr>
        <th align="center" colspan="2"><code>numpy._</code></th>
        <th align="center"><code>numpy.dtypes._</code></th>
        <th align="center" colspan="2"><code>optype.numpy._</code></th>
    </tr>
    <tr>
        <th>scalar</th>
        <th>scalar base</th>
        <th>dtype</th>
        <th>array-like</th>
        <th>dtype-like</th>
    </tr>
    <tr>
<td>

`bool_`[^0]

</td>
        <td rowspan="3"><code>generic</code></td>
        <td><code>BoolDType</code></td>
        <td><code>AnyBoolArray</code></td>
        <td><code>AnyBoolDType</code></td>
    </tr>
    <tr>
        <td><code>object_</code></td>
        <td><code>ObjectDType</code></td>
        <td><code>AnyObjectArray</code></td>
        <td><code>AnyObjectDType</code></td>
    </tr>
    <tr>
        <td><code>datetime64</code></td>
        <td><code>DateTime64DType</code></td>
        <td><code>AnyDateTime64Array</code></td>
        <td><code>AnyDateTime64DType</code></td>
    </tr>
    <tr>
        <td><code>timedelta64</code></td>
<td>

*`generic`*[^22]

</td>
        <td><code>TimeDelta64DType</code></td>
        <td><code>AnyTimeDelta64Array</code></td>
        <td><code>AnyTimeDelta64DType</code></td>
    </tr>
    <tr>
<td colspan=2>

[^2056]

</td>
        <td><code>StringDType</code></td>
        <td><code>AnyStringArray</code></td>
        <td><code>AnyStringDType</code></td>
    </tr>
</table>

[^0]: Since NumPy 2, `np.bool` is preferred over `np.bool_`, which only exists for backwards compatibility.

[^22]: At runtime `np.timedelta64` is a subclass of `np.signedinteger`, but this is currently not
    reflected in the type annotations.

[^2056]: The `np.dypes.StringDType` has no associated numpy scalar type, and its `.type` attribute returns the
    `builtins.str` type instead. But from a typing perspective, such a `np.dtype[builtins.str]` isn't a valid type.

#### Low-level interfaces

Within `optype.numpy` there are several `Can*` (single-method) and `Has*`
(single-attribute) protocols, related to the `__array_*__` dunders of the
NumPy Python API.
These typing protocols are, just like the `optype.Can*` and `optype.Has*` ones,
runtime-checkable and extensible (i.e. not `@final`).

> [!TIP]
> All type parameters of these protocols can be omitted, which is equivalent
> to passing its upper type bound.

<table>
    <tr>
        <th>Protocol type signature</th>
        <th>Implements</th>
        <th>NumPy docs</th>
    </tr>
    <tr>
<td>

```python
class CanArray[
    ND: tuple[int, ...] = ...,
    ST: np.generic = ...,
]: ...
```

</td>
<td>

<!-- blacken-docs:off -->
```python
def __array__[RT = ST](
    _,
    dtype: DType[RT] | None = ...,
) -> Array[ND, RT]
```
<!-- blacken-docs:on -->

</td>
<td>

[User Guide: Interoperability with NumPy][DOC-ARRAY]

</td>
    </tr>
    <tr><td colspan="3"></td></tr>
    <tr>
<td>

```python
class CanArrayUFunc[
    U: UFunc = ...,
    R: object = ...,
]: ...
```

</td>
<td>

```python
def __array_ufunc__(
    _,
    ufunc: U,
    method: LiteralString,
    *args: object,
    **kwargs: object,
) -> R: ...
```

</td>
<td>

[NEP 13][NEP13]

</td>
    </tr>
    <tr><td colspan="3"></td></tr>
    <tr>
<td>

```python
class CanArrayFunction[
    F: CanCall[..., object] = ...,
    R = object,
]: ...
```

</td>
<td>

```python
def __array_function__(
    _,
    func: F,
    types: CanIterSelf[type[CanArrayFunction]],
    args: tuple[object, ...],
    kwargs: Mapping[str, object],
) -> R: ...
```

</td>
<td>

[NEP 18][NEP18]

</td>
    </tr>
    <tr><td colspan="3"></td></tr>
    <tr>
<td>

```python
class CanArrayFinalize[
    T: object = ...,
]: ...
```

</td>
<td>

```python
def __array_finalize__(_, obj: T): ...
```

</td>
<td>

[User Guide: Subclassing ndarray][DOC-AFIN]

</td>
    </tr>
    <tr><td colspan="3"></td></tr>
    <tr>
<td>

```python
class CanArrayWrap: ...
```

</td>
<td>

<!-- blacken-docs:off -->
```python
def __array_wrap__[ND, ST](
    _,
    array: Array[ND, ST],
    context: (...) | None = ...,
    return_scalar: bool = ...,
) -> Self | Array[ND, ST]
```
<!-- blacken-docs:on -->

</td>
<td>

[API: Standard array subclasses][REF_ARRAY-WRAP]

</td>
    </tr>
    <tr><td colspan="3"></td></tr>
    <tr>
<td>

```python
class HasArrayInterface[
    V: Mapping[str, object] = ...,
]: ...
```

</td>
<td>

```python
__array_interface__: V
```

</td>
<td>

[API: The array interface protocol][REF_ARRAY-INTER]

</td>
    </tr>
    <tr><td colspan="3"></td></tr>
    <tr>
<td>

```python
class HasArrayPriority: ...
```

</td>
<td>

```python
__array_priority__: float
```

</td>
<td>

[API: Standard array subclasses][REF_ARRAY-PRIO]

</td>
    </tr>
    <tr><td colspan="3"></td></tr>
    <tr>
<td>

```python
class HasDType[
    DT: DType = ...,
]: ...
```

</td>
<td>

```python
dtype: DT
```

</td>
<td>

[API: Specifying and constructing data types][REF_DTYPE]

</td>
    </tr>
</table>

<!-- references -->

[DOC-UFUNC]: https://numpy.org/doc/stable/reference/ufuncs.html
[DOC-ARRAY]: https://numpy.org/doc/stable/user/basics.interoperability.html#the-array-method
[DOC-AFIN]: https://numpy.org/doc/stable/user/basics.subclassing.html#the-role-of-array-finalize

[REF_UFUNC]: https://numpy.org/doc/stable/reference/generated/numpy.ufunc.html
[REF_FROMPY]: https://numpy.org/doc/stable/reference/generated/numpy.frompyfunc.html
[REF_ARRAY-WRAP]: https://numpy.org/doc/stable/reference/arrays.classes.html#numpy.class.__array_wrap__
[REF_ARRAY-INTER]: https://numpy.org/doc/stable/reference/arrays.interface.html#python-side
[REF_ARRAY-PRIO]: https://numpy.org/doc/stable/reference/arrays.classes.html#numpy.class.__array_priority__
[REF_DTYPE]: https://numpy.org/doc/stable/reference/arrays.dtypes.html#specifying-and-constructing-data-types

[CODE-NP-TO]: https://github.com/jorenham/optype/blob/master/optype/numpy/_to.py

[NEP13]: https://numpy.org/neps/nep-0013-ufunc-overrides.html
[NEP18]: https://numpy.org/neps/nep-0018-array-function-protocol.html
[NEP29]: https://numpy.org/neps/nep-0029-deprecation_policy.html

[SPEC0]: https://scientific-python.org/specs/spec-0000/

[PEP695]: https://peps.python.org/pep-0695/
[PEP696]: https://peps.python.org/pep-0696/

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "optype",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "numpy, type, type hints, typing",
    "author": null,
    "author_email": "Joren Hammudoglu <jhammudoglu@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/08/b7/3053b7d8b648b077422cfd7235f83909b6b192c2fa42bb9dba51cdc773bf/optype-0.7.3.tar.gz",
    "platform": null,
    "description": "<h1 align=\"center\">optype</h1>\n\n<p align=\"center\">\n    Building blocks for precise & flexible type hints.\n</p>\n\n<p align=\"center\">\n    <a href=\"https://pypi.org/project/optype/\">\n        <img\n            alt=\"optype - PyPI\"\n            src=\"https://img.shields.io/pypi/v/optype?style=flat\"\n        />\n    </a>\n    <a href=\"https://anaconda.org/conda-forge/optype\">\n        <img\n            alt=\"optype - conda-forge\"\n            src=\"https://anaconda.org/conda-forge/optype/badges/version.svg\"\n        />\n    </a>\n    <a href=\"https://github.com/jorenham/optype\">\n        <img\n            alt=\"optype - Python Versions\"\n            src=\"https://img.shields.io/pypi/pyversions/optype?style=flat\"\n        />\n    </a>\n    <a href=\"https://scientific-python.org/specs/spec-0000/\">\n        <img\n            alt=\"optype - SPEC 0 \u2014 minimum supported dependencies\"\n            src=\"https://img.shields.io/badge/SPEC-0-green?style=flat&labelColor=%23004811&color=%235CA038\"\n        />\n    </a>\n    <a href=\"https://github.com/jorenham/optype\">\n        <img\n            alt=\"optype - license\"\n            src=\"https://img.shields.io/github/license/jorenham/optype?style=flat\"\n        />\n    </a>\n</p>\n<p align=\"center\">\n    <a href=\"https://github.com/jorenham/optype/actions?query=workflow%3ACI\">\n        <img\n            alt=\"optype - CI\"\n            src=\"https://github.com/jorenham/optype/workflows/CI/badge.svg\"\n        />\n    </a>\n    <a href=\"https://github.com/pre-commit/pre-commit\">\n        <img\n            alt=\"optype - pre-commit\"\n            src=\"https://img.shields.io/badge/pre--commit-enabled-orange?logo=pre-commit\"\n        />\n    </a>\n    <a href=\"https://github.com/KotlinIsland/basedmypy\">\n        <img\n            alt=\"optype - basedmypy\"\n            src=\"https://img.shields.io/badge/basedmypy-checked-fd9002\"\n        />\n    </a>\n    <a href=\"https://detachhead.github.io/basedpyright\">\n        <img\n            alt=\"optype - basedpyright\"\n            src=\"https://img.shields.io/badge/basedpyright-checked-42b983\"\n        />\n    </a>\n    <a href=\"https://github.com/astral-sh/ruff\">\n        <img\n            alt=\"optype - code style: ruff\"\n            src=\"https://img.shields.io/endpoint?style=flat&url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/format.json\"\n        />\n    </a>\n</p>\n\n---\n\n## Installation\n\n### PyPI\n\nOptype is available as [`optype`][PYPI] on PyPI:\n\n```shell\npip install optype\n```\n\nFor optional [NumPy][NUMPY] support, it is recommended to use the\n`numpy` extra.\nThis ensures that the installed `numpy` version is compatible with\n`optype`, following [NEP 29][NEP29] and [SPEC 0][SPEC0].\n\n```shell\npip install \"optype[numpy]\"\n```\n\nSee the [`optype.numpy` docs](#optypenumpy) for more info.\n\n### Conda\n\nOptype can also be installed as with `conda` from the [`conda-forge`][CONDA] channel:\n\n```shell\nconda install conda-forge::optype\n```\n\n[PYPI]: https://pypi.org/project/optype/\n[CONDA]: https://anaconda.org/conda-forge/optype\n[NUMPY]: https://github.com/numpy/numpy\n\n## Example\n\nLet's say you're writing a `twice(x)` function, that evaluates `2 * x`.\nImplementing it is trivial, but what about the type annotations?\n\nBecause `twice(2) == 4`, `twice(3.14) == 6.28` and `twice('I') = 'II'`, it\nmight seem like a good idea to type it as `twice[T](x: T) -> T: ...`.\nHowever, that wouldn't include cases such as `twice(True) == 2` or\n`twice((42, True)) == (42, True, 42, True)`, where the input- and output types\ndiffer.\nMoreover, `twice` should accept *any* type with a custom `__rmul__` method\nthat accepts `2` as argument.\n\nThis is where `optype` comes in handy, which has single-method protocols for\n*all* the builtin special methods.\nFor `twice`, we can use `optype.CanRMul[T, R]`, which, as the name suggests,\nis a protocol with (only) the `def __rmul__(self, lhs: T) -> R: ...` method.\nWith this, the `twice` function can written as:\n\n<table>\n<tr>\n<th width=\"415px\">Python 3.10</th>\n<th width=\"415px\">Python 3.12+</th>\n</tr>\n<tr>\n<td>\n\n```python\nfrom typing import Literal\nfrom typing import TypeAlias, TypeVar\nfrom optype import CanRMul\n\nR = TypeVar(\"R\")\nTwo: TypeAlias = Literal[2]\nRMul2: TypeAlias = CanRMul[Two, R]\n\n\ndef twice(x: RMul2[R]) -> R:\n    return 2 * x\n```\n\n</td>\n<td>\n\n```python\nfrom typing import Literal\nfrom optype import CanRMul\n\ntype Two = Literal[2]\ntype RMul2[R] = CanRMul[Two, R]\n\n\ndef twice[R](x: RMul2[R]) -> R:\n    return 2 * x\n```\n\n</td>\n</tr>\n</table>\n\nBut what about types that implement `__add__` but not `__radd__`?\nIn this case, we could return `x * 2` as fallback (assuming commutativity).\nBecause the `optype.Can*` protocols are runtime-checkable, the revised\n`twice2` function can be compactly written as:\n\n<table>\n<tr>\n<th width=\"415px\">Python 3.10</th>\n<th width=\"415px\">Python 3.12+</th>\n</tr>\n<tr>\n<td>\n\n```python\nfrom optype import CanMul\n\nMul2: TypeAlias = CanMul[Two, R]\nCMul2: TypeAlias = Mul2[R] | RMul2[R]\n\n\ndef twice2(x: CMul2[R]) -> R:\n    if isinstance(x, CanRMul):\n        return 2 * x\n    else:\n        return x * 2\n```\n\n</td>\n<td>\n\n```python\nfrom optype import CanMul\n\ntype Mul2[R] = CanMul[Two, R]\ntype CMul2[R] = Mul2[R] | RMul2[R]\n\n\ndef twice2[R](x: CMul2[R]) -> R:\n    if isinstance(x, CanRMul):\n        return 2 * x\n    else:\n        return x * 2\n```\n\n</td>\n</tr>\n</table>\n\nSee [`examples/twice.py`](examples/twice.py) for the full example.\n\n## Reference\n\nThe API of `optype` is flat; a single `import optype as opt` is all you need\n(except for `optype.numpy`).\n\n<!-- TOC start (generated with https://github.com/derlin/bitdowntoc) -->\n\n- [`optype`](#optype)\n    - [Builtin type conversion](#builtin-type-conversion)\n    - [Rich relations](#rich-relations)\n    - [Binary operations](#binary-operations)\n    - [Reflected operations](#reflected-operations)\n    - [Inplace operations](#inplace-operations)\n    - [Unary operations](#unary-operations)\n    - [Rounding](#rounding)\n    - [Callables](#callables)\n    - [Iteration](#iteration)\n    - [Awaitables](#awaitables)\n    - [Async Iteration](#async-iteration)\n    - [Containers](#containers)\n    - [Attributes](#attributes)\n    - [Context managers](#context-managers)\n    - [Descriptors](#descriptors)\n    - [Buffer types](#buffer-types)\n- [`optype.copy`](#optypecopy)\n- [`optype.dataclasses`](#optypedataclasses)\n- [`optype.inspect`](#optypeinspect)\n- [`optype.json`](#optypejson)\n- [`optype.pickle`](#optypepickle)\n- [`optype.string`](#optypestring)\n- [`optype.typing`](#optypetyping)\n    - [`Any*` type aliases](#any-type-aliases)\n    - [`Empty*` type aliases](#empty-type-aliases)\n    - [Literal types](#literal-types)\n    - [`Just*` types](#just-types) (experimental)\n- [`optype.dlpack`](#optypedlpack)\n- [`optype.numpy`](#optypenumpy)\n    - [Shape-typing with `Array`](#shape-typing-with-array)\n    - [Array-likes](#array-likes)\n    - [`DType`](#dtype)\n    - [`Scalar`](#scalar)\n    - [`UFunc`](#ufunc)\n    - [`Any*Array` and `Any*DType`](#anyarray-and-anydtype)\n    - [Low-level interfaces](#low-level-interfaces)\n\n<!-- TOC end -->\n\n### `optype`\n\nThere are four flavors of things that live within `optype`,\n\n-\n    `optype.Can{}` types describe *what can be done* with it.\n    For instance, any `CanAbs[T]` type can be used as argument to the `abs()`\n    builtin function with return type `T`. Most `Can{}` implement a single\n    special method, whose name directly matched that of the type. `CanAbs`\n    implements `__abs__`, `CanAdd` implements `__add__`, etc.\n-\n    `optype.Has{}` is the analogue of `Can{}`, but for special *attributes*.\n    `HasName` has a `__name__` attribute, `HasDict` has a `__dict__`, etc.\n-\n    `optype.Does{}` describe the *type of operators*.\n    So `DoesAbs` is the type of the `abs({})` builtin function,\n    and `DoesPos` the type of the `+{}` prefix operator.\n-\n    `optype.do_{}` are the correctly-typed implementations of `Does{}`. For\n    each `do_{}` there is a `Does{}`, and vice-versa.\n    So `do_abs: DoesAbs` is the typed alias of `abs({})`,\n    and `do_pos: DoesPos` is a typed version of `operator.pos`.\n    The `optype.do_` operators are more complete than `operators`,\n    have runtime-accessible type annotations, and have names you don't\n    need to know by heart.\n\nThe reference docs are structured as follows:\n\nAll [typing protocols][PC] here live in the root `optype` namespace.\nThey are [runtime-checkable][RC] so that you can do e.g.\n`isinstance('snail', optype.CanAdd)`, in case you want to check whether\n`snail` implements `__add__`.\n\nUnlike`collections.abc`, `optype`'s protocols aren't abstract base classes,\ni.e. they don't extend `abc.ABC`, only `typing.Protocol`.\nThis allows the `optype` protocols to be used as building blocks for `.pyi`\ntype stubs.\n\n[PC]: https://typing.readthedocs.io/en/latest/spec/protocol.html\n[RC]: https://typing.readthedocs.io/en/latest/spec/protocol.html#runtime-checkable-decorator-and-narrowing-types-by-isinstance\n\n#### Builtin type conversion\n\nThe return type of these special methods is *invariant*. Python will raise an\nerror if some other (sub)type is returned.\nThis is why these `optype` interfaces don't accept generic type arguments.\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>complex(_)</code></td>\n        <td><code>do_complex</code></td>\n        <td><code>DoesComplex</code></td>\n        <td><code>__complex__</code></td>\n        <td><code>CanComplex</code></td>\n    </tr>\n    <tr>\n        <td><code>float(_)</code></td>\n        <td><code>do_float</code></td>\n        <td><code>DoesFloat</code></td>\n        <td><code>__float__</code></td>\n        <td><code>CanFloat</code></td>\n    </tr>\n    <tr>\n        <td><code>int(_)</code></td>\n        <td><code>do_int</code></td>\n        <td><code>DoesInt</code></td>\n        <td><code>__int__</code></td>\n        <td><code>CanInt[R: int = int]</code></td>\n    </tr>\n    <tr>\n        <td><code>bool(_)</code></td>\n        <td><code>do_bool</code></td>\n        <td><code>DoesBool</code></td>\n        <td><code>__bool__</code></td>\n        <td><code>CanBool[R: bool = bool]</code></td>\n    </tr>\n    <tr>\n        <td><code>bytes(_)</code></td>\n        <td><code>do_bytes</code></td>\n        <td><code>DoesBytes</code></td>\n        <td><code>__bytes__</code></td>\n        <td><code>CanBytes[R: bytes = bytes]</code></td>\n    </tr>\n    <tr>\n        <td><code>str(_)</code></td>\n        <td><code>do_str</code></td>\n        <td><code>DoesStr</code></td>\n        <td><code>__str__</code></td>\n        <td><code>CanStr[R: str = str]</code></td>\n    </tr>\n</table>\n\n> [!NOTE]\n> The `Can*` interfaces of the types that can used as `typing.Literal`\n> accept an optional type parameter `R`.\n> This can be used to indicate a literal return type,\n> for surgically precise typing, e.g. `None`, `True`, and `42` are\n> instances of `CanBool[Literal[False]]`, `CanInt[Literal[1]]`, and\n> `CanStr[Literal['42']]`, respectively.\n\nThese formatting methods are allowed to return instances that are a subtype\nof the `str` builtin. The same holds for the `__format__` argument.\nSo if you're a 10x developer that wants to hack Python's f-strings, but only\nif your type hints are spot-on; `optype` is you friend.\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>repr(_)</code></td>\n        <td><code>do_repr</code></td>\n        <td><code>DoesRepr</code></td>\n        <td><code>__repr__</code></td>\n        <td><code>CanRepr[R: str = str]</code></td>\n    </tr>\n    <tr>\n        <td><code>format(_, x)</code></td>\n        <td><code>do_format</code></td>\n        <td><code>DoesFormat</code></td>\n        <td><code>__format__</code></td>\n        <td><code>CanFormat[T: str = str, R: str = str]</code></td>\n    </tr>\n</table>\n\nAdditionally, `optype` provides protocols for types with (custom) *hash* or\n*index* methods:\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>hash(_)</code></td>\n        <td><code>do_hash</code></td>\n        <td><code>DoesHash</code></td>\n        <td><code>__hash__</code></td>\n        <td><code>CanHash</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>_.__index__()</code>\n            (<a href=\"https://docs.python.org/3/reference/datamodel.html#object.__index__\">docs</a>)\n        </td>\n        <td><code>do_index</code></td>\n        <td><code>DoesIndex</code></td>\n        <td><code>__index__</code></td>\n        <td><code>CanIndex[R: int = int]</code></td>\n    </tr>\n</table>\n\n#### Rich relations\n\nThe \"rich\" comparison special methods often return a `bool`.\nHowever, instances of any type can be returned (e.g. a numpy array).\nThis is why the corresponding `optype.Can*` interfaces accept a second type\nargument for the return type, that defaults to `bool` when omitted.\nThe first type parameter matches the passed method argument, i.e. the\nright-hand side operand, denoted here as `x`.\n\n<table>\n    <tr>\n        <th colspan=\"4\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <td>reflected</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>_ == x</code></td>\n        <td><code>x == _</code></td>\n        <td><code>do_eq</code></td>\n        <td><code>DoesEq</code></td>\n        <td><code>__eq__</code></td>\n        <td><code>CanEq[T = object, R = bool]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ != x</code></td>\n        <td><code>x != _</code></td>\n        <td><code>do_ne</code></td>\n        <td><code>DoesNe</code></td>\n        <td><code>__ne__</code></td>\n        <td><code>CanNe[T = object, R = bool]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ < x</code></td>\n        <td><code>x > _</code></td>\n        <td><code>do_lt</code></td>\n        <td><code>DoesLt</code></td>\n        <td><code>__lt__</code></td>\n        <td><code>CanLt[T, R = bool]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ <= x</code></td>\n        <td><code>x >= _</code></td>\n        <td><code>do_le</code></td>\n        <td><code>DoesLe</code></td>\n        <td><code>__le__</code></td>\n        <td><code>CanLe[T, R = bool]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ > x</code></td>\n        <td><code>x < _</code></td>\n        <td><code>do_gt</code></td>\n        <td><code>DoesGt</code></td>\n        <td><code>__gt__</code></td>\n        <td><code>CanGt[T, R = bool]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ >= x</code></td>\n        <td><code>x <= _</code></td>\n        <td><code>do_ge</code></td>\n        <td><code>DoesGe</code></td>\n        <td><code>__ge__</code></td>\n        <td><code>CanGe[T, R = bool]</code></td>\n    </tr>\n</table>\n\n#### Binary operations\n\nIn the [Python docs][NT], these are referred to as \"arithmetic operations\".\nBut the operands aren't limited to numeric types, and because the\noperations aren't required to be commutative, might be non-deterministic, and\ncould have side-effects.\nClassifying them \"arithmetic\" is, at the very least, a bit of a stretch.\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>_ + x</code></td>\n        <td><code>do_add</code></td>\n        <td><code>DoesAdd</code></td>\n        <td><code>__add__</code></td>\n        <td><code>CanAdd[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ - x</code></td>\n        <td><code>do_sub</code></td>\n        <td><code>DoesSub</code></td>\n        <td><code>__sub__</code></td>\n        <td><code>CanSub[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ * x</code></td>\n        <td><code>do_mul</code></td>\n        <td><code>DoesMul</code></td>\n        <td><code>__mul__</code></td>\n        <td><code>CanMul[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ @ x</code></td>\n        <td><code>do_matmul</code></td>\n        <td><code>DoesMatmul</code></td>\n        <td><code>__matmul__</code></td>\n        <td><code>CanMatmul[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ / x</code></td>\n        <td><code>do_truediv</code></td>\n        <td><code>DoesTruediv</code></td>\n        <td><code>__truediv__</code></td>\n        <td><code>CanTruediv[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ // x</code></td>\n        <td><code>do_floordiv</code></td>\n        <td><code>DoesFloordiv</code></td>\n        <td><code>__floordiv__</code></td>\n        <td><code>CanFloordiv[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ % x</code></td>\n        <td><code>do_mod</code></td>\n        <td><code>DoesMod</code></td>\n        <td><code>__mod__</code></td>\n        <td><code>CanMod[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>divmod(_, x)</code></td>\n        <td><code>do_divmod</code></td>\n        <td><code>DoesDivmod</code></td>\n        <td><code>__divmod__</code></td>\n        <td><code>CanDivmod[T, R]</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>_ ** x</code><br/>\n            <code>pow(_, x)</code>\n        </td>\n        <td><code>do_pow/2</code></td>\n        <td><code>DoesPow</code></td>\n        <td><code>__pow__</code></td>\n        <td>\n            <code>CanPow2[T, R]</code><br/>\n            <code>CanPow[T, None, R, Never]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>pow(_, x, m)</code></td>\n        <td><code>do_pow/3</code></td>\n        <td><code>DoesPow</code></td>\n        <td><code>__pow__</code></td>\n        <td>\n            <code>CanPow3[T, M, R]</code><br/>\n            <code>CanPow[T, M, Never, R]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ << x</code></td>\n        <td><code>do_lshift</code></td>\n        <td><code>DoesLshift</code></td>\n        <td><code>__lshift__</code></td>\n        <td><code>CanLshift[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ >> x</code></td>\n        <td><code>do_rshift</code></td>\n        <td><code>DoesRshift</code></td>\n        <td><code>__rshift__</code></td>\n        <td><code>CanRshift[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ & x</code></td>\n        <td><code>do_and</code></td>\n        <td><code>DoesAnd</code></td>\n        <td><code>__and__</code></td>\n        <td><code>CanAnd[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ ^ x</code></td>\n        <td><code>do_xor</code></td>\n        <td><code>DoesXor</code></td>\n        <td><code>__xor__</code></td>\n        <td><code>CanXor[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>_ | x</code></td>\n        <td><code>do_or</code></td>\n        <td><code>DoesOr</code></td>\n        <td><code>__or__</code></td>\n        <td><code>CanOr[T, R]</code></td>\n    </tr>\n</table>\n\n> [!NOTE]\n> Because `pow()` can take an optional third argument, `optype`\n> provides separate interfaces for `pow()` with two and three arguments.\n> Additionally, there is the overloaded intersection type\n> `CanPow[T, M, R, RM] =: CanPow2[T, R] & CanPow3[T, M, RM]`, as interface\n> for types that can take an optional third argument.\n\n#### Reflected operations\n\nFor the binary infix operators above, `optype` additionally provides\ninterfaces with *reflected* (swapped) operands, e.g. `__radd__` is a reflected\n`__add__`.\nThey are named like the original, but prefixed with `CanR` prefix, i.e.\n`__name__.replace('Can', 'CanR')`.\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>x + _</code></td>\n        <td><code>do_radd</code></td>\n        <td><code>DoesRAdd</code></td>\n        <td><code>__radd__</code></td>\n        <td><code>CanRAdd[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>x - _</code></td>\n        <td><code>do_rsub</code></td>\n        <td><code>DoesRSub</code></td>\n        <td><code>__rsub__</code></td>\n        <td><code>CanRSub[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>x * _</code></td>\n        <td><code>do_rmul</code></td>\n        <td><code>DoesRMul</code></td>\n        <td><code>__rmul__</code></td>\n        <td><code>CanRMul[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>x @ _</code></td>\n        <td><code>do_rmatmul</code></td>\n        <td><code>DoesRMatmul</code></td>\n        <td><code>__rmatmul__</code></td>\n        <td><code>CanRMatmul[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>x / _</code></td>\n        <td><code>do_rtruediv</code></td>\n        <td><code>DoesRTruediv</code></td>\n        <td><code>__rtruediv__</code></td>\n        <td><code>CanRTruediv[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>x // _</code></td>\n        <td><code>do_rfloordiv</code></td>\n        <td><code>DoesRFloordiv</code></td>\n        <td><code>__rfloordiv__</code></td>\n        <td><code>CanRFloordiv[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>x % _</code></td>\n        <td><code>do_rmod</code></td>\n        <td><code>DoesRMod</code></td>\n        <td><code>__rmod__</code></td>\n        <td><code>CanRMod[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>divmod(x, _)</code></td>\n        <td><code>do_rdivmod</code></td>\n        <td><code>DoesRDivmod</code></td>\n        <td><code>__rdivmod__</code></td>\n        <td><code>CanRDivmod[T, R]</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>x ** _</code><br/>\n            <code>pow(x, _)</code>\n        </td>\n        <td><code>do_rpow</code></td>\n        <td><code>DoesRPow</code></td>\n        <td><code>__rpow__</code></td>\n        <td><code>CanRPow[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>x << _</code></td>\n        <td><code>do_rlshift</code></td>\n        <td><code>DoesRLshift</code></td>\n        <td><code>__rlshift__</code></td>\n        <td><code>CanRLshift[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>x >> _</code></td>\n        <td><code>do_rrshift</code></td>\n        <td><code>DoesRRshift</code></td>\n        <td><code>__rrshift__</code></td>\n        <td><code>CanRRshift[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>x & _</code></td>\n        <td><code>do_rand</code></td>\n        <td><code>DoesRAnd</code></td>\n        <td><code>__rand__</code></td>\n        <td><code>CanRAnd[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>x ^ _</code></td>\n        <td><code>do_rxor</code></td>\n        <td><code>DoesRXor</code></td>\n        <td><code>__rxor__</code></td>\n        <td><code>CanRXor[T, R]</code></td>\n    </tr>\n    <tr>\n        <td><code>x | _</code></td>\n        <td><code>do_ror</code></td>\n        <td><code>DoesROr</code></td>\n        <td><code>__ror__</code></td>\n        <td><code>CanROr[T, R]</code></td>\n    </tr>\n</table>\n\n> [!NOTE]\n> `CanRPow` corresponds to `CanPow2`; the 3-parameter \"modulo\" `pow` does not\n> reflect in Python.\n>\n> According to the relevant [python docs][RPOW]:\n> > Note that ternary `pow()` will not try calling `__rpow__()` (the coercion\n> > rules would become too complicated).\n\n[RPOW]: https://docs.python.org/3/reference/datamodel.html#object.__rpow__\n\n#### Inplace operations\n\nSimilar to the reflected ops, the inplace/augmented ops are prefixed with\n`CanI`, namely:\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>types</th>\n    </tr>\n    <tr>\n        <td><code>_ += x</code></td>\n        <td><code>do_iadd</code></td>\n        <td><code>DoesIAdd</code></td>\n        <td><code>__iadd__</code></td>\n        <td>\n            <code>CanIAdd[T, R]</code><br>\n            <code>CanIAddSelf[T]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ -= x</code></td>\n        <td><code>do_isub</code></td>\n        <td><code>DoesISub</code></td>\n        <td><code>__isub__</code></td>\n        <td>\n            <code>CanISub[T, R]</code><br>\n            <code>CanISubSelf[T]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ *= x</code></td>\n        <td><code>do_imul</code></td>\n        <td><code>DoesIMul</code></td>\n        <td><code>__imul__</code></td>\n        <td>\n            <code>CanIMul[T, R]</code><br>\n            <code>CanIMulSelf[T]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ @= x</code></td>\n        <td><code>do_imatmul</code></td>\n        <td><code>DoesIMatmul</code></td>\n        <td><code>__imatmul__</code></td>\n        <td>\n            <code>CanIMatmul[T, R]</code><br>\n            <code>CanIMatmulSelf[T]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ /= x</code></td>\n        <td><code>do_itruediv</code></td>\n        <td><code>DoesITruediv</code></td>\n        <td><code>__itruediv__</code></td>\n        <td>\n            <code>CanITruediv[T, R]</code><br>\n            <code>CanITruedivSelf[T]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ //= x</code></td>\n        <td><code>do_ifloordiv</code></td>\n        <td><code>DoesIFloordiv</code></td>\n        <td><code>__ifloordiv__</code></td>\n        <td>\n            <code>CanIFloordiv[T, R]</code><br>\n            <code>CanIFloordivSelf[T]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ %= x</code></td>\n        <td><code>do_imod</code></td>\n        <td><code>DoesIMod</code></td>\n        <td><code>__imod__</code></td>\n        <td>\n            <code>CanIMod[T, R]</code><br>\n            <code>CanIModSelf[T]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ **= x</code></td>\n        <td><code>do_ipow</code></td>\n        <td><code>DoesIPow</code></td>\n        <td><code>__ipow__</code></td>\n        <td>\n            <code>CanIPow[T, R]</code><br>\n            <code>CanIPowSelf[T]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ <<= x</code></td>\n        <td><code>do_ilshift</code></td>\n        <td><code>DoesILshift</code></td>\n        <td><code>__ilshift__</code></td>\n        <td>\n            <code>CanILshift[T, R]</code><br>\n            <code>CanILshiftSelf[T]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ >>= x</code></td>\n        <td><code>do_irshift</code></td>\n        <td><code>DoesIRshift</code></td>\n        <td><code>__irshift__</code></td>\n        <td>\n            <code>CanIRshift[T, R]</code><br>\n            <code>CanIRshiftSelf[T]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ &= x</code></td>\n        <td><code>do_iand</code></td>\n        <td><code>DoesIAnd</code></td>\n        <td><code>__iand__</code></td>\n        <td>\n            <code>CanIAnd[T, R]</code><br>\n            <code>CanIAndSelf[T]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ ^= x</code></td>\n        <td><code>do_ixor</code></td>\n        <td><code>DoesIXor</code></td>\n        <td><code>__ixor__</code></td>\n        <td>\n            <code>CanIXor[T, R]</code><br>\n            <code>CanIXorSelf[T]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>_ |= x</code></td>\n        <td><code>do_ior</code></td>\n        <td><code>DoesIOr</code></td>\n        <td><code>__ior__</code></td>\n        <td>\n            <code>CanIOr[T, R]</code><br>\n            <code>CanIOrSelf[T]</code>\n        </td>\n    </tr>\n</table>\n\nThese inplace operators usually return itself (after some in-place mutation).\nBut unfortunately, it currently isn't possible to use `Self` for this (i.e.\nsomething like `type MyAlias[T] = optype.CanIAdd[T, Self]` isn't allowed).\nSo to help ease this unbearable pain, `optype` comes equipped with ready-made\naliases for you to use. They bear the same name, with an additional `*Self`\nsuffix, e.g. `optype.CanIAddSelf[T]`.\n\n#### Unary operations\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>types</th>\n    </tr>\n    <tr>\n        <td><code>+_</code></td>\n        <td><code>do_pos</code></td>\n        <td><code>DoesPos</code></td>\n        <td><code>__pos__</code></td>\n        <td>\n            <code>CanPos[R]</code><br>\n            <code>CanPosSelf</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>-_</code></td>\n        <td><code>do_neg</code></td>\n        <td><code>DoesNeg</code></td>\n        <td><code>__neg__</code></td>\n        <td>\n            <code>CanNeg[R]</code><br>\n            <code>CanNegSelf</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>~_</code></td>\n        <td><code>do_invert</code></td>\n        <td><code>DoesInvert</code></td>\n        <td><code>__invert__</code></td>\n        <td>\n            <code>CanInvert[R]</code><br>\n            <code>CanInvertSelf</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>abs(_)</code></td>\n        <td><code>do_abs</code></td>\n        <td><code>DoesAbs</code></td>\n        <td><code>__abs__</code></td>\n        <td>\n            <code>CanAbs[R]</code><br>\n            <code>CanAbsSelf</code>\n        </td>\n    </tr>\n</table>\n\n#### Rounding\n\nThe `round()` built-in function takes an optional second argument.\nFrom a typing perspective, `round()` has two overloads, one with 1 parameter,\nand one with two.\nFor both overloads, `optype` provides separate operand interfaces:\n`CanRound1[R]` and `CanRound2[T, RT]`.\nAdditionally, `optype` also provides their (overloaded) intersection type:\n`CanRound[T, R, RT] = CanRound1[R] & CanRound2[T, RT]`.\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>round(_)</code></td>\n        <td><code>do_round/1</code></td>\n        <td><code>DoesRound</code></td>\n        <td><code>__round__/1</code></td>\n        <td><code>CanRound1[T = int]</code><br/></td>\n    </tr>\n    <tr>\n        <td><code>round(_, n)</code></td>\n        <td><code>do_round/2</code></td>\n        <td><code>DoesRound</code></td>\n        <td><code>__round__/2</code></td>\n        <td><code>CanRound2[T = int, RT = float]</code><br/></td>\n    </tr>\n    <tr>\n        <td><code>round(_, n=...)</code></td>\n        <td><code>do_round</code></td>\n        <td><code>DoesRound</code></td>\n        <td><code>__round__</code></td>\n        <td><code>CanRound[T = int, R = int, RT = float]</code></td>\n    </tr>\n</table>\n\nFor example, type-checkers will mark the following code as valid (tested with\npyright in strict mode):\n\n```python\nx: float = 3.14\nx1: CanRound1[int] = x\nx2: CanRound2[int, float] = x\nx3: CanRound[int, int, float] = x\n```\n\nFurthermore, there are the alternative rounding functions from the\n[`math`][MATH] standard library:\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>math.trunc(_)</code></td>\n        <td><code>do_trunc</code></td>\n        <td><code>DoesTrunc</code></td>\n        <td><code>__trunc__</code></td>\n        <td><code>CanTrunc[R = int]</code></td>\n    </tr>\n    <tr>\n        <td><code>math.floor(_)</code></td>\n        <td><code>do_floor</code></td>\n        <td><code>DoesFloor</code></td>\n        <td><code>__floor__</code></td>\n        <td><code>CanFloor[R = int]</code></td>\n    </tr>\n    <tr>\n        <td><code>math.ceil(_)</code></td>\n        <td><code>do_ceil</code></td>\n        <td><code>DoesCeil</code></td>\n        <td><code>__ceil__</code></td>\n        <td><code>CanCeil[R = int]</code></td>\n    </tr>\n</table>\n\nAlmost all implementations use `int` for `R`.\nIn fact, if no type for `R` is specified, it will default in `int`.\nBut technially speaking, these methods can be made to return anything.\n\n[MATH]: https://docs.python.org/3/library/math.html\n[NT]: https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types\n\n#### Callables\n\nUnlike `operator`, `optype` provides the operator for callable objects:\n`optype.do_call(f, *args. **kwargs)`.\n\n`CanCall` is similar to `collections.abc.Callable`, but is runtime-checkable,\nand doesn't use esoteric hacks.\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>_(*args, **kwargs)</code></td>\n        <td><code>do_call</code></td>\n        <td><code>DoesCall</code></td>\n        <td><code>__call__</code></td>\n        <td><code>CanCall[**Pss, R]</code></td>\n    </tr>\n</table>\n\n> [!NOTE]\n> Pyright (and probably other typecheckers) tend to accept\n> `collections.abc.Callable` in more places than `optype.CanCall`.\n> This could be related to the lack of co/contra-variance specification for\n> `typing.ParamSpec` (they should almost always be contravariant, but\n> currently they can only be invariant).\n>\n> In case you encounter such a situation, please open an issue about it, so we\n> can investigate further.\n\n#### Iteration\n\nThe operand `x` of `iter(_)` is within Python known as an *iterable*, which is\nwhat `collections.abc.Iterable[V]` is often used for (e.g. as base class, or\nfor instance checking).\n\nThe `optype` analogue is `CanIter[R]`, which as the name suggests,\nalso implements `__iter__`. But unlike `Iterable[V]`, its type parameter `R`\nbinds to the return type of `iter(_) -> R`. This makes it possible to annotate\nthe specific type of the *iterable* that `iter(_)` returns. `Iterable[V]` is\nonly able to annotate the type of the iterated value. To see why that isn't\npossible, see [python/typing#548](https://github.com/python/typing/issues/548).\n\nThe `collections.abc.Iterator[V]` is even more awkward; it is a subtype of\n`Iterable[V]`. For those familiar with `collections.abc` this might come as a\nsurprise, but an iterator only needs to implement `__next__`, `__iter__` isn't\nneeded. This means that the `Iterator[V]` is unnecessarily restrictive.\nApart from that being theoretically \"ugly\", it has significant performance\nimplications, because the time-complexity of `isinstance` on a\n`typing.Protocol` is $O(n)$, with the $n$ referring to the amount of members.\nSo even if the overhead of the inheritance and the `abc.ABC` usage is ignored,\n`collections.abc.Iterator` is twice as slow as it needs to be.\n\nThat's one of the (many) reasons that `optype.CanNext[V]` and\n`optype.CanNext[V]` are the better alternatives to `Iterable` and `Iterator`\nfrom the abracadabra collections. This is how they are defined:\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>next(_)</code></td>\n        <td><code>do_next</code></td>\n        <td><code>DoesNext</code></td>\n        <td><code>__next__</code></td>\n        <td><code>CanNext[V]</code></td>\n    </tr>\n    <tr>\n        <td><code>iter(_)</code></td>\n        <td><code>do_iter</code></td>\n        <td><code>DoesIter</code></td>\n        <td><code>__iter__</code></td>\n        <td><code>CanIter[R: CanNext[object]]</code></td>\n    </tr>\n</table>\n\nFor the sake of compatibility with `collections.abc`, there is\n`optype.CanIterSelf[V]`, which is a protocol whose `__iter__` returns\n`typing.Self`, as well as a `__next__` method that returns `T`.\nI.e. it is equivalent to `collections.abc.Iterator[V]`, but without the `abc`\nnonsense.\n\n#### Awaitables\n\nThe `optype` is almost the same as `collections.abc.Awaitable[R]`, except\nthat `optype.CanAwait[R]` is a pure interface, whereas `Awaitable` is\nalso an abstract base class (making it absolutely useless when writing stubs).\n\n<table>\n    <tr>\n        <th align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>await _</code></td>\n        <td><code>__await__</code></td>\n        <td><code>CanAwait[R]</code></td>\n    </tr>\n</table>\n\n#### Async Iteration\n\nYes, you guessed it right; the abracadabra collections made the exact same\nmistakes for the async iterablors (or was it \"iteramblers\"...?).\n\nBut fret not; the `optype` alternatives are right here:\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>anext(_)</code></td>\n        <td><code>do_anext</code></td>\n        <td><code>DoesANext</code></td>\n        <td><code>__anext__</code></td>\n        <td><code>CanANext[V]</code></td>\n    </tr>\n    <tr>\n        <td><code>aiter(_)</code></td>\n        <td><code>do_aiter</code></td>\n        <td><code>DoesAIter</code></td>\n        <td><code>__aiter__</code></td>\n        <td><code>CanAIter[R: CanAnext[object]]</code></td>\n    </tr>\n</table>\n\nBut wait, shouldn't `V` be a `CanAwait`? Well, only if you don't want to get\nfired...\nTechnically speaking, `__anext__` can return any type, and `anext` will pass\nit along without nagging (instance checks are slow, now stop bothering that\nliberal). For details, see the discussion at [python/typeshed#7491][AN].\nJust because something is legal, doesn't mean it's a good idea (don't eat the\nyellow snow).\n\nAdditionally, there is `optype.CanAIterSelf[R]`, with both the\n`__aiter__() -> Self` and the `__anext__() -> V` methods.\n\n[AN]: https://github.com/python/typeshed/pull/7491\n\n#### Containers\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>len(_)</code></td>\n        <td><code>do_len</code></td>\n        <td><code>DoesLen</code></td>\n        <td><code>__len__</code></td>\n        <td><code>CanLen[R: int = int]</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>_.__length_hint__()</code>\n            (<a href=\"https://docs.python.org/3/reference/datamodel.html#object.__length_hint__\">docs</a>)\n        </td>\n        <td><code>do_length_hint</code></td>\n        <td><code>DoesLengthHint</code></td>\n        <td><code>__length_hint__</code></td>\n        <td><code>CanLengthHint[R: int = int]</code></td>\n    </tr>\n    <tr>\n        <td><code>_[k]</code></td>\n        <td><code>do_getitem</code></td>\n        <td><code>DoesGetitem</code></td>\n        <td><code>__getitem__</code></td>\n        <td><code>CanGetitem[K, V]</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>_.__missing__()</code>\n            (<a href=\"https://docs.python.org/3/reference/datamodel.html#object.__missing__\">docs</a>)\n        </td>\n        <td><code>do_missing</code></td>\n        <td><code>DoesMissing</code></td>\n        <td><code>__missing__</code></td>\n        <td><code>CanMissing[K, D]</code></td>\n    </tr>\n    <tr>\n        <td><code>_[k] = v</code></td>\n        <td><code>do_setitem</code></td>\n        <td><code>DoesSetitem</code></td>\n        <td><code>__setitem__</code></td>\n        <td><code>CanSetitem[K, V]</code></td>\n    </tr>\n    <tr>\n        <td><code>del _[k]</code></td>\n        <td><code>do_delitem</code></td>\n        <td><code>DoesDelitem</code></td>\n        <td><code>__delitem__</code></td>\n        <td><code>CanDelitem[K]</code></td>\n    </tr>\n    <tr>\n        <td><code>k in _</code></td>\n        <td><code>do_contains</code></td>\n        <td><code>DoesContains</code></td>\n        <td><code>__contains__</code></td>\n        <td><code>CanContains[K = object]</code></td>\n    </tr>\n    <tr>\n        <td><code>reversed(_)</code></td>\n        <td><code>do_reversed</code></td></td>\n        <td><code>DoesReversed</code></td>\n        <td><code>__reversed__</code></td>\n        <td>\n            <code>CanReversed[R]</code>, or<br>\n            <code>CanSequence[I, V, N = int]</code>\n        </td>\n    </tr>\n</table>\n\nBecause `CanMissing[K, D]` generally doesn't show itself without\n`CanGetitem[K, V]` there to hold its hand, `optype` conveniently stitched them\ntogether as `optype.CanGetMissing[K, V, D=V]`.\n\nSimilarly, there is `optype.CanSequence[K: CanIndex | slice, V]`, which is the\ncombination of both `CanLen` and `CanItem[I, V]`, and serves as a more\nspecific and flexible `collections.abc.Sequence[V]`.\n\n#### Attributes\n\n<table>\n    <tr>\n        <th colspan=\"3\" align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <th>function</th>\n        <th>type</th>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td>\n            <code>v = _.k</code> or<br/>\n            <code>v = getattr(_, k)</code>\n        </td>\n        <td><code>do_getattr</code></td>\n        <td><code>DoesGetattr</code></td>\n        <td><code>__getattr__</code></td>\n        <td><code>CanGetattr[K: str = str, V = object]</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>_.k = v</code> or<br/>\n            <code>setattr(_, k, v)</code>\n        </td>\n        <td><code>do_setattr</code></td>\n        <td><code>DoesSetattr</code></td>\n        <td><code>__setattr__</code></td>\n        <td><code>CanSetattr[K: str = str, V = object]</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>del _.k</code> or<br/>\n            <code>delattr(_, k)</code>\n        </td>\n        <td><code>do_delattr</code></td>\n        <td><code>DoesDelattr</code></td>\n        <td><code>__delattr__</code></td>\n        <td><code>CanDelattr[K: str = str]</code></td>\n    </tr>\n    <tr>\n        <td><code>dir(_)</code></td>\n        <td><code>do_dir</code></td>\n        <td><code>DoesDir</code></td>\n        <td><code>__dir__</code></td>\n        <td><code>CanDir[R: CanIter[CanIterSelf[str]]]</code></td>\n    </tr>\n</table>\n\n#### Context managers\n\nSupport for the `with` statement.\n\n<table>\n    <tr>\n        <th align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <td>method(s)</td>\n        <th>type(s)</th>\n    </tr>\n    <tr>\n        <td></td>\n        <td><code>__enter__</code></td>\n        <td>\n            <code>CanEnter[C]</code>, or\n            <code>CanEnterSelf</code>\n        </td>\n    </tr>\n    <tr>\n        <td></td>\n        <td><code>__exit__</code></td>\n        <td>\n            <code>CanExit[R = None]</code>\n        </td>\n    </tr>\n    <tr>\n        <td><code>with _ as c:</code></td>\n        <td>\n            <code>__enter__</code>, and <br>\n            <code>__exit__</code>\n        </td>\n        <td>\n            <code>CanWith[C, R=None]</code>, or<br>\n            <code>CanWithSelf[R=None]</code>\n        </td>\n    </tr>\n</table>\n\n`CanEnterSelf` and `CanWithSelf` are (runtime-checkable) aliases for\n`CanEnter[Self]` and `CanWith[Self, R]`, respectively.\n\nFor the `async with` statement the interfaces look very similar:\n\n<table>\n    <tr>\n        <th align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <td>method(s)</td>\n        <th>type(s)</th>\n    </tr>\n    <tr>\n        <td></td>\n        <td><code>__aenter__</code></td>\n        <td>\n            <code>CanAEnter[C]</code>, or<br>\n            <code>CanAEnterSelf</code>\n        </td>\n    </tr>\n    <tr>\n        <td></td>\n        <td><code>__aexit__</code></td>\n        <td><code>CanAExit[R=None]</code></td>\n    </tr>\n    <tr>\n        <td><code>async with _ as c:</code></td>\n        <td>\n            <code>__aenter__</code>, and<br>\n            <code>__aexit__</code>\n        </td>\n        <td>\n            <code>CanAsyncWith[C, R=None]</code>, or<br>\n            <code>CanAsyncWithSelf[R=None]</code>\n        </td>\n    </tr>\n</table>\n\n#### Descriptors\n\nInterfaces for [descriptors](https://docs.python.org/3/howto/descriptor.html).\n\n<table>\n    <tr>\n        <th align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td>\n            <code>v: V = T().d</code><br/>\n            <code>vt: VT = T.d</code>\n        </td>\n        <td><code>__get__</code></td>\n        <td><code>CanGet[T: object, V, VT = V]</code></td>\n    </tr>\n    <tr>\n        <td><code>T().k = v</code></td>\n        <td><code>__set__</code></td>\n        <td><code>CanSet[T: object, V]</code></td>\n    </tr>\n    <tr>\n        <td><code>del T().k</code></td>\n        <td><code>__delete__</code></td>\n        <td><code>CanDelete[T: object]</code></td>\n    </tr>\n    <tr>\n        <td><code>class T: d = _</code></td>\n        <td><code>__set_name__</code></td>\n        <td><code>CanSetName[T: object, N: str = str]</code></td>\n    </tr>\n</table>\n\n#### Buffer types\n\nInterfaces for emulating buffer types using the [buffer protocol][BP].\n\n<table>\n    <tr>\n        <th align=\"center\">operator</th>\n        <th colspan=\"2\" align=\"center\">operand</th>\n    </tr>\n    <tr>\n        <td>expression</td>\n        <td>method</td>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>v = memoryview(_)</code></td>\n        <td><code>__buffer__</code></td>\n        <td><code>CanBuffer[T: int = int]</code></td>\n    </tr>\n    <tr>\n        <td><code>del v</code></td>\n        <td><code>__release_buffer__</code></td>\n        <td><code>CanReleaseBuffer</code></td>\n    </tr>\n</table>\n\n[BP]: https://docs.python.org/3/reference/datamodel.html#python-buffer-protocol\n\n### `optype.copy`\n\nFor the [`copy`][CP] standard library, `optype.copy` provides the following\nruntime-checkable interfaces:\n\n<table>\n    <tr>\n        <th align=\"center\"><code>copy</code> standard library</th>\n        <th colspan=\"2\" align=\"center\"><code>optype.copy</code></th>\n    </tr>\n    <tr>\n        <td>function</td>\n        <th>type</th>\n        <th>method</th>\n    </tr>\n    <tr>\n        <td><code>copy.copy(_) -> R</code></td>\n        <td><code>__copy__() -> R</code></td>\n        <td><code>CanCopy[R]</code></td>\n    </tr>\n    <tr>\n        <td><code>copy.deepcopy(_, memo={}) -> R</code></td>\n        <td><code>__deepcopy__(memo, /) -> R</code></td>\n        <td><code>CanDeepcopy[R]</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>copy.replace(_, /, **changes: V) -> R</code>\n            <sup>[1]</sup>\n        </td>\n        <td><code>__replace__(**changes: V) -> R</code></td>\n        <td><code>CanReplace[V, R]</code></td>\n    </tr>\n</table>\n\n<sup>[1]</sup> *`copy.replace` requires `python>=3.13`\n(but `optype.copy.CanReplace` doesn't)*\n\nIn practice, it makes sense that a copy of an instance is the same type as the\noriginal.\nBut because `typing.Self` cannot be used as a type argument, this difficult\nto properly type.\nInstead, you can use the `optype.copy.Can{}Self` types, which are the\nruntime-checkable equivalents of the following (recursive) type aliases:\n\n```python\ntype CanCopySelf = CanCopy[CanCopySelf]\ntype CanDeepcopySelf = CanDeepcopy[CanDeepcopySelf]\ntype CanReplaceSelf[V] = CanReplace[V, CanReplaceSelf[V]]\n```\n\n[CP]: https://docs.python.org/3/library/copy.html\n\n### `optype.dataclasses`\n\nFor the [`dataclasses`][DC] standard library, `optype.dataclasses` provides the\n`HasDataclassFields[V: Mapping[str, Field]]` interface.\nIt can conveniently be used to check whether a type or instance is a\ndataclass, i.e. `isinstance(obj, HasDataclassFields)`.\n\n[DC]: https://docs.python.org/3/library/dataclasses.html\n\n### `optype.inspect`\n\nA collection of functions for runtime inspection of types, modules, and other\nobjects.\n\n<table width=\"415px\">\n    <tr>\n        <th>Function</th>\n        <th>Description</th>\n    </tr>\n        <tr>\n        <td><code>get_args(_)</code></td>\n<td>\n\nA better alternative to [`typing.get_args()`][GET_ARGS], that\n\n- unpacks `typing.Annotated` and Python 3.12 `type _` alias types\n  (i.e. `typing.TypeAliasType`),\n- recursively flattens unions and nested `typing.Literal` types, and\n- raises `TypeError` if not a type expression.\n\nReturn a `tuple[type | object, ...]` of type arguments or parameters.\n\nTo illustrate one of the (many) issues with `typing.get_args`:\n\n```pycon\n>>> from typing import Literal, TypeAlias, get_args\n>>> Falsy: TypeAlias = Literal[None] | Literal[False, 0] | Literal[\"\", b\"\"]\n>>> get_args(Falsy)\n(typing.Literal[None], typing.Literal[False, 0], typing.Literal['', b''])\n```\n\nBut this is in direct contradiction with the\n[official typing documentation][LITERAL-DOCS]:\n\n> When a Literal is parameterized with more than one value, it\u2019s treated as\n> exactly equivalent to the union of those types.\n> That is, `Literal[v1, v2, v3]` is equivalent to\n> `Literal[v1] | Literal[v2] | Literal[v3]`.\n\nSo this is why `optype.inspect.get_args` should be used\n\n```pycon\n>>> import optype as opt\n>>> opt.inspect.get_args(Falsy)\n(None, False, 0, '', b'')\n```\n\nAnother issue of `typing.get_args` is with Python 3.12 `type _ = ...` aliases,\nwhich are meant as a replacement for `_: typing.TypeAlias = ...`, and should\ntherefore be treated equally:\n\n```pycon\n>>> import typing\n>>> import optype as opt\n>>> type StringLike = str | bytes\n>>> typing.get_args(StringLike)\n()\n>>> opt.inspect.get_args(StringLike)\n(<class 'str'>, <class 'bytes'>)\n```\n\nClearly, `typing.get_args` fails misarably here; it would have been better\nif it would have raised an error, but it instead returns an empty tuple,\nhiding the fact that it doesn't support the new `type _ = ...` aliases.\nBut luckily, `optype.inspect.get_args` doesn't have this problem, and treats\nit just like it treats `typing.Alias` (and so do the other `optype.inspect`\nfunctions).\n\n</td>\n    </tr>\n    <tr>\n        <td><code>get_protocol_members(_)</code></td>\n<td>\n\nA better alternative to [`typing.get_protocol_members()`][PROTO_MEM], that\n\n- doesn't require Python 3.13 or above,\n- supports [PEP 695][PEP695] `type _` alias types on Python 3.12 and above,\n- unpacks unions of `typing.Literal` ...\n- ... and flattens them if nested within another `typing.Literal`,\n- treats `typing.Annotated[T]` as `T`, and\n- raises a `TypeError` if the passed value isn't a type expression.\n\nReturns a `frozenset[str]` with member names.\n\n</td>\n    </tr>\n    <tr>\n        <td><code>get_protocols(_)</code></td>\n<td>\n\nReturns a `frozenset[type]` of the public protocols within the passed module.\nPass `private=True` to also return the private protocols.\n\n</td>\n    </tr>\n    <tr>\n        <td><code>is_iterable(_)</code></td>\n<td>\n\nCheck whether the object can be iterated over, i.e. if it can be used in a\n`for` loop, without attempting to do so.\nIf `True` is returned, then the object is a `optype.typing.AnyIterable`\ninstance.\n\n</td>\n    </tr>\n    <tr>\n        <td><code>is_final(_)</code></td>\n<td>\n\nCheck if the type, method / classmethod / staticmethod / property, is\ndecorated with [`@typing.final`][@FINAL].\n\nNote that a `@property` won't be recognized unless the `@final` decorator is\nplaced *below* the `@property` decorator.\nSee the function docstring for more information.\n\n</td>\n    </tr>\n    <tr>\n        <td><code>is_protocol(_)</code></td>\n<td>\n\nA backport of [`typing.is_protocol`][IS_PROTO] that was added in Python 3.13,\na re-export of [`typing_extensions.is_protocol`][IS_PROTO_EXT].\n\n</td>\n    </tr>\n    <tr>\n        <td><code>is_runtime_protocol(_)</code></td>\n<td>\n\nCheck if the type expression is a *runtime-protocol*, i.e. a\n`typing.Protocol` *type*, decorated with `@typing.runtime_checkable` (also\nsupports `typing_extensions`).\n\n</td>\n    </tr>\n    <tr>\n        <td><code>is_union_type(_)</code></td>\n<td>\n\nCheck if the type is a [`typing.Union`][UNION] type, e.g. `str | int`.\n\nUnlike `isinstance(_, types.Union)`, this function also returns `True` for\nunions of user-defined `Generic` or `Protocol` types (because those are\ndifferent union types for some reason).\n\n</td>\n    </tr>\n    <tr>\n        <td><code>is_generic_alias(_)</code></td>\n<td>\n\nCheck if the type is a *subscripted* type, e.g. `list[str]` or\n`optype.CanNext[int]`, but not `list`, `CanNext`.\n\nUnlike `isinstance(_, typing.GenericAlias)`, this function also returns `True`\nfor user-defined `Generic` or `Protocol` types (because those are\nuse a different generic alias for some reason).\n\nEven though technically `T1 | T2` is represented as `typing.Union[T1, T2]`\n(which is a (special) generic alias), `is_generic_alias` will returns `False`\nfor such union types, because calling `T1 | T2` a subscripted type just\ndoesn't make much sense.\n\n</td>\n    </tr>\n</table>\n\n> [!NOTE]\n> All functions in `optype.inspect` also work for Python 3.12 `type _` aliases\n> (i.e. `types.TypeAliasType`) and with `typing.Annotated`.\n\n[UNION]: https://docs.python.org/3/library/typing.html#typing.Union\n[LITERAL-DOCS]: https://typing.readthedocs.io/en/latest/spec/literal.html#shortening-unions-of-literals\n[@FINAL]: https://docs.python.org/3/library/typing.html#typing.Literal\n[GET_ARGS]: https://docs.python.org/3/library/typing.html#typing.get_args\n[IS_PROTO]: https://docs.python.org/3.13/library/typing.html#typing.is_protocol\n[IS_PROTO_EXT]: https://typing-extensions.readthedocs.io/en/latest/#typing_extensions.is_protocol\n[PROTO_MEM]: https://docs.python.org/3.13/library/typing.html#typing.get_protocol_members\n\n### `optype.json`\n\nType aliases for the `json` standard library:\n\n<table>\n    <tr>\n        <td><code>Value</code></td>\n        <td><code>AnyValue</code></td>\n    </tr>\n    <tr>\n        <th><code>json.load(s)</code> return type</th>\n        <th><code>json.dumps(s)</code> input type</th>\n    </tr>\n    <tr>\n        <td><code>Array[V: Value = Value]</code></td>\n        <td><code>AnyArray[V: AnyValue = AnyValue]</code></td>\n    </tr>\n    <tr>\n        <td><code>Object[V: Value = Value]</code></td>\n        <td><code>AnyObject[V: AnyValue = AnyValue]</code></td>\n    </tr>\n</table>\n\nThe `(Any)Value` can be any json input, i.e. `Value | Array | Object` is\nequivalent to `Value`.\nIt's also worth noting that `Value` is a subtype of `AnyValue`, which means\nthat `AnyValue | Value` is equivalent to `AnyValue`.\n\n### `optype.pickle`\n\nFor the [`pickle`][PK] standard library, `optype.pickle` provides the following\ninterfaces:\n\n[PK]: https://docs.python.org/3/library/pickle.html\n\n<table>\n    <tr>\n        <th>method(s)</th>\n        <th>signature (bound)</th>\n        <th>type</th>\n    </tr>\n    <tr>\n        <td><code>__reduce__</code></td>\n        <td><code>() -> R</code></td>\n        <td><code>CanReduce[R: str | tuple = ...]</code></td>\n    </tr>\n    <tr>\n        <td><code>__reduce_ex__</code></td>\n        <td><code>(CanIndex) -> R</code></td>\n        <td><code>CanReduceEx[R: str | tuple = ...]</code></td>\n    </tr>\n    <tr>\n        <td><code>__getstate__</code></td>\n        <td><code>() -> S</code></td>\n        <td><code>CanGetstate[S]</code></td>\n    </tr>\n    <tr>\n        <td><code>__setstate__</code></td>\n        <td><code>(S) -> None</code></td>\n        <td><code>CanSetstate[S]</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>__getnewargs__</code><br>\n            <code>__new__</code>\n        </td>\n        <td>\n            <code>() -> tuple[V, ...]</code><br>\n            <code>(V) -> Self</code><br>\n        </td>\n        <td><code>CanGetnewargs[V]</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>__getnewargs_ex__</code><br>\n            <code>__new__</code>\n        </td>\n        <td>\n            <code>() -> tuple[tuple[V, ...], dict[str, KV]]</code><br>\n            <code>(*tuple[V, ...], **dict[str, KV]) -> Self</code><br>\n        </td>\n        <td><code>CanGetnewargsEx[V, KV]</code></td>\n    </tr>\n</table>\n\n### `optype.string`\n\nThe [`string`](https://docs.python.org/3/library/string.html) standard\nlibrary contains practical constants, but it has two issues:\n\n- The constants contain a collection of characters, but are represented as\n  a single string. This makes it practically impossible to type-hint the\n  individual characters, so typeshed currently types these constants as a\n  `LiteralString`.\n- The names of the constants are inconsistent, and doesn't follow\n  [PEP 8](https://peps.python.org/pep-0008/#constants).\n\nSo instead, `optype.string` provides an alternative interface, that is\ncompatible with `string`, but with slight differences:\n\n- For each constant, there is a corresponding `Literal` type alias for\n  the *individual* characters. Its name matches the name of the constant,\n  but is singular instead of plural.\n- Instead of a single string, `optype.string` uses a `tuple` of characters,\n  so that each character has its own `typing.Literal` annotation.\n  Note that this is only tested with (based)pyright / pylance, so it might\n  not work with mypy (it has more bugs than it has lines of codes).\n- The names of the constant are consistent with PEP 8, and use a postfix\n  notation for variants, e.g. `DIGITS_HEX` instead of `hexdigits`.\n- Unlike `string`, `optype.string` has a constant (and type alias) for\n  binary digits `'0'` and `'1'`; `DIGITS_BIN` (and `DigitBin`). Because\n  besides `oct` and `hex` functions in `builtins`, there's also the\n  `builtins.bin` function.\n\n<table>\n    <tr>\n        <th colspan=\"2\"><code>string._</code></th>\n        <th colspan=\"2\"><code>optype.string._</code></th>\n    </tr>\n    <tr>\n        <th>constant</th>\n        <th>char type</th>\n        <th>constant</th>\n        <th>char type</th>\n    </tr>\n    <tr>\n        <td colspan=\"2\" align=\"center\"><i>missing</i></td>\n        <td><code>DIGITS_BIN</code></td>\n        <td><code>DigitBin</code></td>\n    </tr>\n    <tr>\n        <td><code>octdigits</code></td>\n        <td rowspan=\"9\"><code>LiteralString</code></td>\n        <td><code>DIGITS_OCT</code></td>\n        <td><code>DigitOct</code></td>\n    </tr>\n    <tr>\n        <td><code>digits</code></td>\n        <td><code>DIGITS</code></td>\n        <td><code>Digit</code></td>\n    </tr>\n    <tr>\n        <td><code>hexdigits</code></td>\n        <td><code>DIGITS_HEX</code></td>\n        <td><code>DigitHex</code></td>\n    </tr>\n    <tr>\n        <td><code>ascii_letters</code></td>\n        <td><code>LETTERS</code></td>\n        <td><code>Letter</code></td>\n    </tr>\n    <tr>\n        <td><code>ascii_lowercase</code></td>\n        <td><code>LETTERS_LOWER</code></td>\n        <td><code>LetterLower</code></td>\n    </tr>\n    <tr>\n        <td><code>ascii_uppercase</code></td>\n        <td><code>LETTERS_UPPER</code></td>\n        <td><code>LetterUpper</code></td>\n    </tr>\n    <tr>\n        <td><code>punctuation</code></td>\n        <td><code>PUNCTUATION</code></td>\n        <td><code>Punctuation</code></td>\n    </tr>\n    <tr>\n        <td><code>whitespace</code></td>\n        <td><code>WHITESPACE</code></td>\n        <td><code>Whitespace</code></td>\n    </tr>\n    <tr>\n        <td><code>printable</code></td>\n        <td><code>PRINTABLE</code></td>\n        <td><code>Printable</code></td>\n    </tr>\n</table>\n\nEach of the `optype.string` constants is exactly the same as the corresponding\n`string` constant (after concatenation / splitting), e.g.\n\n```pycon\n>>> import string\n>>> import optype as opt\n>>> \"\".join(opt.string.PRINTABLE) == string.printable\nTrue\n>>> tuple(string.printable) == opt.string.PRINTABLE\nTrue\n```\n\nSimilarly, the values within a constant's `Literal` type exactly match the\nvalues of its constant:\n\n```pycon\n>>> import optype as opt\n>>> from optype.inspect import get_args\n>>> get_args(opt.string.Printable) == opt.string.PRINTABLE\nTrue\n```\n\nThe `optype.inspect.get_args` is a non-broken variant of `typing.get_args`\nthat correctly flattens nested literals, type-unions, and PEP 695 type aliases,\nso that it matches the official typing specs.\n*In other words; `typing.get_args` is yet another fundamentally broken\npython-typing feature that's useless in the situations where you need it\nmost.*\n\n### `optype.typing`\n\n#### `Any*` type aliases\n\nType aliases for anything that can *always* be passed to\n`int`, `float`, `complex`, `iter`, or `typing.Literal`\n\n<table>\n    <tr>\n        <th>Python constructor</th>\n        <th><code>optype.typing</code> alias</th>\n    </tr>\n    <tr>\n        <td><code>int(_)</code></td>\n        <td><code>AnyInt</code></td>\n    </tr>\n    <tr>\n        <td><code>float(_)</code></td>\n        <td><code>AnyFloat</code></td>\n    </tr>\n    <tr>\n        <td><code>complex(_)</code></td>\n        <td><code>AnyComplex</code></td>\n    </tr>\n    <tr>\n        <td><code>iter(_)</code></td>\n        <td><code>AnyIterable</code></td>\n    </tr>\n    <tr>\n        <td><code>typing.Literal[_]</code></td>\n        <td><code>AnyLiteral</code></td>\n    </tr>\n</table>\n\n> [!NOTE]\n> Even though *some* `str` and `bytes` can be converted to `int`, `float`,\n> `complex`, most of them can't, and are therefore not included in these\n> type aliases.\n\n#### `Empty*` type aliases\n\nThese are builtin types or collections that are empty, i.e. have length 0 or\nyield no elements.\n\n<table>\n    <tr>\n        <th>instance</th>\n        <th><code>optype.typing</code> type</th>\n    </tr>\n    <tr>\n        <td><code>''</code></td>\n        <td><code>EmptyString</code></td>\n    </tr>\n    <tr>\n        <td><code>b''</code></td>\n        <td><code>EmptyBytes</code></td>\n    </tr>\n    <tr>\n        <td><code>()</code></td>\n        <td><code>EmptyTuple</code></td>\n    </tr>\n    <tr>\n        <td><code>[]</code></td>\n        <td><code>EmptyList</code></td>\n    </tr>\n    <tr>\n        <td><code>{}</code></td>\n        <td><code>EmptyDict</code></td>\n    </tr>\n    <tr>\n        <td><code>set()</code></td>\n        <td><code>EmptySet</code></td>\n    </tr>\n    <tr>\n        <td><code>(i for i in range(0))</code></td>\n        <td><code>EmptyIterable</code></td>\n    </tr>\n</table>\n\n#### Literal types\n\n<table>\n    <tr>\n        <th>Literal values</th>\n        <th><code>optype.typing</code> type</th>\n        <th>Notes</th>\n    </tr>\n    <tr>\n        <td><code>{False, True}</code></td>\n        <td><code>LiteralFalse</code></td>\n        <td>\n            Similar to <code>typing.LiteralString</code>, but for\n            <code>bool</code>.\n        </td>\n    </tr>\n    <tr>\n        <td><code>{0, 1, ..., 255}</code></td>\n        <td><code>LiteralByte</code></td>\n        <td>\n            Integers in the range 0-255, that make up a <code>bytes</code>\n            or <code>bytearray</code> objects.\n        </td>\n    </tr>\n</table>\n\n#### `Just` types\n\n> [!WARNING]\n> This is experimental, and is likely to change in the future.\n\nThe `JustInt` type can be used to *only* accept instances of type `int`. Subtypes\nlike `bool` will be rejected. This works with recent versions of mypy and pyright.\n\n```pyi\nimport optype.typing as opt\n\ndef only_int_pls(x: opt.JustInt, /) -> None: ...\n\nf(42)  # accepted\nf(True)  # rejected\n```\n\nThe `Just` type is a generic variant of `JustInt`. At the moment of writing, pyright\ndoesn't support this yet, but it will soon (after the bundled typeshed is updated).\n\n```pyi\nimport optype.typing as opt\n\nclass A: ...\nclass B(A): ...\n\ndef must_have_type_a(a: opt.Just[A]) -> None: ...\n\nmust_have_type_a(A())  # accepted\nmust_have_type_a(B())  # rejected (at least with mypy)\n```\n\n### `optype.dlpack`\n\nA collection of low-level types for working [DLPack](DOC-DLPACK).\n\n#### Protocols\n\n<table>\n    <tr>\n        <th>type signature</th>\n        <th>bound method</th>\n    </tr>\n    <tr>\n<td>\n\n```plain\nCanDLPack[\n    +T = int,\n    +D: int = int,\n]\n```\n\n</td>\n<td>\n\n```python\ndef __dlpack__(\n    *,\n    stream: int | None = ...,\n    max_version: tuple[int, int] | None = ...,\n    dl_device: tuple[T, D] | None = ...,\n    copy: bool | None = ...,\n) -> types.CapsuleType: ...\n```\n\n</td>\n    </tr>\n    <tr></tr>\n    <tr>\n<td>\n\n```plain\nCanDLPackDevice[\n    +T = int,\n    +D: int = int,\n]\n```\n\n</td>\n<td>\n\n```python\ndef __dlpack_device__() -> tuple[T, D]: ...\n```\n\n</td>\n    </tr>\n</table>\n\nThe `+` prefix indicates that the type parameter is *co*variant.\n\n#### Enums\n\nThere are also two convenient\n[`IntEnum`](https://docs.python.org/3/library/enum.html#enum.IntEnum)s\nin `optype.dlpack`: `DLDeviceType` for the device types, and `DLDataTypeCode` for the\ninternal type-codes of the `DLPack` data types.\n\n<table>\n\n### `optype.numpy`\n\nOptype supports both NumPy 1 and 2.\nThe current minimum supported version is `1.24`,\nfollowing [NEP 29][NEP29] and [SPEC 0][SPEC0].\n\nWhen using `optype.numpy`, it is recommended to install `optype` with the\n`numpy` extra, ensuring version compatibility:\n\n```shell\npip install \"optype[numpy]\"\n```\n\n> [!NOTE]\n> For the remainder of the `optype.numpy` docs, assume that the following\n> import aliases are available.\n>\n> ```python\n> from typing import Any, Literal\n> import numpy as np\n> import numpy.typing as npt\n> import optype.numpy as onp\n> ```\n>\n> For the sake of brevity and readability, the [PEP 695][PEP695] and\n> [PEP 696][PEP696] type parameter syntax will be used, which is supported\n> since Python 3.13.\n\n#### Shape-typing with `Array`\n\nOptype provides the generic `onp.Array` type alias for `np.ndarray`.\nIt is similar to `npt.NDArray`, but includes two (optional) type parameters:\none that matches the *shape type* (`ND: tuple[int, ...]`),\nand one that matches the *scalar type* (`ST: np.generic`).\n\nWhen put the definitions of `npt.NDArray` and `onp.Array` side-by-side,\ntheir differences become clear:\n\n<table>\n<tr>\n<th>\n\n`numpy.typing.NDArray`[^1]\n\n</th>\n<th>\n\n`optype.numpy.Array`\n\n</th>\n<th>\n\n`optype.numpy.ArrayND`\n\n</th>\n</tr>\n<tr>\n<td>\n\n```python\ntype NDArray[\n    # no shape type\n    ST: generic,  # no default\n] = ndarray[Any, dtype[ST]]\n```\n\n</td>\n<td>\n\n```python\ntype Array[\n    ND: (int, ...) = (int, ...),\n    ST: generic = generic,\n] = ndarray[ND, dtype[ST]]\n```\n\n</td>\n<td>\n\n```python\ntype ArrayND[\n    ST: generic = generic,\n    ND: (int, ...) = (int, ...),\n] = ndarray[ND, dtype[ST]]\n```\n\n</td>\n</tr>\n</table>\n\nAdditionally, there are the three `Array{0,1,2,3}D[ST: generic]` aliases, which are\nequivalent to `Array` with `tuple[()]`, `tuple[int]`, `tuple[int, int]` and\n`tuple[int, int, int]` as shape-type, respectively.\n\n[^1]: Since `numpy>=2.2` the `NDArray` alias uses `tuple[int, ...]` as shape-type\n    instead of `Any`.\n\n> [!TIP]\n> Before NumPy 2.1, the shape type parameter of `ndarray` (i.e. the type of\n> `ndarray.shape`) was invariant. It is therefore recommended to not use `Literal`\n> within shape types on `numpy<2.1`. So with `numpy>=2.1` you can use\n> `tuple[Literal[3], Literal[3]]` without problem, but with `numpy<2.1` you should use\n> `tuple[int, int]` instead.\n>\n> See [numpy/numpy#25729](https://github.com/numpy/numpy/issues/25729) and\n> [numpy/numpy#26081](https://github.com/numpy/numpy/pull/26081) for details.\n\nWith `onp.Array`, it becomes possible to type the *shape* of arrays.\n\nA *shape* is nothing more than a tuple of (non-negative) integers, i.e.\nan instance of `tuple[int, ...]` such as `(42,)`, `(480, 720, 3)` or `()`.\nThe length of a shape is often referred to as the *number of dimensions*\nor the *dimensionality* of the array or scalar.\nFor arrays this is accessible through the `np.ndarray.ndim`, which is\nan alias for `len(np.ndarray.shape)`.\n\n> [!NOTE]\n> Before NumPy 2, the maximum number of dimensions was `32`, but has since\n> been increased to `ndim <= 64`.\n\nTo make typing the shape of an array easier, optype provides two families of\nshape type aliases: `AtLeast{N}D` and `AtMost{N}D`.\nThe `{N}` should be replaced by the number of dimensions, which currently\nis limited to `0`, `1`, `2`, and `3`.\n\nBoth of these families are generic, and their (optional) type parameters must\nbe either `int` (default), or a literal (non-negative) integer, i.e. like\n`typing.Literal[N: int]`.\n\nThe names `AtLeast{N}D` and `AtMost{N}D` are pretty much as self-explanatory:\n\n- `AtLeast{N}D` is a `tuple[int, ...]` with `ndim >= N`\n- `AtMost{N}D` is a `tuple[int, ...]` with `ndim <= N`\n\nThe shape aliases are roughly defined as:\n\n<table>\n<tr>\n<th align=\"center\" colspan=\"2\"><code>AtLeast{N}D</code></th>\n<th align=\"center\" colspan=\"2\"><code>AtMost{N}D</code></th>\n</tr>\n<tr>\n<th>type signature</th>\n<th>alias type</th>\n<th>type signature</th>\n<th>type alias</th>\n</tr>\n<tr>\n<td colspan=\"4\"></td>\n</tr>\n<tr>\n<td>\n\n```python\ntype AtLeast0D[\n    Ds: int = int,\n] = _\n```\n\n</td>\n<td>\n\n```python\ntuple[Ds, ...]\n```\n\n</td>\n<td>\n\n```python\ntype AtMost0D = _\n```\n\n</td>\n<td>\n\n```python\ntuple[()]\n```\n\n</td>\n</tr>\n<tr><td colspan=\"4\"></td></tr>\n<tr>\n<td>\n\n```python\ntype AtLeast1D[\n    D0: int = int,\n    Ds: int = int,\n] = _\n```\n\n</td>\n<td>\n\n```python\ntuple[\n    D0,\n    *tuple[Ds, ...],\n]\n```\n\n</td>\n<td>\n\n```python\ntype AtMost1D[\n    D0: int = int,\n] = _\n```\n\n</td>\n<td>\n\n```python\ntuple[D0] | AtMost0D\n```\n\n</td>\n</tr>\n<tr><td colspan=\"4\"></td></tr>\n<tr>\n<td>\n\n```python\ntype AtLeast2D[\n    D0: int = int,\n    D1: int = int,\n    Ds: int = int,\n] = _\n```\n\n</td>\n<td>\n\n```python\ntuple[\n    D0,\n    D1,\n    *tuple[Ds, ...],\n]\n```\n\n</td>\n<td>\n\n```python\ntype AtMost2D[\n    D0: int = int,\n    D1: int = int,\n] = _\n```\n\n</td>\n<td>\n\n<!-- blacken-docs:off -->\n```python\n(\n    tuple[D0, D1]\n    | AtMost1D[D0]\n)\n```\n<!-- blacken-docs:on -->\n\n</td>\n</tr>\n<tr><td colspan=\"4\"></td></tr>\n<tr>\n<td>\n\n```python\ntype AtLeast3D[\n    D0: int = int,\n    D1: int = int,\n    D2: int = int,\n    Ds: int = int,\n] = _\n```\n\n</td>\n<td>\n\n```python\ntuple[\n    D0,\n    D1,\n    D2,\n    *tuple[Ds, ...],\n]\n```\n\n</td>\n<td>\n\n```python\ntype AtMost3D[\n    D0: int = int,\n    D1: int = int,\n    D2: int = int,\n] = _\n```\n\n</td>\n<td>\n\n<!-- blacken-docs:off -->\n```python\n(\n    tuple[D0, D1, D2]\n    | AtMost2D[D0, D1]\n)\n```\n<!-- blacken-docs:on -->\n\n</td>\n</tr>\n</table>\n\n#### Array-likes\n\nSimilar to the `numpy._typing._ArrayLike{}_co` *coercible array-like* types,\n`optype.numpy` provides the `optype.numpy.To{}ND`. Unlike the ones in `numpy`, these\ndon't accept \"bare\" scalar types (the `__len__` method is required).\nAdditionally, there are the `To{}1D`, `To{}2D`, and `To{}3D` for vector-likes,\nmatrix-likes, and cuboid-likes, and the `To{}` aliases for \"bare\" scalar types.\n\n<table>\n<tr>\n    <th align=\"center\" colspan=\"2\">scalar types</th>\n    <th align=\"center\">scalar-like</th>\n    <th align=\"center\"><code>{1,2,3}</code>-d array-like</th>\n    <th align=\"center\"><code>*</code>-d array-like</th>\n</tr>\n<tr>\n    <th align=\"left\">\n        <code>builtins</code> /<br>\n        <a href=\"#optypetyping\"><code>optype.typing</code></a>\n    </th>\n    <th align=\"left\"><code>numpy</code></th>\n    <th align=\"center\" colspan=\"4\"><code>optype.numpy</code></th>\n</tr>\n<tr><td colspan=\"5\"></td></tr>\n<tr>\n    <td align=\"left\"><code>bool</code></td>\n    <td align=\"left\"><code>bool_</code></td>\n    <td align=\"left\"><code>ToBool</code></td>\n    <td align=\"left\"><code>ToBool[strict]{1,2,3}D</code></td>\n    <td align=\"left\"><code>ToBoolND</code></td>\n</tr>\n<tr><td colspan=\"6\"></td></tr>\n<tr>\n    <td align=\"left\">\n        <a href=\"#just-types\"><code>JustInt</code><a>\n    </td>\n    <td align=\"left\">\n        <code>integer</code>\n    </td>\n    <td align=\"left\"><code>ToJustInt</code></td>\n    <td align=\"left\"><code>ToJustInt[strict]{1,2,3}D</code></td>\n    <td align=\"left\"><code>ToJustIntND</code></td>\n</tr>\n<tr><td colspan=\"6\"></td></tr>\n<tr>\n    <td align=\"left\"><code>int</code></td>\n    <td align=\"left\">\n        <code>integer</code><br>\n        <code>| bool_</code>\n    </td>\n    <td align=\"left\"><code>ToInt</code></td>\n    <td align=\"left\"><code>ToInt[strict]{1,2,3}D</code></td>\n    <td align=\"left\"><code>ToIntND</code></td>\n</tr>\n<tr><td colspan=\"6\"></td></tr>\n<tr>\n    <td align=\"left\">\n        <code>float</code><br>\n        <code>| int</code>\n    </td>\n    <td align=\"left\">\n        <code>floating</code><br>\n        <code>| integer</code><br>\n        <code>| bool_</code>\n    </td>\n    <td align=\"left\"><code>ToFloat</code></td>\n    <td align=\"left\"><code>ToFloat[strict]{1,2,3}D</code></td>\n    <td align=\"left\"><code>ToFloatND</code></td>\n</tr>\n<tr><td colspan=\"6\"></td></tr>\n<tr>\n    <td align=\"left\">\n        <code>complex</code><br>\n        <code>| float</code><br>\n        <code>| int</code>\n    </td>\n    <td align=\"left\">\n        <code>number</code><br>\n        <code>| bool_</code>\n    </td>\n    <td align=\"left\"><code>ToComplex</code></td>\n    <td align=\"left\"><code>ToComplex[strict]{1,2,3}D</code></td>\n    <td align=\"left\"><code>ToComplexND</code></td>\n</tr>\n<tr><td colspan=\"6\"></td></tr>\n<tr>\n    <td align=\"left\">\n        <code>bytes</code><br>\n        <code>| str</code><br>\n        <code>| complex</code><br>\n        <code>| float</code><br>\n        <code>| int</code>\n    </td>\n    <td align=\"left\"><code>generic</code></td>\n    <td align=\"left\"><code>ToScalar</code></td>\n    <td align=\"left\"><code>ToArray[strict]{1,2,3}D</code></td>\n    <td align=\"left\"><code>ToArrayND</code></td>\n</tr>\n</table>\n\n> [!NOTE]\n> The `To*Strict{1,2,3}D` aliases were added in `optype 0.7.3`.\n>\n> These array-likes with *strict shape-type* require the shape-typed input to be\n> shape-typed.\n> This means that e.g. `ToFloat1D` and `ToFloat2D` are disjoint (non-overlapping),\n> and makes them suitable to overload array-likes of a particular dtype for different\n> numbers of dimensions.\n\nSource code: [`optype/numpy/_to.py`][CODE-NP-TO]\n\n#### `DType`\n\nIn NumPy, a *dtype* (data type) object, is an instance of the\n`numpy.dtype[ST: np.generic]` type.\nIt's commonly used to convey metadata of a scalar type, e.g. within arrays.\n\nBecause the type parameter of `np.dtype` isn't optional, it could be more\nconvenient to use the alias `optype.numpy.DType`, which is defined as:\n\n```python\ntype DType[ST: np.generic = np.generic] = np.dtype[ST]\n```\n\nApart from the \"CamelCase\" name, the only difference with `np.dtype` is that\nthe type parameter can be omitted, in which case it's equivalent to\n`np.dtype[np.generic]`, but shorter.\n\n#### `Scalar`\n\nThe `optype.numpy.Scalar` interface is a generic runtime-checkable protocol,\nthat can be seen as a \"more specific\" `np.generic`, both in name, and from\na typing perspective.\n\nIts type signature looks roughly like this:\n\n```python\ntype Scalar[\n    # The \"Python type\", so that `Scalar.item() -> PT`.\n    PT: object,\n    # The \"N-bits\" type (without having to deal with `npt.NBitBase`).\n    # It matches the `itemsize: NB` property.\n    NB: int = int,\n] = ...\n```\n\nIt can be used as e.g.\n\n```python\nare_birds_real: Scalar[bool, Literal[1]] = np.bool_(True)\nthe_answer: Scalar[int, Literal[2]] = np.uint16(42)\nalpha: Scalar[float, Literal[8]] = np.float64(1 / 137)\n```\n\n> [!NOTE]\n> The second type argument for `itemsize` can be omitted, which is equivalent\n> to setting it to `int`, so `Scalar[PT]` and `Scalar[PT, int]` are equivalent.\n\n#### `UFunc`\n\nA large portion of numpy's public API consists of *universal functions*, often\ndenoted as [ufuncs][DOC-UFUNC], which are (callable) instances of\n[`np.ufunc`][REF_UFUNC].\n\n> [!TIP]\n> Custom ufuncs can be created using [`np.frompyfunc`][REF_FROMPY], but also\n> through a user-defined class that implements the required attributes and\n> methods (i.e., duck typing).\n>\nBut `np.ufunc` has a big issue; it accepts no type parameters.\nThis makes it very difficult to properly annotate its callable signature and\nits literal attributes (e.g. `.nin` and `.identity`).\n\nThis is where `optype.numpy.UFunc` comes into play:\nIt's a runtime-checkable generic typing protocol, that has been thoroughly\ntype- and unit-tested to ensure compatibility with all of numpy's ufunc\ndefinitions.\nIts generic type signature looks roughly like:\n\n```python\ntype UFunc[\n    # The type of the (bound) `__call__` method.\n    Fn: CanCall = CanCall,\n    # The types of the `nin` and `nout` (readonly) attributes.\n    # Within numpy these match either `Literal[1]` or `Literal[2]`.\n    Nin: int = int,\n    Nout: int = int,\n    # The type of the `signature` (readonly) attribute;\n    # Must be `None` unless this is a generalized ufunc (gufunc), e.g.\n    # `np.matmul`.\n    Sig: str | None = str | None,\n    # The type of the `identity` (readonly) attribute (used in `.reduce`).\n    # Unless `Nin: Literal[2]`, `Nout: Literal[1]`, and `Sig: None`,\n    # this should always be `None`.\n    # Note that `complex` also includes `bool | int | float`.\n    Id: complex | bytes | str | None = float | None,\n] = ...\n```\n\n> [!NOTE]\n> Unfortunately, the extra callable methods of `np.ufunc` (`at`, `reduce`,\n> `reduceat`, `accumulate`, and `outer`), are incorrectly annotated (as `None`\n> *attributes*, even though at runtime they're methods that raise a\n> `ValueError` when called).\n> This currently makes it impossible to properly type these in\n> `optype.numpy.UFunc`; doing so would make it incompatible with numpy's\n> ufuncs.\n\n#### `Any*Array` and `Any*DType`\n\nThe `Any{Scalar}Array` type aliases describe array-likes that are coercible to an\n`numpy.ndarray` with specific [dtype][REF-DTYPES].\n\nUnlike `numpy.typing.ArrayLike`, these `optype.numpy` aliases **don't**\naccept \"bare\" scalar types such as `float` and `np.float64`. However, arrays of\n\"zero dimensions\" like `onp.Array[tuple[()], np.float64]` will be accepted.\nThis is in line with the behavior of [`numpy.isscalar`][REF-ISSCALAR] on `numpy >= 2`.\n\n```py\nimport numpy.typing as npt\nimport optype.numpy as onp\n\nv_np: npt.ArrayLike = 3.14  # accepted\nv_op: onp.AnyArray = 3.14  # rejected\n\nsigma1_np: npt.ArrayLike = [[0, 1], [1, 0]]  # accepted\nsigma1_op: onp.AnyArray = [[0, 1], [1, 0]]  # accepted\n```\n\n> [!NOTE]\n> The [`numpy.dtypes` docs][REF-DTYPES] exists since NumPy 1.25, but its\n> type annotations were incorrect before NumPy 2.1 (see\n> [numpy/numpy#27008](https://github.com/numpy/numpy/pull/27008))\n\nSee the [docs][REF-SCT] for more info on the NumPy scalar type hierarchy.\n\n[REF-SCT]: https://numpy.org/doc/stable/reference/arrays.scalars.html\n[REF-DTYPES]: https://numpy.org/doc/stable/reference/arrays.dtypes.html\n[REF-ISSCALAR]: https://numpy.org/doc/stable/reference/generated/numpy.isscalar.html\n\n##### Abstract types\n\n<table>\n    <tr>\n        <th align=\"center\" colspan=\"2\"><code>numpy._</code></th>\n        <th align=\"center\" colspan=\"2\"><code>optype.numpy._</code></th>\n    </tr>\n    <tr>\n        <th>scalar</th>\n        <th>scalar base</th>\n        <th>array-like</th>\n        <th>dtype-like</th>\n    </tr>\n    <tr>\n        <td><code>generic</code></td>\n        <td></td>\n        <td><code>AnyArray</code></td>\n        <td><code>AnyDType</code></td>\n    </tr>\n    <tr>\n        <td><code>number</code></td>\n        <td><code>generic</code></td>\n        <td><code>AnyNumberArray</code></td>\n        <td><code>AnyNumberDType</code></td>\n    </tr>\n    <tr>\n        <td><code>integer</code></td>\n        <td rowspan=\"2\"><code>number</code></td>\n        <td><code>AnyIntegerArray</code></td>\n        <td><code>AnyIntegerDType</code></td>\n    </tr>\n    <tr>\n        <td><code>inexact</code></td>\n        <td><code>AnyInexactArray</code></td>\n        <td><code>AnyInexactDType</code></td>\n    </tr>\n    <tr>\n        <td><code>unsignedinteger</code></td>\n        <td rowspan=\"2\"><code>integer</code></td>\n        <td><code>AnyUnsignedIntegerArray</code></td>\n        <td><code>AnyUnsignedIntegerDType</code></td>\n    </tr>\n    <tr>\n        <td><code>signedinteger</code></td>\n        <td><code>AnySignedIntegerArray</code></td>\n        <td><code>AnySignedIntegerDType</code></td>\n    </tr>\n    <tr>\n        <td><code>floating</code></td>\n        <td rowspan=\"2\"><code>inexact</code></td>\n        <td><code>AnyFloatingArray</code></td>\n        <td><code>AnyFloatingDType</code></td>\n    </tr>\n    <tr>\n        <td><code>complexfloating</code></td>\n        <td><code>AnyComplexFloatingArray</code></td>\n        <td><code>AnyComplexFloatingDType</code></td>\n    </tr>\n</table>\n\n##### Unsigned integers\n\n<table>\n    <tr>\n        <th align=\"center\" colspan=\"2\"><code>numpy._</code></th>\n        <th align=\"center\"><code>numpy.dtypes._</code></th>\n        <th align=\"center\" colspan=\"2\"><code>optype.numpy._</code></th>\n    </tr>\n    <tr>\n        <th>scalar</th>\n        <th>scalar base</th>\n        <th>dtype</th>\n        <th>array-like</th>\n        <th>dtype-like</th>\n    </tr>\n    <tr>\n        <td><code>uint8</code>, <code>ubyte</code></td>\n        <td rowspan=\"8\"><code>unsignedinteger</code></td>\n        <td><code>UInt8DType</code></td>\n        <td><code>AnyUInt8Array</code></td>\n        <td><code>AnyUInt8DType</code></td>\n    </tr>\n    <tr>\n        <td><code>uint16</code>, <code>ushort</code></td>\n        <td><code>UInt16DType</code></td>\n        <td><code>AnyUInt16Array</code></td>\n        <td><code>AnyUInt16DType</code></td>\n    </tr>\n    <tr>\n<td>\n\n`uint32`[^5]\n\n</td>\n        <td><code>UInt32DType</code></td>\n        <td><code>AnyUInt32Array</code></td>\n        <td><code>AnyUInt32DType</code></td>\n    </tr>\n    <tr>\n        <td><code>uint64</code></td>\n        <td><code>UInt64DType</code></td>\n        <td><code>AnyUInt64Array</code></td>\n        <td><code>AnyUInt64DType</code></td>\n    </tr>\n    <tr>\n<td>\n\n`uintc`[^5]\n\n</td>\n        <td><code>UIntDType</code></td>\n        <td><code>AnyUIntCArray</code></td>\n        <td><code>AnyUIntCDType</code></td>\n    </tr>\n    <tr>\n<td>\n\n`uintp`, `uint_` [^7]\n\n</td>\n        <td></td>\n        <td><code>AnyUIntPArray</code></td>\n        <td><code>AnyUIntPDType</code></td>\n    </tr>\n    <tr>\n<td>\n\n`ulong`[^6]\n\n</td>\n        <td><code>ULongDType</code></td>\n        <td><code>AnyULongArray</code></td>\n        <td><code>AnyULongDType</code></td>\n    </tr>\n    <tr>\n        <td><code>ulonglong</code></td>\n        <td><code>ULongLongDType</code></td>\n        <td><code>AnyULongLongArray</code></td>\n        <td><code>AnyULongLongDType</code></td>\n    </tr>\n</table>\n\n##### Signed integers\n\n<table>\n    <tr>\n        <th align=\"center\" colspan=\"2\"><code>numpy._</code></th>\n        <th align=\"center\"><code>numpy.dtypes._</code></th>\n        <th align=\"center\" colspan=\"2\"><code>optype.numpy._</code></th>\n    </tr>\n    <tr>\n        <th>scalar</th>\n        <th>scalar base</th>\n        <th>dtype</th>\n        <th>array-like</th>\n        <th>dtype-like</th>\n    </tr>\n    <tr>\n        <td><code>int8</code></td>\n        <td rowspan=\"8\"><code>signedinteger</code></td>\n        <td><code>Int8DType</code></td>\n        <td><code>AnyInt8Array</code></td>\n        <td><code>AnyInt8DType</code></td>\n    </tr>\n    <tr>\n        <td><code>int16</code></td>\n        <td><code>Int16DType</code></td>\n        <td><code>AnyInt16Array</code></td>\n        <td><code>AnyInt16DType</code></td>\n    </tr>\n    <tr>\n<td>\n\n`int32`[^5]\n\n</td>\n        <td><code>Int32DType</code></td>\n        <td><code>AnyInt32Array</code></td>\n        <td><code>AnyInt32DType</code></td>\n    </tr>\n    <tr>\n        <td><code>int64</code></td>\n        <td><code>Int64DType</code></td>\n        <td><code>AnyInt64Array</code></td>\n        <td><code>AnyInt64DType</code></td>\n    </tr>\n    <tr>\n<td>\n\n`intc`[^5]\n\n</td>\n        <td><code>IntDType</code></td>\n        <td><code>AnyIntCArray</code></td>\n        <td><code>AnyIntCDType</code></td>\n    </tr>\n    <tr>\n<td>\n\n`intp`, `int_` [^7]\n\n</td>\n        <td></td>\n        <td><code>AnyIntPArray</code></td>\n        <td><code>AnyIntPDType</code></td>\n    </tr>\n    <tr>\n<td>\n\n`long`[^6]\n\n</td>\n        <td><code>LongDType</code></td>\n        <td><code>AnyLongArray</code></td>\n        <td><code>AnyLongDType</code></td>\n    </tr>\n    <tr>\n        <td><code>longlong</code></td>\n        <td><code>LongLongDType</code></td>\n        <td><code>AnyLongLongArray</code></td>\n        <td><code>AnyLongLongDType</code></td>\n    </tr>\n</table>\n\n[^5]: On unix-based platforms `np.[u]intc` are aliases for `np.[u]int32`.\n[^6]: On NumPy 1 `np.uint` and `np.int_` are what in NumPy 2 are now the `np.ulong` and `np.long` types, respectively.\n[^7]: Since NumPy 2, `np.uint` and `np.int_` are aliases for `np.uintp` and `np.intp`, respectively.\n\n##### Floats\n\n<table>\n    <tr>\n        <th align=\"center\" colspan=\"2\"><code>numpy._</code></th>\n        <th align=\"center\"><code>numpy.dtypes._</code></th>\n        <th align=\"center\" colspan=\"2\"><code>optype.numpy._</code></th>\n    </tr>\n    <tr>\n        <th>scalar</th>\n        <th>scalar base</th>\n        <th>dtype</th>\n        <th>array-like</th>\n        <th>dtype-like</th>\n    </tr>\n    <tr>\n        <td>\n            <code>float16</code>,<br>\n            <code>half</code>\n        </td>\n        <td rowspan=\"2\"><code>np.floating</code></td>\n        <td><code>Float16DType</code></td>\n        <td><code>AnyFloat16Array</code></td>\n        <td><code>AnyFloat16DType</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>float32</code>,<br>\n            <code>single</code>\n        </td>\n        <td><code>Float32DType</code></td>\n        <td><code>AnyFloat32Array</code></td>\n        <td><code>AnyFloat32DType</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>float64</code>,<br>\n            <code>double</code>\n        </td>\n        <td>\n            <code>np.floating &</code><br>\n            <code>builtins.float</code>\n        </td>\n        <td><code>Float64DType</code></td>\n        <td><code>AnyFloat64Array</code></td>\n        <td><code>AnyFloat64DType</code></td>\n    </tr>\n    <tr>\n<td>\n\n`longdouble`[^13]\n\n</td>\n        <td><code>np.floating</code></td>\n        <td><code>LongDoubleDType</code></td>\n        <td><code>AnyLongDoubleArray</code></td>\n        <td><code>AnyLongDoubleDType</code></td>\n    </tr>\n</table>\n\n[^13]: Depending on the platform, `np.longdouble` is (almost always) an alias for **either** `float128`,\n    `float96`, or (sometimes) `float64`.\n\n##### Complex numbers\n\n<table>\n    <tr>\n        <th align=\"center\" colspan=\"2\"><code>numpy._</code></th>\n        <th align=\"center\"><code>numpy.dtypes._</code></th>\n        <th align=\"center\" colspan=\"2\"><code>optype.numpy._</code></th>\n    </tr>\n    <tr>\n        <th>scalar</th>\n        <th>scalar base</th>\n        <th>dtype</th>\n        <th>array-like</th>\n        <th>dtype-like</th>\n    </tr>\n    <tr>\n        <td>\n            <code>complex64</code>,<br>\n            <code>csingle</code>\n        </td>\n        <td><code>complexfloating</code></td>\n        <td><code>Complex64DType</code></td>\n        <td><code>AnyComplex64Array</code></td>\n        <td><code>AnyComplex64DType</code></td>\n    </tr>\n    <tr>\n        <td>\n            <code>complex128</code>,<br>\n            <code>cdouble</code>\n        </td>\n        <td>\n            <code>complexfloating &</code><br>\n            <code>builtins.complex</code>\n        </td>\n        <td><code>Complex128DType</code></td>\n        <td><code>AnyComplex128Array</code></td>\n        <td><code>AnyComplex128DType</code></td>\n    </tr>\n    <tr>\n<td>\n\n`clongdouble`[^16]\n\n</td>\n        <td><code>complexfloating</code></td>\n        <td><code>CLongDoubleDType</code></td>\n        <td><code>AnyCLongDoubleArray</code></td>\n        <td><code>AnyCLongDoubleDType</code></td>\n    </tr>\n</table>\n\n[^16]: Depending on the platform, `np.clongdouble` is (almost always) an alias for **either** `complex256`,\n    `complex192`, or (sometimes) `complex128`.\n\n##### \"Flexible\"\n\nScalar types with \"flexible\" length, whose values have a (constant) length\nthat depends on the specific `np.dtype` instantiation.\n\n<table>\n    <tr>\n        <th align=\"center\" colspan=\"2\"><code>numpy._</code></th>\n        <th align=\"center\"><code>numpy.dtypes._</code></th>\n        <th align=\"center\" colspan=\"2\"><code>optype.numpy._</code></th>\n    </tr>\n    <tr>\n        <th>scalar</th>\n        <th>scalar base</th>\n        <th>dtype</th>\n        <th>array-like</th>\n        <th>dtype-like</th>\n    </tr>\n    <tr>\n        <td><code>bytes_</code></td>\n        <td rowspan=\"2\"><code>character</code></td>\n        <td><code>BytesDType</code></td>\n        <td><code>AnyBytesArray</code></td>\n        <td><code>AnyBytesDType</code></td>\n    </tr>\n    <tr>\n        <td><code>str_</code></td>\n        <td><code>StrDType</code></td>\n        <td><code>AnyStrArray</code></td>\n        <td><code>AnyStrDType</code></td>\n    </tr>\n    <tr>\n        <td><code>void</code></td>\n        <td><code>flexible</code></td>\n        <td><code>VoidDType</code></td>\n        <td><code>AnyVoidArray</code></td>\n        <td><code>AnyVoidDType</code></td>\n    </tr>\n</table>\n\n##### Other types\n\n<table>\n    <tr>\n        <th align=\"center\" colspan=\"2\"><code>numpy._</code></th>\n        <th align=\"center\"><code>numpy.dtypes._</code></th>\n        <th align=\"center\" colspan=\"2\"><code>optype.numpy._</code></th>\n    </tr>\n    <tr>\n        <th>scalar</th>\n        <th>scalar base</th>\n        <th>dtype</th>\n        <th>array-like</th>\n        <th>dtype-like</th>\n    </tr>\n    <tr>\n<td>\n\n`bool_`[^0]\n\n</td>\n        <td rowspan=\"3\"><code>generic</code></td>\n        <td><code>BoolDType</code></td>\n        <td><code>AnyBoolArray</code></td>\n        <td><code>AnyBoolDType</code></td>\n    </tr>\n    <tr>\n        <td><code>object_</code></td>\n        <td><code>ObjectDType</code></td>\n        <td><code>AnyObjectArray</code></td>\n        <td><code>AnyObjectDType</code></td>\n    </tr>\n    <tr>\n        <td><code>datetime64</code></td>\n        <td><code>DateTime64DType</code></td>\n        <td><code>AnyDateTime64Array</code></td>\n        <td><code>AnyDateTime64DType</code></td>\n    </tr>\n    <tr>\n        <td><code>timedelta64</code></td>\n<td>\n\n*`generic`*[^22]\n\n</td>\n        <td><code>TimeDelta64DType</code></td>\n        <td><code>AnyTimeDelta64Array</code></td>\n        <td><code>AnyTimeDelta64DType</code></td>\n    </tr>\n    <tr>\n<td colspan=2>\n\n[^2056]\n\n</td>\n        <td><code>StringDType</code></td>\n        <td><code>AnyStringArray</code></td>\n        <td><code>AnyStringDType</code></td>\n    </tr>\n</table>\n\n[^0]: Since NumPy 2, `np.bool` is preferred over `np.bool_`, which only exists for backwards compatibility.\n\n[^22]: At runtime `np.timedelta64` is a subclass of `np.signedinteger`, but this is currently not\n    reflected in the type annotations.\n\n[^2056]: The `np.dypes.StringDType` has no associated numpy scalar type, and its `.type` attribute returns the\n    `builtins.str` type instead. But from a typing perspective, such a `np.dtype[builtins.str]` isn't a valid type.\n\n#### Low-level interfaces\n\nWithin `optype.numpy` there are several `Can*` (single-method) and `Has*`\n(single-attribute) protocols, related to the `__array_*__` dunders of the\nNumPy Python API.\nThese typing protocols are, just like the `optype.Can*` and `optype.Has*` ones,\nruntime-checkable and extensible (i.e. not `@final`).\n\n> [!TIP]\n> All type parameters of these protocols can be omitted, which is equivalent\n> to passing its upper type bound.\n\n<table>\n    <tr>\n        <th>Protocol type signature</th>\n        <th>Implements</th>\n        <th>NumPy docs</th>\n    </tr>\n    <tr>\n<td>\n\n```python\nclass CanArray[\n    ND: tuple[int, ...] = ...,\n    ST: np.generic = ...,\n]: ...\n```\n\n</td>\n<td>\n\n<!-- blacken-docs:off -->\n```python\ndef __array__[RT = ST](\n    _,\n    dtype: DType[RT] | None = ...,\n) -> Array[ND, RT]\n```\n<!-- blacken-docs:on -->\n\n</td>\n<td>\n\n[User Guide: Interoperability with NumPy][DOC-ARRAY]\n\n</td>\n    </tr>\n    <tr><td colspan=\"3\"></td></tr>\n    <tr>\n<td>\n\n```python\nclass CanArrayUFunc[\n    U: UFunc = ...,\n    R: object = ...,\n]: ...\n```\n\n</td>\n<td>\n\n```python\ndef __array_ufunc__(\n    _,\n    ufunc: U,\n    method: LiteralString,\n    *args: object,\n    **kwargs: object,\n) -> R: ...\n```\n\n</td>\n<td>\n\n[NEP 13][NEP13]\n\n</td>\n    </tr>\n    <tr><td colspan=\"3\"></td></tr>\n    <tr>\n<td>\n\n```python\nclass CanArrayFunction[\n    F: CanCall[..., object] = ...,\n    R = object,\n]: ...\n```\n\n</td>\n<td>\n\n```python\ndef __array_function__(\n    _,\n    func: F,\n    types: CanIterSelf[type[CanArrayFunction]],\n    args: tuple[object, ...],\n    kwargs: Mapping[str, object],\n) -> R: ...\n```\n\n</td>\n<td>\n\n[NEP 18][NEP18]\n\n</td>\n    </tr>\n    <tr><td colspan=\"3\"></td></tr>\n    <tr>\n<td>\n\n```python\nclass CanArrayFinalize[\n    T: object = ...,\n]: ...\n```\n\n</td>\n<td>\n\n```python\ndef __array_finalize__(_, obj: T): ...\n```\n\n</td>\n<td>\n\n[User Guide: Subclassing ndarray][DOC-AFIN]\n\n</td>\n    </tr>\n    <tr><td colspan=\"3\"></td></tr>\n    <tr>\n<td>\n\n```python\nclass CanArrayWrap: ...\n```\n\n</td>\n<td>\n\n<!-- blacken-docs:off -->\n```python\ndef __array_wrap__[ND, ST](\n    _,\n    array: Array[ND, ST],\n    context: (...) | None = ...,\n    return_scalar: bool = ...,\n) -> Self | Array[ND, ST]\n```\n<!-- blacken-docs:on -->\n\n</td>\n<td>\n\n[API: Standard array subclasses][REF_ARRAY-WRAP]\n\n</td>\n    </tr>\n    <tr><td colspan=\"3\"></td></tr>\n    <tr>\n<td>\n\n```python\nclass HasArrayInterface[\n    V: Mapping[str, object] = ...,\n]: ...\n```\n\n</td>\n<td>\n\n```python\n__array_interface__: V\n```\n\n</td>\n<td>\n\n[API: The array interface protocol][REF_ARRAY-INTER]\n\n</td>\n    </tr>\n    <tr><td colspan=\"3\"></td></tr>\n    <tr>\n<td>\n\n```python\nclass HasArrayPriority: ...\n```\n\n</td>\n<td>\n\n```python\n__array_priority__: float\n```\n\n</td>\n<td>\n\n[API: Standard array subclasses][REF_ARRAY-PRIO]\n\n</td>\n    </tr>\n    <tr><td colspan=\"3\"></td></tr>\n    <tr>\n<td>\n\n```python\nclass HasDType[\n    DT: DType = ...,\n]: ...\n```\n\n</td>\n<td>\n\n```python\ndtype: DT\n```\n\n</td>\n<td>\n\n[API: Specifying and constructing data types][REF_DTYPE]\n\n</td>\n    </tr>\n</table>\n\n<!-- references -->\n\n[DOC-UFUNC]: https://numpy.org/doc/stable/reference/ufuncs.html\n[DOC-ARRAY]: https://numpy.org/doc/stable/user/basics.interoperability.html#the-array-method\n[DOC-AFIN]: https://numpy.org/doc/stable/user/basics.subclassing.html#the-role-of-array-finalize\n\n[REF_UFUNC]: https://numpy.org/doc/stable/reference/generated/numpy.ufunc.html\n[REF_FROMPY]: https://numpy.org/doc/stable/reference/generated/numpy.frompyfunc.html\n[REF_ARRAY-WRAP]: https://numpy.org/doc/stable/reference/arrays.classes.html#numpy.class.__array_wrap__\n[REF_ARRAY-INTER]: https://numpy.org/doc/stable/reference/arrays.interface.html#python-side\n[REF_ARRAY-PRIO]: https://numpy.org/doc/stable/reference/arrays.classes.html#numpy.class.__array_priority__\n[REF_DTYPE]: https://numpy.org/doc/stable/reference/arrays.dtypes.html#specifying-and-constructing-data-types\n\n[CODE-NP-TO]: https://github.com/jorenham/optype/blob/master/optype/numpy/_to.py\n\n[NEP13]: https://numpy.org/neps/nep-0013-ufunc-overrides.html\n[NEP18]: https://numpy.org/neps/nep-0018-array-function-protocol.html\n[NEP29]: https://numpy.org/neps/nep-0029-deprecation_policy.html\n\n[SPEC0]: https://scientific-python.org/specs/spec-0000/\n\n[PEP695]: https://peps.python.org/pep-0695/\n[PEP696]: https://peps.python.org/pep-0696/\n",
    "bugtrack_url": null,
    "license": "BSD-3-Clause",
    "summary": "Building blocks for precise & flexible type hints",
    "version": "0.7.3",
    "project_urls": {
        "Changelog": "https://github.com/jorenham/optype/releases",
        "Documentation": "https://github.com/jorenham/optype/blob/master/README.md",
        "Funding": "https://github.com/sponsors/jorenham",
        "Issues": "https://github.com/jorenham/optype/issues",
        "Repository": "https://github.com/jorenham/optype/"
    },
    "split_keywords": [
        "numpy",
        " type",
        " type hints",
        " typing"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "2b92466c23b21b341d062f33be00a307b1581b90ca86b07f27a4a71ecbec830b",
                "md5": "bf55eceb01d7442a50d4f4fe9844a0a9",
                "sha256": "856416484131038799e0e9cefc19d0ef37e7b4fde2144f25e8bb0e8981ebbe95"
            },
            "downloads": -1,
            "filename": "optype-0.7.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "bf55eceb01d7442a50d4f4fe9844a0a9",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 70043,
            "upload_time": "2024-11-30T16:29:36",
            "upload_time_iso_8601": "2024-11-30T16:29:36.741320Z",
            "url": "https://files.pythonhosted.org/packages/2b/92/466c23b21b341d062f33be00a307b1581b90ca86b07f27a4a71ecbec830b/optype-0.7.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "08b73053b7d8b648b077422cfd7235f83909b6b192c2fa42bb9dba51cdc773bf",
                "md5": "452e725a35894fc321ba9a7dc217de15",
                "sha256": "51c8dd104ac197457059bcee5e256160a641ca72c6c852012d952790a5e0cac0"
            },
            "downloads": -1,
            "filename": "optype-0.7.3.tar.gz",
            "has_sig": false,
            "md5_digest": "452e725a35894fc321ba9a7dc217de15",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 80608,
            "upload_time": "2024-11-30T16:29:59",
            "upload_time_iso_8601": "2024-11-30T16:29:59.430128Z",
            "url": "https://files.pythonhosted.org/packages/08/b7/3053b7d8b648b077422cfd7235f83909b6b192c2fa42bb9dba51cdc773bf/optype-0.7.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-11-30 16:29:59",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "jorenham",
    "github_project": "optype",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "optype"
}
        
Elapsed time: 0.41141s