mirror of
https://github.com/wassname/jaxtyping.git
synced 2026-09-10 12:14:04 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
356f5b7f7b | ||
|
|
1b9c9fab52 | ||
|
|
066a5b058f | ||
|
|
319d54abcf | ||
|
|
6a64ef114e | ||
|
|
10e1852b37 |
@@ -33,7 +33,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
test-script: |
|
test-script: |
|
||||||
python -m pip install pytest beartype equinox jaxlib cloudpickle
|
python -m pip install -r ${{ github.workspace }}/test/requirements.txt
|
||||||
python -m pip install torch --extra-index-url https://download.pytorch.org/whl/cpu
|
python -m pip install torch --extra-index-url https://download.pytorch.org/whl/cpu
|
||||||
cp -r ${{ github.workspace }}/test ./test
|
cp -r ${{ github.workspace }}/test ./test
|
||||||
pytest
|
pytest
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
python -m pip install pytest wheel beartype equinox jaxlib cloudpickle
|
python -m pip install -r test/requirements.txt
|
||||||
python -m pip install torch --extra-index-url https://download.pytorch.org/whl/cpu
|
python -m pip install torch --extra-index-url https://download.pytorch.org/whl/cpu
|
||||||
|
|
||||||
- name: Checks with pre-commit
|
- name: Checks with pre-commit
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ def accepts_pytree_of_arrays(x: PyTree[Float[Array, "batch c1 c2"]]):
|
|||||||
pip install jaxtyping
|
pip install jaxtyping
|
||||||
```
|
```
|
||||||
|
|
||||||
Requires Python 3.8+.
|
Requires Python 3.9+.
|
||||||
|
|
||||||
JAX is an optional dependency, required for a few JAX-specific types. If JAX is not installed then these will not be available, but you may still use jaxtyping to provide shape/dtype annotations for PyTorch/NumPy/TensorFlow/etc.
|
JAX is an optional dependency, required for a few JAX-specific types. If JAX is not installed then these will not be available, but you may still use jaxtyping to provide shape/dtype annotations for PyTorch/NumPy/TensorFlow/etc.
|
||||||
|
|
||||||
|
|||||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 807 B After Width: | Height: | Size: 541 B |
@@ -1,13 +1,18 @@
|
|||||||
# Advanced features
|
# Advanced features
|
||||||
|
|
||||||
## Abstract base classes
|
## Creating your own dtypes
|
||||||
|
|
||||||
::: jaxtyping.AbstractDtype
|
::: jaxtyping.AbstractDtype
|
||||||
selection:
|
selection:
|
||||||
members:
|
members:
|
||||||
false
|
false
|
||||||
|
|
||||||
::: jaxtyping.AbstractArray
|
## Introspection
|
||||||
selection:
|
|
||||||
members:
|
If you're writing your own type hint parser, then you may wish to detect if some Python object is a jaxtyping-provided type.
|
||||||
false
|
|
||||||
|
You can check for dtypes by doing `issubclass(x, AbstractDtype)`. For example, `issubclass(Float32, AbstractDtype)` will pass.
|
||||||
|
|
||||||
|
You can check for arrays by doing `issubclass(x, AbstractArray)`. Here, `AbstractArray` is the base class for all shape-and-dtype specified arrays, e.g. it's a base class for `Float32[Array, "foo"]`.
|
||||||
|
|
||||||
|
You can check for pytrees by doing `issubclass(x, PyTree)`. For example, `issubclass(PyTree[int], PyTree)` will pass.
|
||||||
|
|||||||
+7
-1
@@ -5,4 +5,10 @@
|
|||||||
members:
|
members:
|
||||||
false
|
false
|
||||||
|
|
||||||
Note that `jaxtyping.PyTree` is only available if JAX has been installed.
|
---
|
||||||
|
|
||||||
|
:::jaxtyping.PyTreeDef
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Note that `jaxtyping.{PyTree, PyTreeDef}` are only available if JAX has been installed.
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ jaxtyping is a library providing type annotations **and runtime type-checking**
|
|||||||
pip install jaxtyping
|
pip install jaxtyping
|
||||||
```
|
```
|
||||||
|
|
||||||
Requires Python 3.8+.
|
Requires Python 3.9+.
|
||||||
|
|
||||||
JAX is an optional dependency, required for a few JAX-specific types. If JAX is not installed then these will not be available, but you may still use jaxtyping to provide shape/dtype annotations for PyTorch/NumPy/TensorFlow/etc.
|
JAX is an optional dependency, required for a few JAX-specific types. If JAX is not installed then these will not be available, but you may still use jaxtyping to provide shape/dtype annotations for PyTorch/NumPy/TensorFlow/etc.
|
||||||
|
|
||||||
|
|||||||
+23
-11
@@ -30,14 +30,14 @@ else:
|
|||||||
del jax
|
del jax
|
||||||
|
|
||||||
# First import some things as normal
|
# First import some things as normal
|
||||||
from .array_types import (
|
from ._array_types import (
|
||||||
AbstractArray as AbstractArray,
|
AbstractArray as AbstractArray,
|
||||||
AbstractDtype as AbstractDtype,
|
AbstractDtype as AbstractDtype,
|
||||||
get_array_name_format as get_array_name_format,
|
get_array_name_format as get_array_name_format,
|
||||||
set_array_name_format as set_array_name_format,
|
set_array_name_format as set_array_name_format,
|
||||||
)
|
)
|
||||||
from .decorator import jaxtyped as jaxtyped
|
from ._decorator import jaxtyped as jaxtyped
|
||||||
from .import_hook import install_import_hook as install_import_hook
|
from ._import_hook import install_import_hook as install_import_hook
|
||||||
|
|
||||||
|
|
||||||
# Now import Array and ArrayLike
|
# Now import Array and ArrayLike
|
||||||
@@ -71,7 +71,7 @@ elif has_jax:
|
|||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
# Introduce an indirection so that we can `import X as X` to make it clear that
|
# Introduce an indirection so that we can `import X as X` to make it clear that
|
||||||
# these are public.
|
# these are public.
|
||||||
from .indirection import (
|
from ._indirection import (
|
||||||
BFloat16 as BFloat16,
|
BFloat16 as BFloat16,
|
||||||
Bool as Bool,
|
Bool as Bool,
|
||||||
Complex as Complex,
|
Complex as Complex,
|
||||||
@@ -98,7 +98,7 @@ if typing.TYPE_CHECKING:
|
|||||||
UInt64 as UInt64,
|
UInt64 as UInt64,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
from .array_types import (
|
from ._array_types import (
|
||||||
BFloat16 as BFloat16,
|
BFloat16 as BFloat16,
|
||||||
Bool as Bool,
|
Bool as Bool,
|
||||||
Complex as Complex,
|
Complex as Complex,
|
||||||
@@ -125,14 +125,16 @@ else:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if has_jax:
|
if has_jax:
|
||||||
from .array_types import Key as Key
|
from ._array_types import Key as Key
|
||||||
|
|
||||||
|
|
||||||
# Now import PyTree
|
# Now import PyTreeDef and PyTree
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
# Set up to deliberately confuse a static type checker.
|
|
||||||
import typing_extensions
|
import typing_extensions
|
||||||
|
|
||||||
|
from jax.tree_util import PyTreeDef as PyTreeDef
|
||||||
|
|
||||||
|
# Set up to deliberately confuse a static type checker.
|
||||||
PyTree: typing_extensions.TypeAlias = getattr(typing, "foo" + "bar")
|
PyTree: typing_extensions.TypeAlias = getattr(typing, "foo" + "bar")
|
||||||
# What's going on with this madness?
|
# What's going on with this madness?
|
||||||
#
|
#
|
||||||
@@ -151,16 +153,26 @@ if typing.TYPE_CHECKING:
|
|||||||
# anything. (I believe this is sometimes called `Unknown`.) Thus, this odd-looking
|
# anything. (I believe this is sometimes called `Unknown`.) Thus, this odd-looking
|
||||||
# annotation, which static type checkers aren't smart enough to resolve.
|
# annotation, which static type checkers aren't smart enough to resolve.
|
||||||
elif has_jax:
|
elif has_jax:
|
||||||
from .pytree_type import PyTree as PyTree # noqa: F401
|
if hasattr(typing, "GENERATING_DOCUMENTATION"):
|
||||||
|
|
||||||
|
class PyTreeDef:
|
||||||
|
"""Alias for `jax.tree_util.PyTreeDef`, which is the type of the return
|
||||||
|
from `jax.tree_util.tree_structure(...)`.
|
||||||
|
"""
|
||||||
|
|
||||||
|
else:
|
||||||
|
from jax.tree_util import PyTreeDef as PyTreeDef
|
||||||
|
|
||||||
|
from ._pytree_type import PyTree as PyTree # noqa: F401
|
||||||
|
|
||||||
|
|
||||||
# Conveniences
|
# Conveniences
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from jax.random import PRNGKeyArray as PRNGKeyArray
|
from jax.random import PRNGKeyArray as PRNGKeyArray
|
||||||
|
|
||||||
from .indirection import Scalar as Scalar, ScalarLike as ScalarLike
|
from ._indirection import Scalar as Scalar, ScalarLike as ScalarLike
|
||||||
elif has_jax:
|
elif has_jax:
|
||||||
from .array_types import PRNGKeyArray, Scalar, ScalarLike # noqa: F401
|
from ._array_types import PRNGKeyArray, Scalar, ScalarLike # noqa: F401
|
||||||
|
|
||||||
del has_jax
|
del has_jax
|
||||||
|
|
||||||
|
|||||||
@@ -23,20 +23,11 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
import types
|
import types
|
||||||
import typing
|
import typing
|
||||||
from typing import (
|
from typing import Any, Literal, NoReturn, Optional, Union
|
||||||
Any,
|
|
||||||
Dict,
|
|
||||||
List,
|
|
||||||
Literal,
|
|
||||||
NoReturn,
|
|
||||||
Optional,
|
|
||||||
Tuple,
|
|
||||||
Union,
|
|
||||||
)
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from .decorator import storage
|
from ._decorator import storage
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -108,9 +99,9 @@ _AbstractDim = Union[Literal[_anonymous_dim], _NamedDim, _FixedDim, _SymbolicDim
|
|||||||
|
|
||||||
|
|
||||||
def _check_dims(
|
def _check_dims(
|
||||||
cls_dims: List[_AbstractDim],
|
cls_dims: list[_AbstractDim],
|
||||||
obj_shape: Tuple[int],
|
obj_shape: tuple[int],
|
||||||
single_memo: Dict[str, int],
|
single_memo: dict[str, int],
|
||||||
) -> bool:
|
) -> bool:
|
||||||
assert len(cls_dims) == len(obj_shape)
|
assert len(cls_dims) == len(obj_shape)
|
||||||
for cls_dim, obj_size in zip(cls_dims, obj_shape):
|
for cls_dim, obj_size in zip(cls_dims, obj_shape):
|
||||||
@@ -123,7 +114,8 @@ def _check_dims(
|
|||||||
return False
|
return False
|
||||||
elif type(cls_dim) is _SymbolicDim:
|
elif type(cls_dim) is _SymbolicDim:
|
||||||
try:
|
try:
|
||||||
eval_size = eval(cls_dim.expr, single_memo)
|
# Make a copy to avoid `__builtins__` getting added as a key.
|
||||||
|
eval_size = eval(cls_dim.expr, single_memo.copy())
|
||||||
except NameError as e:
|
except NameError as e:
|
||||||
raise NameError(
|
raise NameError(
|
||||||
f"Cannot process symbolic dimension '{cls_dim.expr}' as some "
|
f"Cannot process symbolic dimension '{cls_dim.expr}' as some "
|
||||||
@@ -213,9 +205,9 @@ class _MetaAbstractArray(type):
|
|||||||
def _check_shape(
|
def _check_shape(
|
||||||
cls,
|
cls,
|
||||||
obj,
|
obj,
|
||||||
single_memo: Dict[str, int],
|
single_memo: dict[str, int],
|
||||||
variadic_memo: Dict[str, Tuple[int, ...]],
|
variadic_memo: dict[str, tuple[int, ...]],
|
||||||
variadic_broadcast_memo: Dict[str, List[Tuple[int, ...]]],
|
variadic_broadcast_memo: dict[str, list[tuple[int, ...]]],
|
||||||
):
|
):
|
||||||
if cls.index_variadic is None:
|
if cls.index_variadic is None:
|
||||||
if obj.ndim != len(cls.dims):
|
if obj.ndim != len(cls.dims):
|
||||||
@@ -289,8 +281,8 @@ class AbstractArray(metaclass=_MetaAbstractArray):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
array_type: Any
|
array_type: Any
|
||||||
dtypes: List[str]
|
dtypes: list[str]
|
||||||
dims: Tuple[_AbstractDimOrVariadicDim, ...]
|
dims: tuple[_AbstractDimOrVariadicDim, ...]
|
||||||
index_variadic: Optional[int]
|
index_variadic: Optional[int]
|
||||||
dim_str: str
|
dim_str: str
|
||||||
|
|
||||||
@@ -517,7 +509,7 @@ class _MetaAbstractDtype(type):
|
|||||||
f'`jaxtyping.{cls.__name__}[jnp.ndarray, "..."]`.'
|
f'`jaxtyping.{cls.__name__}[jnp.ndarray, "..."]`.'
|
||||||
)
|
)
|
||||||
|
|
||||||
def __getitem__(cls, item: Tuple[Any, str]):
|
def __getitem__(cls, item: tuple[Any, str]):
|
||||||
if not isinstance(item, tuple) or len(item) != 2:
|
if not isinstance(item, tuple) or len(item) != 2:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"As of jaxtyping v0.2.0, type annotations must now include an explicit "
|
"As of jaxtyping v0.2.0, type annotations must now include an explicit "
|
||||||
@@ -570,7 +562,7 @@ class AbstractDtype(metaclass=_MetaAbstractDtype):
|
|||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
dtypes: Union[Literal[_any_dtype], List[Union[str, re.Pattern]]]
|
dtypes: Union[Literal[_any_dtype], list[Union[str, re.Pattern]]]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
@@ -581,7 +573,7 @@ class AbstractDtype(metaclass=_MetaAbstractDtype):
|
|||||||
def __init_subclass__(cls, **kwargs):
|
def __init_subclass__(cls, **kwargs):
|
||||||
super().__init_subclass__(**kwargs)
|
super().__init_subclass__(**kwargs)
|
||||||
|
|
||||||
dtypes: Union[Literal[_any_dtype], str, List[str]] = cls.dtypes
|
dtypes: Union[Literal[_any_dtype], str, list[str]] = cls.dtypes
|
||||||
if isinstance(dtypes, (str, re.Pattern)):
|
if isinstance(dtypes, (str, re.Pattern)):
|
||||||
dtypes = (dtypes,)
|
dtypes = (dtypes,)
|
||||||
elif dtypes is not _any_dtype:
|
elif dtypes is not _any_dtype:
|
||||||
@@ -52,11 +52,12 @@
|
|||||||
import ast
|
import ast
|
||||||
import functools as ft
|
import functools as ft
|
||||||
import sys
|
import sys
|
||||||
|
from collections.abc import Sequence
|
||||||
from importlib.abc import MetaPathFinder
|
from importlib.abc import MetaPathFinder
|
||||||
from importlib.machinery import SourceFileLoader
|
from importlib.machinery import SourceFileLoader
|
||||||
from importlib.util import cache_from_source, decode_source
|
from importlib.util import cache_from_source, decode_source
|
||||||
from inspect import isclass
|
from inspect import isclass
|
||||||
from typing import List, Optional, Sequence, Union
|
from typing import Optional, Union
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ def _str_lookup(string):
|
|||||||
|
|
||||||
class _JaxtypingTransformer(ast.NodeVisitor):
|
class _JaxtypingTransformer(ast.NodeVisitor):
|
||||||
def __init__(self, *, typechecker) -> None:
|
def __init__(self, *, typechecker) -> None:
|
||||||
self._parents: List[ast.AST] = []
|
self._parents: list[ast.AST] = []
|
||||||
self._typechecker = typechecker
|
self._typechecker = typechecker
|
||||||
|
|
||||||
def visit_Module(self, node: ast.Module):
|
def visit_Module(self, node: ast.Module):
|
||||||
@@ -120,7 +121,7 @@ class _JaxtypingTransformer(ast.NodeVisitor):
|
|||||||
return node
|
return node
|
||||||
|
|
||||||
def visit_ClassDef(self, node: ast.ClassDef):
|
def visit_ClassDef(self, node: ast.ClassDef):
|
||||||
func = _dot_lookup("jaxtyping", "decorator", "_jaxtyped_typechecker")
|
func = _dot_lookup("jaxtyping", "_decorator", "_jaxtyped_typechecker")
|
||||||
if self._typechecker is None:
|
if self._typechecker is None:
|
||||||
args = [ast.Constant(None)]
|
args = [ast.Constant(None)]
|
||||||
else:
|
else:
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# Note that `from typing_extensions import Annotated; Bool = Annotated`
|
# Note that `from typing import Annotated; Bool = Annotated`
|
||||||
# does not work with static type checkers. `Annotated` is a typeform rather
|
# does not work with static type checkers. `Annotated` is a typeform rather
|
||||||
# than a type, meaning it cannot be assigned.
|
# than a type, meaning it cannot be assigned.
|
||||||
from typing_extensions import (
|
from typing import (
|
||||||
Annotated as BFloat16, # noqa: F401
|
Annotated as BFloat16, # noqa: F401
|
||||||
Annotated as Bool, # noqa: F401
|
Annotated as Bool, # noqa: F401
|
||||||
Annotated as Complex, # noqa: F401
|
Annotated as Complex, # noqa: F401
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from .import_hook import install_import_hook
|
from ._import_hook import install_import_hook
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
@@ -35,10 +35,6 @@ class _FakePyTree(Generic[_T]):
|
|||||||
_FakePyTree.__name__ = "PyTree"
|
_FakePyTree.__name__ = "PyTree"
|
||||||
_FakePyTree.__qualname__ = "PyTree"
|
_FakePyTree.__qualname__ = "PyTree"
|
||||||
_FakePyTree.__module__ = "builtins"
|
_FakePyTree.__module__ = "builtins"
|
||||||
# Can't do type("PyTree", (Generic[_T],), {}) because dynamic subclassing of typeforms
|
|
||||||
# isn't allowed.
|
|
||||||
# Can't do types.new_class("PyTree", (Generic[_T],), {}) because that has __module__
|
|
||||||
# "types", e.g. we get types.PyTree[int].
|
|
||||||
|
|
||||||
|
|
||||||
class _MetaPyTree(type):
|
class _MetaPyTree(type):
|
||||||
@@ -46,32 +42,9 @@ class _MetaPyTree(type):
|
|||||||
raise RuntimeError("PyTree cannot be instantiated")
|
raise RuntimeError("PyTree cannot be instantiated")
|
||||||
|
|
||||||
def __instancecheck__(cls, obj):
|
def __instancecheck__(cls, obj):
|
||||||
return True
|
if not hasattr(cls, "leaftype"):
|
||||||
|
return True # Just `isinstance(x, PyTree)`
|
||||||
|
|
||||||
@ft.lru_cache(maxsize=None)
|
|
||||||
def __getitem__(cls, item):
|
|
||||||
name = str(_FakePyTree[item])
|
|
||||||
out = _MetaSubscriptPyTree(name, (), {"leaftype": item})
|
|
||||||
if getattr(typing, "GENERATING_DOCUMENTATION", False):
|
|
||||||
out.__module__ = "builtins"
|
|
||||||
else:
|
|
||||||
out.__module__ = "jaxtyping"
|
|
||||||
return out
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
# new typeguard
|
|
||||||
_TypeCheckError = (TypeError, typeguard.TypeCheckError)
|
|
||||||
except AttributeError:
|
|
||||||
# old typeguard
|
|
||||||
_TypeCheckError = TypeError
|
|
||||||
|
|
||||||
|
|
||||||
class _MetaSubscriptPyTree(type):
|
|
||||||
def __call__(self, *args, **kwargs):
|
|
||||||
raise RuntimeError("PyTree cannot be instantiated")
|
|
||||||
|
|
||||||
def __instancecheck__(cls, obj):
|
|
||||||
# We could use `isinstance` here but that would fail for more complicated
|
# We could use `isinstance` here but that would fail for more complicated
|
||||||
# types, e.g. PyTree[Tuple[int]]. So at least internally we make a particular
|
# types, e.g. PyTree[Tuple[int]]. So at least internally we make a particular
|
||||||
# choice of typechecker.
|
# choice of typechecker.
|
||||||
@@ -93,6 +66,36 @@ class _MetaSubscriptPyTree(type):
|
|||||||
leaves = jtu.tree_leaves(obj, is_leaf=is_leaftype)
|
leaves = jtu.tree_leaves(obj, is_leaf=is_leaftype)
|
||||||
return all(map(is_leaftype, leaves))
|
return all(map(is_leaftype, leaves))
|
||||||
|
|
||||||
|
# Can't return a generic (e.g. _FakePyTree[item]) because generic aliases don't do
|
||||||
|
# the custom __instancecheck__ that we want.
|
||||||
|
# We can't add that __instancecheck__ via subclassing, e.g.
|
||||||
|
# type("PyTree", (Generic[_T],), {}), because dynamic subclassing of typeforms
|
||||||
|
# isn't allowed.
|
||||||
|
# Likewise we can't do types.new_class("PyTree", (Generic[_T],), {}) because that
|
||||||
|
# has __module__ "types", e.g. we get types.PyTree[int].
|
||||||
|
@ft.lru_cache(maxsize=None)
|
||||||
|
def __getitem__(cls, item):
|
||||||
|
name = str(_FakePyTree[item])
|
||||||
|
|
||||||
|
class X(PyTree):
|
||||||
|
leaftype = item
|
||||||
|
|
||||||
|
X.__name__ = name
|
||||||
|
X.__qualname__ = name
|
||||||
|
if getattr(typing, "GENERATING_DOCUMENTATION", False):
|
||||||
|
X.__module__ = "builtins"
|
||||||
|
else:
|
||||||
|
X.__module__ = "jaxtyping"
|
||||||
|
return X
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
# new typeguard
|
||||||
|
_TypeCheckError = (TypeError, typeguard.TypeCheckError)
|
||||||
|
except AttributeError:
|
||||||
|
# old typeguard
|
||||||
|
_TypeCheckError = TypeError
|
||||||
|
|
||||||
|
|
||||||
# Can't do `class PyTree(Generic[_T]): ...` because we need to override the
|
# Can't do `class PyTree(Generic[_T]): ...` because we need to override the
|
||||||
# instancecheck for PyTree[foo], but subclassing
|
# instancecheck for PyTree[foo], but subclassing
|
||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "jaxtyping"
|
name = "jaxtyping"
|
||||||
version = "0.2.19"
|
version = "0.2.20"
|
||||||
description = "Type annotations and runtime checking for shape and dtype of JAX arrays, and PyTrees."
|
description = "Type annotations and runtime checking for shape and dtype of JAX arrays, and PyTrees."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python ="~=3.8"
|
requires-python ="~=3.9"
|
||||||
license = {file = "LICENSE"}
|
license = {file = "LICENSE"}
|
||||||
authors = [
|
authors = [
|
||||||
{name = "Patrick Kidger", email = "contact@kidger.site"},
|
{name = "Patrick Kidger", email = "contact@kidger.site"},
|
||||||
@@ -24,7 +24,7 @@ classifiers = [
|
|||||||
]
|
]
|
||||||
urls = {repository = "https://github.com/google/jaxtyping" }
|
urls = {repository = "https://github.com/google/jaxtyping" }
|
||||||
dependencies = ["numpy>=1.20.0", "typeguard>=2.13.3", "typing_extensions>=3.7.4.1"]
|
dependencies = ["numpy>=1.20.0", "typeguard>=2.13.3", "typing_extensions>=3.7.4.1"]
|
||||||
entry-points = {pytest11 = {jaxtyping = "jaxtyping.pytest_plugin"}}
|
entry-points = {pytest11 = {jaxtyping = "jaxtyping._pytest_plugin"}}
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["hatchling"]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
equinox>=0.5.3
|
beartype
|
||||||
pytest>=7.0.1
|
cloudpickle
|
||||||
beartype>=0.10.4
|
equinox
|
||||||
typeguard>=2.13.3
|
jaxlib
|
||||||
cloudpickle>=2.2.1
|
pytest
|
||||||
|
typeguard<3
|
||||||
|
|||||||
@@ -185,3 +185,11 @@ def test_pytree_namedtuple(typecheck):
|
|||||||
y=jax.random.normal(jax.random.PRNGKey(420), (2, 5)),
|
y=jax.random.normal(jax.random.PRNGKey(420), (2, 5)),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_subclass_pytree():
|
||||||
|
x = PyTree
|
||||||
|
y = PyTree[int]
|
||||||
|
assert issubclass(x, PyTree)
|
||||||
|
assert issubclass(y, PyTree)
|
||||||
|
assert not issubclass(int, PyTree)
|
||||||
|
|||||||
Reference in New Issue
Block a user