Custom range types

The built in range types may not suffice for your particular application. It is very easy to extend with your own classes. The only requirement is that the type supports rich comparison PEP 207 and is immutable.

Standard range types

A normal range can be implemented by extending spans.types.Range.

from spans.types import Range

class floatrange(Range):
        __slots__ = ()
        type = float

span = floatrange(1.0, 5.0)

assert span.lower == 1.0
assert span.upper == 5.0

Note

The __slots__ = () is a performance optimization that is used for all ranges. It lowers the memory footprint for every instance. It is not mandatory but encourgaged.

Offsetable range types

An offsetable range can be implemented using the mixin spans.types.OffsetableRangeMixin. The class still needs to extend spans.types.Range.

from spans.types import Range, OffsetableRangeMixin

class floatrange(Range, OffsetableRangeMixin):
        __slots__ = ()
        type = float

If the offset type is not the same as the range type (such as date that is offsetable with timedelta) the attribute offset_type can be used.

from spans.types import DiscreteRange, OffsetableRangeMixin
from datetime import date, timedelta

class daterange(DiscreteRange, OffsetableRangeMixin):
        __slots__ = ()

        type = date
        offset_type = timedelta

span = daterange(date(2000, 1, 1), date(2000, 2, 1))
assert span.offset(timedelta(14)).upper == date(2000, 2, 15)

Discrete range types

Discrete ranges (such as intrange and daterange) can be implemented by extending spans.types.DiscreteRange.

from spans.types import DiscreteRange, OffsetableRangeMixin

class intrange(DiscreteRange, OffsetableRangeMixin):
        __slots__ = ()
        type = intrange
        step = 1

assert list(intrange(1, 5)) == [1, 2, 3, 4]

Note the step attribute. It must always be the smallest possible unit. Using 2 for intranges would not have expected behavior.

Range sets

Range sets are conveinient to implement regardless of the mixins used. This is due to the metaclass spans.settypes.MetaRangeSet. The metaclass automatically adds required mixins to the range set type.

from spans.types import intrange
from spans.settypes import RangeSet

class intrangeset(RangeSet):
        __slots__ = ()
        type = intrange

assert intrangeset(
        [intrange(1, 5), intrange(10, 15)]).span() == intrange(1, 15)

Custom mixins

It is possible to create custom mixins for range sets by adding mappings to spans.settypes.MetaRangeSet. The mapping has to be added before the range set class is created or it will not be used.