dltype


Namedltype JSON
Version 0.3.1 PyPI version JSON
download
home_pageNone
SummaryAn extremely lightweight typing library for torch tensors or numpy arrays. Supports runtime shape checking and data type validation.
upload_time2025-08-18 13:42:27
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseNone
keywords pytorch numpy shape check type check
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # DL Type (Deep Learning Type Library)

This typing library is intended to replace jaxtyping for runtime type checking of torch tensors and numpy arrays.

In particular, we support two functions that beartype/jaxtype do not:

1. Support for torch.jit.script/torch.compile/torch.jit.trace
2. Pydantic model type annotations for torch tensors.

## Features

- Shape and Type Validation: Validate tensor shapes and types at runtime with symbolic dimension support.
- Pydantic Integration: First-class support for tensor validation in Pydantic models.
- Context-Aware Validation: Ensures consistency across multiple tensors in the same context.
- ONNX/torch.compile Compatible: Works seamlessly with model export and compilation workflows.
- Symbolic Dimensions: Support for named dimensions that enforce consistency.

## Usage

Type hints are evaluated in a context in source-code order, so any references to dimension symbols must exist before an expression is evaluated.

## Supported syntax

DL Type supports four types of dimension specifications:

### Scalars

Single element tensors with no shape

```python
IntTensor[None] # An integer tensor with a single value and no axes
```

### Literal Dimensions

Simple integer dimensions with fixed sizes:

```python
FloatTensor["3 5"]  # A tensor with shape (3, 5)
FloatTensor["batch channels=3 height width"] # identifiers set to dimensions for documentation
```

### Expressions

Mathematical expressions combining literals and symbols.

```python
FloatTensor["batch channels*2"]  # If channels=64, shape would be (batch, 128)
FloatTensor["batch-1"]  # One less than the batch dimension
FloatTensor["features/2"]  # Half the features dimension
```

#### Supported Operators and Functions

> [!NOTE]
> Expressions _must_ never have spaces.

##### Operators

- `+` Addition
- `-` Subtraction
- `*` Multiplication
- `/` Integer division
- `^` Exponentiation

##### Functions

- `min(a,b)` Minimum of two expressions
- `max(a,b)` Maximum of two expressions

> [!WARNING]
> While nested function calls like `min(max(a,b),c)` are supported,
> combining function calls with other operators in the same expression
> (e.g., `min(1,batch)+max(2,channels)`) is not supported to simplify parsing.

### Symbolic Dimensions

Symbolic Dimensions
Named dimensions that ensure consistency across tensors:

```python
FloatTensor["batch channels"]  # A tensor with two dimensions
```

### Multi Dimensions

Named or anonymous dimension identifiers that may cover zero or more dimensions in the actual tensors.
Only one multi-dimension identifier is allowed per type hint.

```python
FloatTensor["... channels h w"] # anonymous dimension will not be matched across tensors
DoubleTensor["batch *channels features"] # named dimension which can be matched across tensors
```

## Argument and return typing

```python
from typing import Annotated
import torch
from dltype import FloatTensor, dltyped

@dltyped()
def add_tensors(
    x: Annotated[torch.Tensor, FloatTensor["batch features"]],
    y: Annotated[torch.Tensor, FloatTensor["batch features"]]
) -> Annotated[torch.Tensor, FloatTensor["batch features"]]:
    return x + y
```

## Pydantic model typing

```python
from typing import Annotated
from pydantic import BaseModel
import torch
from dltype import FloatTensor, IntTensor

class ImageBatch(BaseModel):
    # note the parenthesis instead of brackets for pydantic models
    images: Annotated[torch.Tensor, FloatTensor("batch 3 height width")]
    labels: Annotated[torch.Tensor, IntTensor("batch")]

    # All tensor validations happen automatically
    # Shape consistency is enforced across fields
```

## NamedTuple typing

We expose `@dltyped_namedtuple()` for NamedTuples.
`NamedTuples` are validated upon construction, beware that assignments or manipulations after construction are unchecked.

```python
@dltype.dltyped_namedtuple()
class MyNamedTuple(NamedTuple):
    tensor: Annotated[torch.Tensor, dltype.FloatTensor["b c h w"]]
    mask: Annotated[torch.Tensor, dltype.IntTensor["b h w"]]
    other: int
```

## @dataclass support

Similar to `NamedTuples` and pydantic `BaseModels`, `@dataclasses` may be decorated and validated.
The normal caveats apply in that we only validate at construction and not on assignment.
Therefore, we recommend using frozen `@dataclasses` when possible.

```python
from typing import Annotated
import torch
from dltype import FloatTensor, IntTensor, dltyped_dataclass

# order is important, we raise an error if dltyped_dataclass is applied below dataclass
# this is because the @dataclass decorator applies a bunch of source code modification that we don't want to have to hack around
@dltyped_dataclass()
@dataclass(frozen=True, slots=True)
class MyDataclass:
    images: Annotated[torch.Tensor, FloatTensor["batch 3 height width"]]
    labels: Annotated[torch.Tensor, IntTensor["batch"]]
```

## Optionals

We have no support for general unions of types to prevent confusing behavior when using runtime shape checking.
DLType only supports optional types (i.e. `Type | None`).
To annotate a tensor as being optional, see the example below.

```python
@dltype.dltyped()
def optional_tensor_func(tensor: Annotated[torch.Tensor, dltype.FloatTensor["b c h w"]] | None) -> torch.Tensor:
    if tensor is None:
        return torch.zeros(1, 3, 5, 5)
    return tensor
```

## Numpy and Tensor Mixing

```python
from typing import Annotated
import torch
import numpy as np
from dltype import FloatTensor, dltyped

@dltyped()
def transform_tensors(
    points: Annotated[np.ndarray, FloatTensor["N 3"]]
    transform: Annotated[torch.Tensor, FloatTensor["3 3"]]
) -> Annotated[torch.Tensor, FloatTensor["N 3"]]:
    return torch.from_numpy(points) @ transform
```

## Providing External Scope

There are situations that a runtime variable may influence the expected shape of a tensor.
To provide external scope to be used by dltype, you may implement the `DLTypeScopeProvider` protocol.
There are two flavors of this, one for methods, the other for free functions, both are shown below.
Using external scope providers for free functions is not an encouraged use case as it encourages keeping global state.
Additionally, free functions are generally stateless but this makes the type checking logic stateful and thus
makes the execution of the function impure.
We support this because there are certain scenarios where loading a configuration from a file and providing it as an expected dimension for some typed function may be useful and necessary.

```python

# Using `self` as the DLTypeScopeProvider in an object (this is the primary use case)
class MyModule(nn.Module):
    # ... some implementation details
    def __init__(self, config: MyConfig) -> None:
        self.cfg = config

    # the DLTypeScopeProvider protocol requires this function to be specified.
    def get_dltype_scope(self) -> dict[str, int]:
        """Return the DLType scope which is simply a dictionary of 'axis-name' -> dimension size."""
        return {"in_channel": self.cfg.in_channel}

    # "self" is a literal, not a string -- pyright will yell at you if this is wrong.
    # The first argument of the decorated function will be checked to obey the protocol before calling `get_dltype_scope`.
    @dltyped("self")
    def forward(
        self,
        tensor_1: Annotated[torch.Tensor, FloatTensor["batch num_voxel_features z y x"]],
        # NOTE: in_channel comes from the external scope and is used in the expression below to evaluate the 'channels' expected dimension
        tensor_2: Annotated[torch.Tensor, FloatTensor["batch channels=in_channel-num_voxel_features z y x"]]
    ) -> torch.Tensor:

## Using a scope provider for a free function

class MyProvider:
    def get_dltype_scope(self) -> dict[str, int]:
        # load some_value from a config file in the constructor
        # or fetch it from a singleton
        return {
            "dim1": self.some_value
        }

@dltyped(provider=MyProvider())
def free_function(tensor: FloatTensor["batch dim1"]) -> None:
    # ... implementation details, dim1 provided by the external scope
```

## Supported Types

- `FloatTensor`: For any precision floating point tensor. Is a superset of the following:
    - `Float16Tensor`: For any 16 bit floating point type. Is a superset of the following:
        - `IEEE754HalfFloatTensor`: For 16 bit floating point types that comply with the IEE 754 half-precision specification (notably, does not include `bfloat16`). For numpy tensors `Float16Tensor` is equal to `IEEE754HalfFloatTensor`. Use if you need to forbid usage of `bfloat16` for some reason. Otherwise prefer the `Float16Tensor` type for usage with mixed precision codebases.
        - `BFloat16Tensor`: For 16 bit floating point tensors following the [`bfloat16` format](https://en.wikipedia.org/wiki/Bfloat16_floating-point_format). Is not IEEE 754 compliant and is not supported by NumPy. Use if you need to write code that is `bfloat16` specific, otherwise prefer `Float16Tensor` for usage with a mixed precision instruction scope (such as `torch.amp`).
    - `Float32Tensor`: For single precision 32 bit floats.
    - `Float64Tensor`: For double precision 64 bit floats. Aliases to `DoubleTensor`.
    - Note that `np.float128` and `np.longdouble` will be considered as `FloatTensors` BUT do not exist as standalone types to be used by `dltype` ie. there is no `Float128Tensor` type. These types are not suported by torch, and only supported by numpy on certain platforms, thus we only "support" them insofar as they are considered floating point types.
- `IntTensor`: For integer tensors of any precision. Is a superset of the following:
    - `Int8Tensor`
    - `Int16Tensor`
    - `Int32Tensor`
    - `Int64Tensor`
- `BoolTensor`: For boolean tensors
- `TensorTypeBase`: Base class for any tensor which does not enforce any specific datatype, feel free to add custom validation logic by overriding the `check` method.

## Limitations

- In the current implementation, _every_ call will be checked, which may or may not be slow depending on how big the context is (it shouldn't be that slow).
- Pydantic default values are not checked.
- Only symbolic, literal, and expressions are allowed for dimension specifiers, f-string syntax from `jaxtyping` is not supported.
- Only torch tensors and numpy arrays are supported for now.
- Static checking is not supported, only runtime checks, though some errors will be caught statically by construction.
- We do not support container types (i.e. `list[TensorTypeBase]`) and we probably never will because parsing arbitrarily nested containers is very slow to do at runtime.
- We do not support union types, but we do support optionals.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "dltype",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "pytorch, numpy, shape check, type check",
    "author": null,
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/31/3a/c8bad76c8f37f1c0b52b6923b673e684fc16ad79dd94c635e36faa209281/dltype-0.3.1.tar.gz",
    "platform": null,
    "description": "# DL Type (Deep Learning Type Library)\n\nThis typing library is intended to replace jaxtyping for runtime type checking of torch tensors and numpy arrays.\n\nIn particular, we support two functions that beartype/jaxtype do not:\n\n1. Support for torch.jit.script/torch.compile/torch.jit.trace\n2. Pydantic model type annotations for torch tensors.\n\n## Features\n\n- Shape and Type Validation: Validate tensor shapes and types at runtime with symbolic dimension support.\n- Pydantic Integration: First-class support for tensor validation in Pydantic models.\n- Context-Aware Validation: Ensures consistency across multiple tensors in the same context.\n- ONNX/torch.compile Compatible: Works seamlessly with model export and compilation workflows.\n- Symbolic Dimensions: Support for named dimensions that enforce consistency.\n\n## Usage\n\nType hints are evaluated in a context in source-code order, so any references to dimension symbols must exist before an expression is evaluated.\n\n## Supported syntax\n\nDL Type supports four types of dimension specifications:\n\n### Scalars\n\nSingle element tensors with no shape\n\n```python\nIntTensor[None] # An integer tensor with a single value and no axes\n```\n\n### Literal Dimensions\n\nSimple integer dimensions with fixed sizes:\n\n```python\nFloatTensor[\"3 5\"]  # A tensor with shape (3, 5)\nFloatTensor[\"batch channels=3 height width\"] # identifiers set to dimensions for documentation\n```\n\n### Expressions\n\nMathematical expressions combining literals and symbols.\n\n```python\nFloatTensor[\"batch channels*2\"]  # If channels=64, shape would be (batch, 128)\nFloatTensor[\"batch-1\"]  # One less than the batch dimension\nFloatTensor[\"features/2\"]  # Half the features dimension\n```\n\n#### Supported Operators and Functions\n\n> [!NOTE]\n> Expressions _must_ never have spaces.\n\n##### Operators\n\n- `+` Addition\n- `-` Subtraction\n- `*` Multiplication\n- `/` Integer division\n- `^` Exponentiation\n\n##### Functions\n\n- `min(a,b)` Minimum of two expressions\n- `max(a,b)` Maximum of two expressions\n\n> [!WARNING]\n> While nested function calls like `min(max(a,b),c)` are supported,\n> combining function calls with other operators in the same expression\n> (e.g., `min(1,batch)+max(2,channels)`) is not supported to simplify parsing.\n\n### Symbolic Dimensions\n\nSymbolic Dimensions\nNamed dimensions that ensure consistency across tensors:\n\n```python\nFloatTensor[\"batch channels\"]  # A tensor with two dimensions\n```\n\n### Multi Dimensions\n\nNamed or anonymous dimension identifiers that may cover zero or more dimensions in the actual tensors.\nOnly one multi-dimension identifier is allowed per type hint.\n\n```python\nFloatTensor[\"... channels h w\"] # anonymous dimension will not be matched across tensors\nDoubleTensor[\"batch *channels features\"] # named dimension which can be matched across tensors\n```\n\n## Argument and return typing\n\n```python\nfrom typing import Annotated\nimport torch\nfrom dltype import FloatTensor, dltyped\n\n@dltyped()\ndef add_tensors(\n    x: Annotated[torch.Tensor, FloatTensor[\"batch features\"]],\n    y: Annotated[torch.Tensor, FloatTensor[\"batch features\"]]\n) -> Annotated[torch.Tensor, FloatTensor[\"batch features\"]]:\n    return x + y\n```\n\n## Pydantic model typing\n\n```python\nfrom typing import Annotated\nfrom pydantic import BaseModel\nimport torch\nfrom dltype import FloatTensor, IntTensor\n\nclass ImageBatch(BaseModel):\n    # note the parenthesis instead of brackets for pydantic models\n    images: Annotated[torch.Tensor, FloatTensor(\"batch 3 height width\")]\n    labels: Annotated[torch.Tensor, IntTensor(\"batch\")]\n\n    # All tensor validations happen automatically\n    # Shape consistency is enforced across fields\n```\n\n## NamedTuple typing\n\nWe expose `@dltyped_namedtuple()` for NamedTuples.\n`NamedTuples` are validated upon construction, beware that assignments or manipulations after construction are unchecked.\n\n```python\n@dltype.dltyped_namedtuple()\nclass MyNamedTuple(NamedTuple):\n    tensor: Annotated[torch.Tensor, dltype.FloatTensor[\"b c h w\"]]\n    mask: Annotated[torch.Tensor, dltype.IntTensor[\"b h w\"]]\n    other: int\n```\n\n## @dataclass support\n\nSimilar to `NamedTuples` and pydantic `BaseModels`, `@dataclasses` may be decorated and validated.\nThe normal caveats apply in that we only validate at construction and not on assignment.\nTherefore, we recommend using frozen `@dataclasses` when possible.\n\n```python\nfrom typing import Annotated\nimport torch\nfrom dltype import FloatTensor, IntTensor, dltyped_dataclass\n\n# order is important, we raise an error if dltyped_dataclass is applied below dataclass\n# this is because the @dataclass decorator applies a bunch of source code modification that we don't want to have to hack around\n@dltyped_dataclass()\n@dataclass(frozen=True, slots=True)\nclass MyDataclass:\n    images: Annotated[torch.Tensor, FloatTensor[\"batch 3 height width\"]]\n    labels: Annotated[torch.Tensor, IntTensor[\"batch\"]]\n```\n\n## Optionals\n\nWe have no support for general unions of types to prevent confusing behavior when using runtime shape checking.\nDLType only supports optional types (i.e. `Type | None`).\nTo annotate a tensor as being optional, see the example below.\n\n```python\n@dltype.dltyped()\ndef optional_tensor_func(tensor: Annotated[torch.Tensor, dltype.FloatTensor[\"b c h w\"]] | None) -> torch.Tensor:\n    if tensor is None:\n        return torch.zeros(1, 3, 5, 5)\n    return tensor\n```\n\n## Numpy and Tensor Mixing\n\n```python\nfrom typing import Annotated\nimport torch\nimport numpy as np\nfrom dltype import FloatTensor, dltyped\n\n@dltyped()\ndef transform_tensors(\n    points: Annotated[np.ndarray, FloatTensor[\"N 3\"]]\n    transform: Annotated[torch.Tensor, FloatTensor[\"3 3\"]]\n) -> Annotated[torch.Tensor, FloatTensor[\"N 3\"]]:\n    return torch.from_numpy(points) @ transform\n```\n\n## Providing External Scope\n\nThere are situations that a runtime variable may influence the expected shape of a tensor.\nTo provide external scope to be used by dltype, you may implement the `DLTypeScopeProvider` protocol.\nThere are two flavors of this, one for methods, the other for free functions, both are shown below.\nUsing external scope providers for free functions is not an encouraged use case as it encourages keeping global state.\nAdditionally, free functions are generally stateless but this makes the type checking logic stateful and thus\nmakes the execution of the function impure.\nWe support this because there are certain scenarios where loading a configuration from a file and providing it as an expected dimension for some typed function may be useful and necessary.\n\n```python\n\n# Using `self` as the DLTypeScopeProvider in an object (this is the primary use case)\nclass MyModule(nn.Module):\n    # ... some implementation details\n    def __init__(self, config: MyConfig) -> None:\n        self.cfg = config\n\n    # the DLTypeScopeProvider protocol requires this function to be specified.\n    def get_dltype_scope(self) -> dict[str, int]:\n        \"\"\"Return the DLType scope which is simply a dictionary of 'axis-name' -> dimension size.\"\"\"\n        return {\"in_channel\": self.cfg.in_channel}\n\n    # \"self\" is a literal, not a string -- pyright will yell at you if this is wrong.\n    # The first argument of the decorated function will be checked to obey the protocol before calling `get_dltype_scope`.\n    @dltyped(\"self\")\n    def forward(\n        self,\n        tensor_1: Annotated[torch.Tensor, FloatTensor[\"batch num_voxel_features z y x\"]],\n        # NOTE: in_channel comes from the external scope and is used in the expression below to evaluate the 'channels' expected dimension\n        tensor_2: Annotated[torch.Tensor, FloatTensor[\"batch channels=in_channel-num_voxel_features z y x\"]]\n    ) -> torch.Tensor:\n\n## Using a scope provider for a free function\n\nclass MyProvider:\n    def get_dltype_scope(self) -> dict[str, int]:\n        # load some_value from a config file in the constructor\n        # or fetch it from a singleton\n        return {\n            \"dim1\": self.some_value\n        }\n\n@dltyped(provider=MyProvider())\ndef free_function(tensor: FloatTensor[\"batch dim1\"]) -> None:\n    # ... implementation details, dim1 provided by the external scope\n```\n\n## Supported Types\n\n- `FloatTensor`: For any precision floating point tensor. Is a superset of the following:\n    - `Float16Tensor`: For any 16 bit floating point type. Is a superset of the following:\n        - `IEEE754HalfFloatTensor`: For 16 bit floating point types that comply with the IEE 754 half-precision specification (notably, does not include `bfloat16`). For numpy tensors `Float16Tensor` is equal to `IEEE754HalfFloatTensor`. Use if you need to forbid usage of `bfloat16` for some reason. Otherwise prefer the `Float16Tensor` type for usage with mixed precision codebases.\n        - `BFloat16Tensor`: For 16 bit floating point tensors following the [`bfloat16` format](https://en.wikipedia.org/wiki/Bfloat16_floating-point_format). Is not IEEE 754 compliant and is not supported by NumPy. Use if you need to write code that is `bfloat16` specific, otherwise prefer `Float16Tensor` for usage with a mixed precision instruction scope (such as `torch.amp`).\n    - `Float32Tensor`: For single precision 32 bit floats.\n    - `Float64Tensor`: For double precision 64 bit floats. Aliases to `DoubleTensor`.\n    - Note that `np.float128` and `np.longdouble` will be considered as `FloatTensors` BUT do not exist as standalone types to be used by `dltype` ie. there is no `Float128Tensor` type. These types are not suported by torch, and only supported by numpy on certain platforms, thus we only \"support\" them insofar as they are considered floating point types.\n- `IntTensor`: For integer tensors of any precision. Is a superset of the following:\n    - `Int8Tensor`\n    - `Int16Tensor`\n    - `Int32Tensor`\n    - `Int64Tensor`\n- `BoolTensor`: For boolean tensors\n- `TensorTypeBase`: Base class for any tensor which does not enforce any specific datatype, feel free to add custom validation logic by overriding the `check` method.\n\n## Limitations\n\n- In the current implementation, _every_ call will be checked, which may or may not be slow depending on how big the context is (it shouldn't be that slow).\n- Pydantic default values are not checked.\n- Only symbolic, literal, and expressions are allowed for dimension specifiers, f-string syntax from `jaxtyping` is not supported.\n- Only torch tensors and numpy arrays are supported for now.\n- Static checking is not supported, only runtime checks, though some errors will be caught statically by construction.\n- We do not support container types (i.e. `list[TensorTypeBase]`) and we probably never will because parsing arbitrarily nested containers is very slow to do at runtime.\n- We do not support union types, but we do support optionals.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "An extremely lightweight typing library for torch tensors or numpy arrays. Supports runtime shape checking and data type validation.",
    "version": "0.3.1",
    "project_urls": {
        "homepage": "https://github.com/stackav-oss/dltype",
        "repository": "https://github.com/stackav-oss/dltype.git"
    },
    "split_keywords": [
        "pytorch",
        " numpy",
        " shape check",
        " type check"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "588f14512b405cc28b9184db9273334a3d34928b7ef449e7f7868f7e73b890fb",
                "md5": "922320b593764eaf54f8af64ba5f9f97",
                "sha256": "7a1fd04bcd17c0cf44d10b09d3e14939bda7549f31ceb8aae5303a44b27f6e2c"
            },
            "downloads": -1,
            "filename": "dltype-0.3.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "922320b593764eaf54f8af64ba5f9f97",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 31823,
            "upload_time": "2025-08-18T13:42:26",
            "upload_time_iso_8601": "2025-08-18T13:42:26.220684Z",
            "url": "https://files.pythonhosted.org/packages/58/8f/14512b405cc28b9184db9273334a3d34928b7ef449e7f7868f7e73b890fb/dltype-0.3.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "313ac8bad76c8f37f1c0b52b6923b673e684fc16ad79dd94c635e36faa209281",
                "md5": "50155d560ed98f03411b2e8d7207ba3d",
                "sha256": "f8478083129c5004c5434105cdf3eb4d68742944312f6b3da75ca937e9bf86f4"
            },
            "downloads": -1,
            "filename": "dltype-0.3.1.tar.gz",
            "has_sig": false,
            "md5_digest": "50155d560ed98f03411b2e8d7207ba3d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 30631,
            "upload_time": "2025-08-18T13:42:27",
            "upload_time_iso_8601": "2025-08-18T13:42:27.524914Z",
            "url": "https://files.pythonhosted.org/packages/31/3a/c8bad76c8f37f1c0b52b6923b673e684fc16ad79dd94c635e36faa209281/dltype-0.3.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-18 13:42:27",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "stackav-oss",
    "github_project": "dltype",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "dltype"
}
        
Elapsed time: 1.75041s