phantom-types is a Python library that enables the creation of 'phantom types' to enforce type safety at compile time without incurring runtime overhead. It leverages Python's `__instancecheck__` protocol and boolean predicates to allow developers to define stricter type constraints, helping to make 'illegal states unrepresentable' and mitigate 'shotgun parsing'. The library is currently at version 3.0.2 and follows semantic versioning after its 1.0 release, with new versions released periodically to add features, fix bugs, and maintain compatibility.
pip install phantom-typesVerified import paths — ran on the pinned version, not inferred.
This quickstart demonstrates how to define a simple phantom type `Name` that narrows the `str` type to only accept specific values ('Jane' or 'Joe'). It shows both explicit parsing using `Name.parse()` and leveraging Python's `isinstance()` for type narrowing recognized by static type checkers. Invalid inputs are caught at compile time by type checkers, preventing runtime errors.
Consult the changelog for specific migration steps if upgrading from <1.0 or if moving to 2.0.0+ from Python 3.7. Ensure your environment uses Python 3.9 or newer.
To resolve, create a new metaclass that inherits from both `PhantomMeta` (the metaclass used by `Phantom`) and the other custom metaclass, then use this new metaclass for your composite phantom type. Example: `class NewMeta(PhantomMeta, OldMeta): pass; class New(Old, Phantom, metaclass=NewMeta): ...`
Only apply phantom types to immutable base types (e.g., `str`, `int`, `tuple`, `datetime.datetime`). Avoid using them with mutable types like `list` or custom mutable objects where internal state can change.
Always ensure the phantom type explicitly inherits from its runtime base type as the first base class (e.g., `class MyPhantom(MyBaseType, Phantom, ...): ...`).
Install the `dateutil` extra: `pip install 'phantom-types[dateutil]'` or `pip install phantom-types[all]`.
Explicitly convert the value using the phantom type's `parse` method (e.g., `greet(Name.parse(my_string))`) or assert its type at runtime to inform the static type checker (e.g., `assert isinstance(my_string_var, Name); greet(my_string_var)`).
Ensure the phantom type inherits directly from its runtime type as the first base class. For instance, `class UTCDateTime(datetime.datetime, Phantom, predicate=is_utc): ...` instead of `class UTCDateTime(Phantom, predicate=is_utc): ...`.