Span: An Ergonomic Wrapper for tuple[int, int]#

class my.types.Span.Span#
class my.types.Span.Span(arg0: S, arg1: S)
class my.types.Span.Span(arg0: Span[S] | tuple[S, S])
class my.types.Span.Span(arg0: str | bytes | bytearray | memoryview | IO | int | float | complex | bool | tuple[int | float | complex | bool, int | float | complex | bool] | Span, arg1: str | bytes | bytearray | memoryview | IO | int | float | complex | bool, tvar: type[S] | MyType[S])

An immutable half-open interval [start, end), typically representing a text range.

Spans are a simple wrapper around tuple[int, int] built to support arithmetic (shifting by integers), containment testing (checking if positions or other spans intersect), and merging operations (combining overlapping spans into minimal non-overlapping sets).

The class provides flexible construction from strings like "10-20" or abbreviated forms like "432-3" (interpreted as 432-433). The parse() classmethod handles smart abbreviation expansion, where trailing digits inherit leading digits from the start position. Note that str() renders the inclusive form – Span(3, 9) becomes '3-8' – which is what parse() expects back.

Examples

Construct spans from points, pairs, or strings:

>>> from my import Span
>>> Span(3, 9)
Span(3, 9)
>>> Span('10-20')
Span(10, 20)

Shift a span by an integer and test containment:

>>> Span(3, 9) + 1
Span(4, 10)
>>> 5 in Span(3, 9)
True
>>> (8, 12) in Span(3, 9)
True

Render the inclusive string form:

>>> str(Span(3, 9))
'3-8'

I Properties#

property Span.delta: T#

Return the length of this span.

II Methods#

Span.intersects(other: tuple[T, T] | Self | list[Self]) → bool#

Check if this span overlaps with another span.

Parameters:

other – Span to test for intersection.

Returns:

True if the spans overlap.

Examples

Test a partial overlap:

>>> from my import Span
>>> Span(3, 9).intersects((8, 12))
True
Span.join(other: Self | tuple[T, T]) → Self#

Create a span that encompasses both this span and another.

Parameters:

other – Span to join with.

Returns:

New span from the minimum start to maximum end.

Examples

Join two overlapping spans:

>>> from my import Span
>>> Span(3, 9).join((7, 15))
Span(3, 15)
classmethod Span.serialize(*args: Self | tuple[T, T]) → str#

Serialize multiple spans to a delimited string.

Parameters:

*args – Spans to serialize.

Returns:

String with spans separated by DELIM.

Examples

Serialize two spans (inclusive display form):

>>> from my import Span
>>> Span.serialize(Span(1, 3), Span(8, 12))
'1-2 // 8-11'
classmethod Span.parse(text: str) → Self#

Parse a span from text with smart abbreviation handling.

Handles formats like:

  • "10-20": Full range

  • "432-3": Abbreviated end (becomes 432-433)

  • "1475-33": Abbreviated end with rollover (becomes 1475-1533)

  • "42": Single position (becomes 42-43)

Parameters:

text – String to parse.

Returns:

Parsed Span, or empty Span (0, 0) if parsing fails.

Examples

Expand abbreviated inclusive ranges into half-open spans:

>>> from my import Span
>>> Span.parse('432-3')
Span(432, 434)
>>> Span.parse('1475-33')
Span(1475, 1534)
>>> Span.parse('42')
Span(42, 43)
classmethod Span.merge(*args: tuple[int, int] | Self) → list[Self]#

Merge overlapping spans into a minimal set of non-overlapping spans.

Parameters:

*args – Spans to merge.

Returns:

Sorted list of non-overlapping spans covering the same positions.

Examples

Collapse overlapping spans:

>>> from my import Span
>>> Span.merge((0, 5), (3, 9), (12, 15))
[Span(0, 9), Span(12, 15)]