# tsl wraps PyG and Lightning with pinned version ceilings and one compile switch

> tsl is a PyTorch library for spatiotemporal research, built on PyTorch Geometric, PyTorch Lightning and Hydra, with packaged datasets, missing-data handling and a graph-compilation switch gated on a per-model flag. The dependency ranges all have upper bounds, and the newest tagged release predates the recent commits by two years.

**TorchSpatiotemporal/tsl** — tsl: a PyTorch library for processing spatiotemporal data.

- Repository: https://github.com/TorchSpatiotemporal/tsl
- Website: https://torch-spatiotemporal.readthedocs.io/
- Stars: 388 · Forks: 37
- Language: Python
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/torchspatiotemporal-tsl

## Every dependency is capped on both ends, not just floored

The dependency list in `pyproject.toml` is unusually explicit about what it refuses. `numpy>=1.26,<3`, `torch>=2.2,<2.13`, `torch_geometric>=2.4,<3`, `pytorch-lightning>=2.2,<3`, `hydra-core>=1.3,<1.4`, `omegaconf>=2.3,<2.4`, `pandas>=2,<3` and `torchmetrics>=1,<2`. Nothing is left open-ended.

The intent is defensible. PyTorch Geometric and Lightning both move breaking changes, and an uncapped range on a research library tends to produce breakage reports that are really upstream release problems. The cost is that you cannot take a new PyTorch point release until tsl widens the ceiling, and the README does not explain where the numbers come from or how often they are revisited.

Two dependencies sit in that list without being mentioned anywhere in the README. `tables` is the PyTables binding, which pulls in an HDF5 stack, and `einops` handles tensor axis reordering. If you are sizing an environment or working on a platform where HDF5 wheels are scarce, that `tables` dependency is the line to check first.

Python support runs from 3.10 to 3.14 by classifier, with `requires-python = ">=3.10"`. The licence is MIT and the authors are Ivan Marisca and Andrea Cini.

## uv with --torch-backend=auto replaces a separate framework install

The recommended install path is uv, and the interesting part is one flag:

```bash
uv venv --python 3.10
uv pip install torch-spatiotemporal --torch-backend=auto
```

`--torch-backend=auto` lets uv select the PyTorch build, taking CUDA wheels on an NVIDIA machine with a compatible driver and CPU wheels otherwise. The point is that tsl does not ask you to install PyTorch first and then install itself into that environment. uv resolves PyTorch and PyG alongside tsl in a single resolution, which removes the version-mismatch class of error where a torch build and a compiled extension disagree.

Windows PowerShell gets the same two lines. On macOS the PyTorch wheels are the platform's own, and GPU work runs through MPS rather than CUDA, so there is no CUDA selection to make there.

For development work and tests, the extras go into the same environment:

```bash
uv pip install -e ".[dev]" --torch-backend=auto
uv run pytest
```

That editable install is also the documented setup for a local project environment. Slow tests are marked and can be excluded by name rather than by remembering which files are heavy:

```bash
uv run pytest -m "not slow"
```

The default `pytest` invocation picks up its coverage settings from `pyproject.toml`.

## conda_env.yml ships CUDA by default, so CPU conda needs an edit

The conda route still exists and carries a caveat that the uv route does not:

```bash
conda env create -f conda_env.yml
conda activate tsl
```

The file is described as remaining CUDA-oriented by default. To get a CPU-only conda environment you are told to remove the `nvidia` channel and the `pytorch-cuda` dependency from `conda_env.yml` yourself, which means editing a tracked file in the repository rather than passing a flag. Anyone who installs and then discovers the wrong backend ends up with a modified checkout, or with a local edit to remember.

That asymmetry is the practical argument for uv here. The wheel selection is delegated to the resolver, where a mistake is a deleted virtual environment, rather than being encoded in a YAML file that has to be edited per machine.

Two optional extras round out the picture. `full` adds `holidays`, which matters if your time series carry calendar features and you need holiday alignment across regions. `doc` pulls in Sphinx, `furo`, `myst-nb`, `sphinx-design`, `sphinx-hoverxref`, `sphinxext-opengraph`, `docutils`, `sphinx-copybutton`, matplotlib and the `full` extra, which is the set needed to build the Read the Docs site the README links to.

## torch-sparse is optional, and its wheels must match your build exactly

One compiled extension sits outside the normal install. `torch-sparse` is needed only if you want `torch_sparse.SparseTensor` adjacency matrices, and it requires `torch-scatter` at runtime, so both have to be present together. The requirement is exact rather than approximate: the wheels must match the precise PyTorch and CUDA build you already have.

The commented lines in the install block show the shape, with the version placeholders left in:

```bash
# uv pip install torch-scatter torch-sparse -f https://data.pyg.org/whl/torch-${TORCH}+${CUDA}.html
```

So a working tsl install can still fail later, at graph construction time, on a machine where the dense path is fine and the sparse one is not. The fix is picking from the PyG wheel index for your exact combination, not upgrading anything.

This is the one place where the tidy uv story does not hold. Everything else is resolved together, but these two packages are indexed by build rather than resolved by version, so they stay a manual step.

## Graph compilation is opt-in per model, and Hydra exposes it from the command line

tsl adds a compile switch on top of PyTorch's standard module API, but it is not available everywhere. Models marked with `ModelClass.can_be_compiled = True` are the ones covered by full-graph compilation tests, so the flag on your chosen model is the gate to check first.

Given a model that passes it, compilation is PyTorch's own call:

```python
model.compile(mode="reduce-overhead")
```

The forecasting and imputation examples reach the same setting through Hydra rather than in Python:

```bash
python examples/forecasting/run_traffic_experiment.py \
    model=dcrnn dataset=la compile.enabled=true compile.mode=reduce-overhead
```

`compile.enabled` is the Hydra-side switch and `compile.mode` takes the same value string. That command also tells you what the example surface looks like: a model key, a dataset key, and the run script under `examples/forecasting/`.

Two limits are stated. There is an initial warm-up cost, so a single short run will not show the benefit, and compilation suits repeated training or inference with stable tensor shapes, which is the normal case for a fixed benchmark and not the case for ragged variable-length data. The README also points to a migration audit for the tested model matrix and current limitations, so the honest answer to whether your model compiles is in that audit rather than in the flag.

## The newest tagged release is v0.9.5 from July 2024

The commit history and the release history tell different stories. The last push to the default branch was on 2026-09-25, which is recent. The most recent tagged release is v0.9.5 from 2024-07-18, with v0.9.4 from 2023-08-18 and v0.9.3 from 2023-06-01 before it.

So the maintenance question has two answers depending on what you need. Source is moving, with the install instructions, the compile path and the dependency pins all showing signs of recent work. A tagged artefact is two years old relative to that source, which means anything that depends on a pinned `torch-spatiotemporal==X.Y.Z` is installing something considerably behind the default branch.

The project classifies itself as `Development Status :: 5 - Production/Stable`, and it is a CITATION.cff and docs project with a Read the Docs site, so it is a research library rather than an application. The gap between the two histories is the thing to weigh: `uv pip install torch-spatiotemporal` pulls from PyPI and gets the older tag, while a clone of `main` gets the current state, and the two will not behave identically on compile support or dependency ceilings.

The MIT licence places no restriction on either route.

## Conclusion

Adopt tsl if your research sits on PyTorch Geometric anyway and you want packaged spatiotemporal datasets and missing-value preprocessing instead of your own loaders. Do not adopt it if your work needs a PyTorch or PyG release newer than the pinned ceilings, or if you require a released package rather than a checkout. Verify first that your installed PyTorch falls inside `torch>=2.2,<2.13` and your Python inside 3.10 to 3.14, since every dependency in `pyproject.toml` is capped on both ends and a resolver will refuse rather than warn.

## FAQ

### Which PyTorch versions does tsl support?

PyTorch 2.2 or newer and below 2.13, PyG 2.4 or newer and below 3, and NumPy 1.26 or newer and below 3. Every dependency is capped at both ends, so a resolver will refuse a version outside the range rather than warn about it.

### Do I need to install PyTorch separately before installing tsl?

No. uv resolves PyTorch and PyG alongside tsl in one step, and `--torch-backend=auto` selects CUDA wheels on a compatible NVIDIA machine and CPU wheels otherwise. On macOS, GPU work goes through MPS rather than CUDA.

### When is torch-sparse required in tsl?

Only for `torch_sparse.SparseTensor` adjacency matrices. It needs `torch-scatter` at runtime, and both wheels must match the exact PyTorch and CUDA build already installed, picked from the PyG wheel index rather than resolved by version.

### How do I compile a model in tsl?

Check that the model sets `ModelClass.can_be_compiled = True`, since that flag marks the models covered by full-graph compilation tests, then call `model.compile(mode="reduce-overhead")`. Examples expose the same through Hydra with `compile.enabled=true` and `compile.mode=reduce-overhead`.

### How do I skip the slow tests in tsl?

Run `uv run pytest -m "not slow"`. The default `uv run pytest` picks up its coverage settings from `pyproject.toml`, and slow tests are marked so they can be excluded by marker rather than by name.

### Is there a conda environment file for tsl?

Yes, `conda_env.yml` is still included and creates an environment named tsl. It is CUDA-oriented by default, so a CPU-only conda setup means removing the `nvidia` channel and the `pytorch-cuda` dependency from that file yourself.

## Sources

- [License: MIT](https://github.com/TorchSpatiotemporal/tsl/blob/main/LICENSE)
- [Project website](https://torch-spatiotemporal.readthedocs.io/)
- [README](https://github.com/TorchSpatiotemporal/tsl/blob/main/README.md)
- [Releases](https://github.com/TorchSpatiotemporal/tsl/releases)
- [TorchSpatiotemporal/tsl on GitHub](https://github.com/TorchSpatiotemporal/tsl)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/torchspatiotemporal-tsl
