🐦 pyvers
A Python library for dynamic dispatch based on module versions and backends.
What can you do with pyvers?
- 🔄 Handle breaking changes between different versions of a library without cluttering your code
- 🔀 Switch seamlessly between different backend implementations (e.g., CPU vs GPU)
- ✨ Support multiple versions of a dependency in the same codebase without complex if/else logic
- 🚀 Write version-specific optimizations while maintaining backward compatibility
- 🧹 Keep your code clean and maintainable while supporting multiple environments
Usage
pyvers lets you write version-specific implementations that are automatically selected based on the installed package version or backend. Here's a simple example using the register API (recommended):
from pyvers import implement_for, register_backend, get_backend, set_backend
# Register numpy backend - you could register more than one backend!
register_backend(group="numpy", backends={"numpy": "numpy"})
# Define the function with @implement_for, then register version-specific implementations
@implement_for("numpy")
def create_mask(arr):
"""Create a boolean mask marking positive values."""
raise NotImplementedError("No matching numpy version found")
# Function for NumPy < 2.0 (using bool8)
@create_mask.register(from_version=None, to_version="2.0.0")
def _(arr):
np = get_backend("numpy")
return np.array([x > 0 for x in arr], dtype=np.bool8)
# Function for NumPy >= 2.0 (using bool_)
@create_mask.register(from_version="2.0.0")
def _(arr):
np = get_backend("numpy")
return np.array([x > 0 for x in arr], dtype=np.bool_)
# The correct implementation is automatically chosen based on your NumPy version
result = create_mask([-1, 2, -3, 4])
print("NumPy result:", result)
The .register() API follows the same pattern as functools.singledispatch. Using _ as the function name is a Python convention that linters recognize, so you don't need # noqa comments.
Alternative: Traditional API
You can also use the traditional decorator pattern (requires # noqa: F811 for linters):
@implement_for("numpy", from_version=None, to_version="2.0.0")
def create_mask(arr):
np = get_backend("numpy")
return np.array([x > 0 for x in arr], dtype=np.bool8)
@implement_for("numpy", from_version="2.0.0")
def create_mask(arr): # noqa: F811
np = get_backend("numpy")
return np.array([x > 0 for x in arr], dtype=np.bool_)
Check out the examples folder for more advanced use cases:
- Switching between NumPy and JAX.numpy backends
- Handling CPU (SciPy) vs GPU (CuPy) implementations
- Managing breaking changes in PyTorch 2.0
- Supporting both gym and gymnasium APIs
Installation
pip install pyvers
Features
Version-based dispatch
Automatically select the right implementation based on package versions:
@implement_for("torch")
def optimize_model(model):
"""Optimize a model using version-appropriate techniques."""
raise NotImplementedError("No matching torch version")
@optimize_model.register(from_version="2.0.0")
def _(model):
return torch.compile(model) # Only available in PyTorch 2.0+
@optimize_model.register(from_version=None, to_version="2.0.0")
def _(model):
return model # Fallback for older versions
Backend switching
Easily switch between different implementations:
# Register both backends
register_backend(group="numpy", backends={
"numpy": "numpy",
"jax.numpy": "jax.numpy"
})
# Use context manager to switch backends
with set_backend("numpy", "jax.numpy"):
result = your_function() # Uses JAX
with set_backend("numpy", "numpy"):
result = your_function() # Uses NumPy
Dynamic imports
Backends are imported only when needed, so you can have optional dependencies:
register_backend(group="sparse", backends={
"scipy.sparse": "scipy.sparse", # CPU backend
"cupyx.scipy.sparse": "cupyx.scipy.sparse" # GPU backend - does NOT require cupy to be installed!
})
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Development
Setup
- Clone the repository
- Install Poetry (package manager)
- Install dependencies:
poetry install
Running Tests
poetry run pytest
This will run the test suite with coverage reporting.
Code Quality
We use Ruff for linting and code formatting. Ruff combines multiple Python linters into a single fast, unified tool.
To check your code:
poetry run ruff check .
To automatically fix issues:
poetry run ruff check --fix .
Ruff is configured to:
- Follow PEP 8 style guide
- Sort imports automatically
- Check for common bugs and code complexity
- Target Python 3.12+
See pyproject.toml for the complete linting configuration.
License
This project is licensed under the MIT License - see the LICENSE file for details.
## Citation
pyvers was developped as part of TorchRL.
Metadata
Release files for pyvers 0.2.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyvers-0.2.3.tar.gz | 12.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyvers-0.2.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.1 kB
Release files / pyvers-0.2.3.tar.gz
| Download URL | pyvers-0.2.3.tar.gz |
|---|---|
| Size | 12.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c4b81c3a033963245e124cdecb052783c9c4cea3bb08c051833af1c44faa6283
|
|
BLAKE2b-256 checksum How to use checksums |
62219daf8da2793d112a04b46ac33ab9046c91b0af8292cd93b3cfdd07ff7169
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 9, 2026.
Transparency logRelease files / pyvers-0.2.3-py3-none-any.whl
| Download URL | pyvers-0.2.3-py3-none-any.whl |
|---|---|
| Size | 11.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6f5b5612f2f4bd08caa49baa70fc5f875fc7da701a5385c13e244eea6b8114dd
|
|
BLAKE2b-256 checksum How to use checksums |
2d8d63787e8feda59d981ebc953b6581ccab3c97cf7bfe0a6a407c07b50fc86c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 9, 2026.
Transparency log