Types

Boolean

Types describing objects that coerce to either True or False respectively when calling bool() on them.

class phantom.boolean.Truthy(instance)[source]

Bases: phantom.base.Phantom

>>> isinstance("Huzzah!", Truthy)
True
>>> isinstance((), Truthy)
False
class phantom.boolean.Falsy(instance)[source]

Bases: phantom.base.Phantom

>>> isinstance((), Falsy)
True
>>> isinstance("Hej!", Falsy)
False

Datetime

Types for narrowing on the builtin datetime types.

class phantom.datetime.TZAware(instance)[source]

Bases: datetime.datetime, phantom.base.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.datetime, phantom.base.Phantom

>>> isinstance(datetime.datetime.now(), TZNaive)
True
>>> isinstance(datetime.datetime.now(tz=datetime.timezone.utc), TZNaive)
False

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 open range (0, 100) for a volume control you would define a type like this:

class VolumeLevel(int, Open, 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

Base classes

class phantom.interval.Interval(instance)[source]

Bases: phantom.base.Phantom

Base class for all interval types, providing the following class arguments:

  • check: IntervalCheck

  • low: float (defaults to negative infinity)

  • high: float (defaults to positive infinity)

Concrete subclasses must specify their runtime type bound as their first base.

__check__: IntervalCheck
class phantom.interval.Open(instance)[source]

Bases: phantom.interval.Interval

Uses phantom.predicate.interval.open() as check.

class phantom.interval.Closed(instance)[source]

Bases: phantom.interval.Interval

Uses phantom.predicate.interval.closed() as check.

class phantom.interval.OpenClosed(instance)[source]

Bases: phantom.interval.Interval

Uses phantom.predicate.interval.open_closed() as check.

class phantom.interval.ClosedOpen(instance)[source]

Bases: phantom.interval.Interval

Uses phantom.predicate.interval.closed_open() as check.

Concrete interval types

class phantom.interval.Natural(instance)[source]

Bases: int, phantom.interval.Open

Represents integer values in the inclusive range (0, ∞).

class phantom.interval.NegativeInt(instance)[source]

Bases: int, phantom.interval.Open

Represents integer values in the inclusive range (-∞, 0).

class phantom.interval.Portion(instance)[source]

Bases: float, phantom.interval.Open

Represents float values in the inclusive range (0, 1).

Regular expressions

Types for representing strings that match a pattern.

class Greeting(Match, pattern=re.compile(r"^(Hi|Hello)")):
    ...

assert isinstance("Hello Jane!", Greeting)
class phantom.re.Match(instance)[source]

Bases: str, phantom.base.Phantom

Takes pattern: Pattern[str] as class argument. Uses the phantom.predicate.re.is_match() predicate.

class phantom.re.FullMatch(instance)[source]

Bases: str, phantom.base.Phantom

Takes pattern: Pattern[str] as class argument. Uses the phantom.predicate.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 PhantomSized and providing a predicate that will be called with the size of the tested collection. For instance, NonEmpty is implemented using len=numeric.greater(0).

This made-up type would describe sized collections with between 5 and 10 ints:

class SpecificSize(PhantomSized[int], len=numeric.greater(0)):
    ...
class phantom.sized.SizedIterable(*args, **kwds)[source]

Bases: collections.abc.Sized, collections.abc.Iterable, typing.Protocol

Intersection of typing.Sized and typing.Iterable.

class phantom.sized.PhantomSized(instance)[source]

Bases: phantom.sized.SizedIterable, phantom.base.Phantom, typing.Generic

Takes class argument len: Predicate[float].

class phantom.sized.NonEmpty(instance)[source]

Bases: phantom.sized.PhantomSized, typing.Generic

A sized collection with at least one item.

class phantom.sized.Empty(instance)[source]

Bases: phantom.sized.PhantomSized, typing.Generic

A sized collection with exactly zero items.