Types#
Base classes#
Use Phantom
to create arbitrary phantom types using boolean predicates.
from phantom import Phantom
def is_big(value: int) -> bool:
return value > 5
class Big(int, Phantom, predicate=is_big):
...
assert isinstance(10, Big) # this passes
- class phantom.Phantom(instance)[source]#
Bases:
PhantomBase
,Generic
[T
]Base class for predicate-based phantom types.
Class arguments
predicate: Predicate[T] | None
- Predicate function used for instance checks. Can beNone
if the type is abstract.bound: type[T] | None
- Bound used to check values before passing them to the type’s predicate function. This will often but not always be the same as the runtime type that values of the phantom type are represented as. If this is not provided as a class argument, it’s attempted to be resolved in order from an implicit bound (any bases of the type that come beforePhantom
), or inherited from super phantom types that provide a bound. Can beNone
if the type is abstract.abstract: bool
- Set toTrue
to create an abstract phantom type. This allows deferring definitions ofpredicate
andbound
to concrete subtypes.
-
__bound__:
typing.ClassVar
[type
]#
- classmethod __get_validators__()#
Hook that makes phantom types compatible with pydantic.
- Return type:
typing.Iterator
[typing.Callable
[[object
],typing.TypeVar
(Derived
, bound= PhantomBase)]]
- classmethod __modify_schema__(field_schema)#
This final method is called by pydantic and collects overrides from
Phantom.__schema__()
. Override__schema__()
to provide custom schema representations for phantom types.- Parameters:
field_schema (
dict
) –- Return type:
None
- classmethod __schema__()#
Hook for providing schema metadata. Override in subclasses to customize a types schema representation. See pydantic’s documentation on
__modify_schema__()
for more information. This hook differs to pydantic’s__modify_schema__()
and expects subclasses to instantiate new dicts instead of mutating a given one.Example:
class Name(str, Phantom, predicate=...): @classmethod def __schema__(cls): return {**super().__schema__(), "description": "A name type"}
- Return type:
phantom.schema.Schema
- classmethod parse(instance)#
Parse an arbitrary value into a phantom type.
- Raises:
TypeError –
- Parameters:
instance (
object
) –- Return type:
typing.TypeVar
(Derived
, bound= PhantomBase)
Boolean#
Types describing objects that coerce to either True
or False
respectively when
calling bool()
on them.
Country codes#
Exposes a CountryCode
type that is a union of a Literal
containing all ISO3166 alpha-2 codes, and a phantom type that parses alpha-2 codes at
runtime. This allows mixing statically known values with runtime-parsed values, like
so:
countries: tuple[CountryCode] = ("SE", "DK", ParsedAlpha2.parse("FR"))
- phantom.iso3166.LiteralAlpha2#
Literal of all ISO3166 alpha-2 codes.
alias of
Literal
[‘AF’, ‘AX’, ‘AL’, ‘DZ’, ‘AS’, ‘AD’, ‘AO’, ‘AI’, ‘AQ’, ‘AG’, ‘AR’, ‘AM’, ‘AW’, ‘AU’, ‘AT’, ‘AZ’, ‘BS’, ‘BH’, ‘BD’, ‘BB’, ‘BY’, ‘BE’, ‘BZ’, ‘BJ’, ‘BM’, ‘BT’, ‘BO’, ‘BQ’, ‘BA’, ‘BW’, ‘BV’, ‘BR’, ‘IO’, ‘BN’, ‘BG’, ‘BF’, ‘BI’, ‘KH’, ‘CM’, ‘CA’, ‘CV’, ‘KY’, ‘CF’, ‘TD’, ‘CL’, ‘CN’, ‘CX’, ‘CC’, ‘CO’, ‘KM’, ‘CG’, ‘CD’, ‘CK’, ‘CR’, ‘CI’, ‘HR’, ‘CU’, ‘CW’, ‘CY’, ‘CZ’, ‘DK’, ‘DJ’, ‘DM’, ‘DO’, ‘EC’, ‘EG’, ‘SV’, ‘GQ’, ‘ER’, ‘EE’, ‘ET’, ‘FK’, ‘FO’, ‘FJ’, ‘FI’, ‘FR’, ‘GF’, ‘PF’, ‘TF’, ‘GA’, ‘GM’, ‘GE’, ‘DE’, ‘GH’, ‘GI’, ‘GR’, ‘GL’, ‘GD’, ‘GP’, ‘GU’, ‘GT’, ‘GG’, ‘GN’, ‘GW’, ‘GY’, ‘HT’, ‘HM’, ‘VA’, ‘HN’, ‘HK’, ‘HU’, ‘IS’, ‘IN’, ‘ID’, ‘IR’, ‘IQ’, ‘IE’, ‘IM’, ‘IL’, ‘IT’, ‘JM’, ‘JP’, ‘JE’, ‘JO’, ‘KZ’, ‘KE’, ‘KI’, ‘KP’, ‘KR’, ‘XK’, ‘KW’, ‘KG’, ‘LA’, ‘LV’, ‘LB’, ‘LS’, ‘LR’, ‘LY’, ‘LI’, ‘LT’, ‘LU’, ‘MO’, ‘MK’, ‘MG’, ‘MW’, ‘MY’, ‘MV’, ‘ML’, ‘MT’, ‘MH’, ‘MQ’, ‘MR’, ‘MU’, ‘YT’, ‘MX’, ‘FM’, ‘MD’, ‘MC’, ‘MN’, ‘ME’, ‘MS’, ‘MA’, ‘MZ’, ‘MM’, ‘NA’, ‘NR’, ‘NP’, ‘NL’, ‘NC’, ‘NZ’, ‘NI’, ‘NE’, ‘NG’, ‘NU’, ‘NF’, ‘MP’, ‘NO’, ‘OM’, ‘PK’, ‘PW’, ‘PS’, ‘PA’, ‘PG’, ‘PY’, ‘PE’, ‘PH’, ‘PN’, ‘PL’, ‘PT’, ‘PR’, ‘QA’, ‘RE’, ‘RO’, ‘RU’, ‘RW’, ‘BL’, ‘SH’, ‘KN’, ‘LC’, ‘MF’, ‘PM’, ‘VC’, ‘WS’, ‘SM’, ‘ST’, ‘SA’, ‘SN’, ‘RS’, ‘SC’, ‘SL’, ‘SG’, ‘SX’, ‘SK’, ‘SI’, ‘SB’, ‘SO’, ‘ZA’, ‘GS’, ‘SS’, ‘ES’, ‘LK’, ‘SD’, ‘SR’, ‘SJ’, ‘SZ’, ‘SE’, ‘CH’, ‘SY’, ‘TW’, ‘TJ’, ‘TZ’, ‘TH’, ‘TL’, ‘TG’, ‘TK’, ‘TO’, ‘TT’, ‘TN’, ‘TR’, ‘TM’, ‘TC’, ‘TV’, ‘UG’, ‘UA’, ‘AE’, ‘GB’, ‘US’, ‘UM’, ‘UY’, ‘UZ’, ‘VU’, ‘VE’, ‘VN’, ‘VG’, ‘VI’, ‘WF’, ‘EH’, ‘YE’, ‘ZM’, ‘ZW’]
- class phantom.iso3166.ParsedAlpha2(instance)[source]#
Bases:
str
,Phantom
- phantom.iso3166.is_alpha2_country_code(value)#
- Parameters:
value (
object
) –- Return type:
bool
Datetime#
Types for narrowing on the builtin datetime types.
These types can be used without installing any extra dependencies, however, to parse
strings, python-dateutil must be installed or a
phantom.errors.MissingDependency
error will be raised when calling parse.
You can install python-dateutil by using the [dateutil]
or [all]
extras.
- class phantom.datetime.TZAware(instance)[source]#
Bases:
datetime
,Phantom
A type for helping ensure that
datetime
objects are always timezone aware.>>> isinstance(datetime.datetime.now(), TZAware) False >>> isinstance(datetime.datetime.now(tz=datetime.timezone.utc), TZAware) True
- class phantom.datetime.TZNaive(instance)[source]#
Bases:
datetime
,Phantom
>>> isinstance(datetime.datetime.now(), TZNaive) True >>> isinstance(datetime.datetime.now(tz=datetime.timezone.utc), TZNaive) False
Negated types#
This module provides a single type: SequenceNotStr
. This type is equivalent
to typing.Sequence
except it excludes values of type str
and
bytes
from the set of valid instances. This can be useful when you want to
eliminate the easy mistake of forgetting to wrap a string value in a containing
sequence.
Numeric intervals#
Types for describing narrower sets of numbers than builtin numeric types like int
and float
. Use the provided base classes to build custom intervals. For example, to
represent number in the closed range [0, 100]
for a volume control you would define
a type like this:
class VolumeLevel(int, Inclusive, low=0, high=100):
...
There is also a set of concrete ready-to-use interval types provided, that use predicate
functions from phantom.predicates.interval
.
def take_portion(portion: Portion, whole: Natural) -> float:
return portion * whole
All interval types fully support pydantic and appropriately adds inclusive or exclusive minimums and maximums to their schema representations.
Base classes#
- class phantom.interval.Interval(instance)[source]#
Bases:
Phantom
[Comparable
]Base class for all interval types, providing the following class arguments:
check: IntervalCheck
low: Comparable
(defaults to negative infinity)high: Comparable
(defaults to positive infinity)
Concrete subclasses must specify their runtime type bound as their first base.
- __check__: IntervalCheck#
- class phantom.interval.Exclusive(instance)[source]#
Bases:
Interval
Uses
phantom.predicates.interval.exclusive()
ascheck
.
- class phantom.interval.Inclusive(instance)[source]#
Bases:
Interval
Uses
phantom.predicates.interval.inclusive()
ascheck
.
- class phantom.interval.ExclusiveInclusive(instance)[source]#
Bases:
Interval
Uses
phantom.predicates.interval.exclusive_inclusive()
ascheck
.
- class phantom.interval.InclusiveExclusive(instance)[source]#
Bases:
Interval
Uses
phantom.predicates.interval.inclusive_exclusive()
ascheck
.
Concrete interval types#
- class phantom.interval.Natural(instance)[source]#
Bases:
int
,InclusiveExclusive
Represents integer values in the inclusive range
[0, ∞)
.
- class phantom.interval.NegativeInt(instance)[source]#
Bases:
int
,ExclusiveInclusive
Represents integer values in the inclusive range
(-∞, 0]
.
Regular expressions#
Types for representing strings that match a pattern.
class Greeting(Match, pattern=r"^(Hi|Hello)"):
...
assert isinstance("Hello Jane!", Greeting)
- class phantom.re.Match(instance)[source]#
Bases:
str
,Phantom
Takes
pattern: Pattern[str] | str
as class argument as either a compiledPattern
or astr
to be compiled. Uses thephantom.predicates.re.is_match()
predicate.
- class phantom.re.FullMatch(instance)[source]#
Bases:
str
,Phantom
Takes
pattern: Pattern[str] | str
as class argument as either a compiledPattern
or astr
to be compiled. Uses thephantom.predicates.re.is_full_match()
predicate.
Sized collections#
Types describing collections with size boundaries. These types should only be used with immutable collections. There is a naive check that eliminates some of the most common mutable collections in the instance check. However, a guaranteed check is probably impossible to implement, so some amount of developer discipline is required.
Sized types are created by subclassing PhantomBound
and providing a minimum,
maximum, or both as the min
and max
class arguments. For instance,
NonEmpty
is implemented using min=1
.
This made-up type would describe sized collections with between 5 and 10 ints:
class SpecificSize(PhantomBound[int], min=5, max=10):
...
This example creates a type that accepts strings with 255 or less characters:
class SizedStr(str, PhantomBound[str], max=255):
...
- class phantom.sized.SizedIterable(*args, **kwargs)[source]#
Bases:
Sized
,Iterable
[T
],Protocol
[T
]Intersection of
typing.Sized
andtyping.Iterable
.
- class phantom.sized.PhantomSized(instance)[source]#
Bases:
Phantom
[Sized
],SizedIterable
[T
],Generic
[T
]Takes class argument
len: Predicate[int]
.Discouraged in favor of
PhantomBound
, which better supports automatic schema generation.
- class phantom.sized.PhantomBound(instance)[source]#
Bases:
Phantom
[Sized
],SizedIterable
[T
],Generic
[T
]Takes class arguments
min: int
,max: int
.
- class phantom.sized.NonEmpty(instance)[source]#
Bases:
PhantomBound
[T
],Generic
[T
]A sized collection with at least one item.
- class phantom.sized.NonEmptyStr(instance)[source]#
Bases:
str
,NonEmpty
[str
]A sized str with at least one character.
- class phantom.sized.Empty(instance)[source]#
Bases:
PhantomBound
[T
],Generic
[T
]A sized collection with exactly zero items.