A library to help with the management of alternative implementations of functions
Project description
alternative
A tiny, dependency-free library for managing multiple implementations of the same function — especially when you're iterating toward faster or cleaner versions and want those choices to stay explicit, testable, and safe.
Full documentation is available on Read the Docs. The documentation source lives in docs/.
Why use this?
When optimizing a hot path, it’s common to accumulate:
- a trusted reference implementation
- one or more candidate rewrites
- tests to keep them equivalent
- benchmarks to validate wins
alternative keeps that workflow tidy by making implementation registration and selection first-class.
The same model works for module functions, instance methods, class methods, and static methods. Public typing is shipped in alternative.pyi, so type checkers and IDEs can see the original call signatures instead of losing them behind the decorator objects.
Quick example
import alternative
@alternative.reference
def constant_number():
return 1
@constant_number.add(default=True)
def alternative_constant_number():
return 2
@constant_number.add
def unused_alternative_constant_number():
return 3
# the default=True implementation is used if specified;
# otherwise, the reference is the implicit default
assert constant_number() == 2
# alternative implementations still act like themselves
assert unused_alternative_constant_number() == 3
See the quickstart for registration patterns, defaults, and method examples.
Methods and descriptors
Decorate instance methods directly. For @classmethod and @staticmethod, put @alternative.reference and .add(...) outside the built-in descriptor decorator:
import alternative
class Parser:
def __init__(self, value: str = ""):
self.value = value
@alternative.reference
def parse(self, value: str) -> int:
return int(value.strip())
@parse.add(default=True)
def parse_fast(self, value: str) -> int:
return int(value)
@alternative.reference
@classmethod
def from_text(cls, value: str) -> "Parser":
return cls(value.strip())
@from_text.add(default=True)
@classmethod
def from_text_fast(cls, value: str) -> "Parser":
return cls(value)
@alternative.reference
@staticmethod
def is_valid(value: str) -> bool:
return value.strip().isdigit()
@is_valid.add(default=True)
@staticmethod
def is_valid_fast(value: str) -> bool:
return value.isdigit()
Calling through an instance or class follows normal Python binding rules, and direct implementation calls bind the same way. The full descriptor examples are in Use Methods and Testing Methods.
Pytest features
The pytest helpers are documented in the pytest integration guide.
Pairwise equivalence checks
Use pytest_parametrize_pairs(...) to compare the reference against each candidate implementation.
Single-implementation parametrization
Use pytest_parametrize(...) to run one test body across all implementations.
Runtime tools
Alternatives.measure(...) runs every implementation with the same arguments and measures the results with a callable you provide. See Measure Implementations.
Safety guarantees
The library tries to avoid unpleasant surprises caused by import order or accidental state changes:
- The selected implementation cannot be changed once it has been used.
- Implementations cannot be added once they have been inspected, reducing the chance that tests only covered a subset.
Debug mode
Set ALTERNATIVE_DEBUG=1 to record where critical state changes happened (like selecting defaults or inspecting implementations). These locations are surfaced in error messages to make stateful issues easier to track down.
When debug mode is enabled, each Implementation also captures a label with its registration call-site. This label appears in repr(...) and selected debug errors, making it easier to disambiguate implementation instances.
Typing and IDEs
alternative ships a top-level stub file, alternative.pyi, for the public typing surface. It includes overloads for descriptor binding, transparent method/classmethod/staticmethod decoration, and the pytest helpers, while alternative.py stays focused on runtime behavior.
The typing probes are checked with mypy, pyright, pyrefly, and a headless PyCharm inspection script: scripts/pycharm-type-probes.sh. The PyCharm probe covers type assertions, unresolved references, and type checker warnings in typing_tests/type_probes.py.
Known PyCharm caveat: JetBrains PyNestedDecoratorsInspection currently reports a false-positive for correctly typed decorators stacked outside @classmethod or @staticmethod. Runtime behavior and type resolution are correct, and the project does not require # noinspection PyTypeChecker call-site suppressions for these examples.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file alternative-0.2.0.tar.gz.
File metadata
- Download URL: alternative-0.2.0.tar.gz
- Upload date:
- Size: 77.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba498997dcff8d52f3a4ad2d73f10417c36bc5fe9b965a55586a3ea5c36af84f
|
|
| MD5 |
6390aa5b4e017a5f423f5250c3ff4bce
|
|
| BLAKE2b-256 |
7e08114cbad987a4ed231628129c16c704a891a3792f55d4f274bba7d82edb8d
|
Provenance
The following attestation bundles were made for alternative-0.2.0.tar.gz:
Publisher:
publish.yml on Code0x58/alternative
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
alternative-0.2.0.tar.gz -
Subject digest:
ba498997dcff8d52f3a4ad2d73f10417c36bc5fe9b965a55586a3ea5c36af84f - Sigstore transparency entry: 1495058953
- Sigstore integration time:
-
Permalink:
Code0x58/alternative@6822f93406277014e532e729e36e3ef691700760 -
Branch / Tag:
refs/tags/0.2.0 - Owner: https://github.com/Code0x58
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6822f93406277014e532e729e36e3ef691700760 -
Trigger Event:
release
-
Statement type:
File details
Details for the file alternative-0.2.0-py3-none-any.whl.
File metadata
- Download URL: alternative-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76df2a57db0d592c771713a2c1a743de7781144e28d53bff48cfe1387959fe71
|
|
| MD5 |
7f05d996c3fe9a12796cdf983ebc7c9a
|
|
| BLAKE2b-256 |
28e03284f35242e5bb775bf5e9eff9fdfad8350a675e85b222472fc25c3ff9bb
|
Provenance
The following attestation bundles were made for alternative-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on Code0x58/alternative
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
alternative-0.2.0-py3-none-any.whl -
Subject digest:
76df2a57db0d592c771713a2c1a743de7781144e28d53bff48cfe1387959fe71 - Sigstore transparency entry: 1495059444
- Sigstore integration time:
-
Permalink:
Code0x58/alternative@6822f93406277014e532e729e36e3ef691700760 -
Branch / Tag:
refs/tags/0.2.0 - Owner: https://github.com/Code0x58
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6822f93406277014e532e729e36e3ef691700760 -
Trigger Event:
release
-
Statement type: