Skip to main content

⟨ beset ⟩

typed intervals with the interface of Python sets

PyPI Python versions License Build Documentation

The beset Python library provides generic interval classes for use in typed Python. It is tested to work well with mypy, ty, pyright and pyrefly.

The interface of beset intervals mirrors that of Python set. If you know Python set operations, you know how to use this library.

Full documentation is available on Read the Docs.

Contents

Installation

beset is available on PyPI and can be installed using pip.

$ pip install beset

Popular package managers can install it out of the box. For instance, you can run poetry add beset or uv add beset if you use these tools.

Development status

The beset library is currently still in an early stage of development. Its design and API are likely to change in upcoming versions until version 1.0 is reached.

If maturity and stability are requirements, check out some other libraries that might meet your needs. Conversely, if you have requirements or needs you'd like to see the beset library satisfy or have feedback on the current design or API, any input or contribution is highly appreciated.

Quick demo

Let's assume beset is imported as follows:

>>> import beset as b

We can use one of the interval classes, such as ClosedOpen, to create intervals and perform standard set operations on them:

>>> working_hours = b.ClosedOpen(9, 17)
>>> lunch_break = b.ClosedOpen(12, 13)

>>> available = working_hours - lunch_break  # set subtraction operator

>>> print(available)
[9 ; 12) | [13 ; 17)

>>> meeting = b.ClosedOpen(11, 12)
>>> meeting <= available  # is a subset operator
True

Why use beset?

When writing typed Python code

Use beset when you need statically typed intervals. Its generic classes preserve bound types through interval and set operations and are understood by type checkers.

Adherence to the Python set interface

Adherence to the existing interface of Python set means you can jump in and start using this library with little prior knowledge.

Note: Since beset intervals are immutable it would be more accurate to say they follow the interface of frozenset, which itself matches most of the set interface.

Strict function signatures and variable definitions

beset classes allow you to strictly specify in function signatures and variable type hints what kinds of intervals your code expects and to use type checkers to enforce those expectations. For example, the Open[int] type hint limits objects to open continuous non-empty intervals defined on integer bounds, while ClosedOpenSet[datetime | None] allows bounded and unbounded multiintervals defined on date-times.

That means your code needs fewer run-time checks and error handling to deal with intervals of the wrong type or containing the wrong type of data.

Intervals work on many data types

beset intervals can be defined on any type of data that can be ordered using its less-than (<) operator. This not only includes int, float, datetime and similar types, but also types like str that have an ordering without a concept of distance between values. Intervals can be defined on your own classes as well, as long as you provide an implementation for the less-than operator.

Note: beset is not the only interval library providing this. See below for some others.

Intervals are immutable and hashable

beset interval objects are immutable and hashable, as long as the objects used as bounds can be hashed.

Some additional examples

Intervals can have open or closed bounds:

>>> print(b.Open(6, 7))
(6 ; 7)

>>> print(b.OpenClosed(6, 7))
(6 ; 7]

>>> print(b.ClosedOpen(6, 7))
[6 ; 7)

>>> print(b.Closed(6, 7))
[6 ; 7]

Intervals contain all possible values between their lower and upper bounds:

>>> 6 in b.ClosedOpen(7, 9)
False

>>> 7 in b.ClosedOpen(7, 9)
True

>>> 8 in b.ClosedOpen(7, 9)
True

>>> 9 in b.ClosedOpen(7, 9)
False

>>> 10 in b.ClosedOpen(7, 9)
False

beset intervals have methods and operators mirroring those of Python set (or frozenset more specifically, since beset intervals are immutable). Some examples:

>>> b.ClosedOpen(10, 20) & b.ClosedOpen(15, 25)  # intersection
ClosedOpen(15, 20)

>>> b.ClosedOpen(3, 9) < b.Open(0, 10)  # is proper subset
True

Set subtraction can lead to disjoint sets. The beset library represents these using the class IntervalSet.

>>> s = b.Open(0, 10) - b.Open(3, 5)

>>> s
IntervalSet([OpenClosed(0, 3), ClosedOpen(5, 10)])

>>> print(s)
(0 ; 3] | [5 ; 10)

You can also create an IntervalSet explicitly, but it's often easier to use the union operator on simple intervals. The results are the same.

>>> b.IntervalSet([b.Open(10, 20), b.Open(30, 40)]) == b.Open(10, 20) | b.Open(30, 40)
True

The beset library supports unbounded intervals without upper or lower bound. Create such intervals by using None as a bound.

>>> x = b.Closed(10, None)
>>> print(x)
[10 ; +inf⟩

>>> 100 in x
True

Unbounded intervals allow for the introduction of the complement operation that returns the complementary interval, containing everything not in the original interval.

>>> b.Closed(-3, 7).complement()
OpenSet([RightOpen(-3), LeftOpen(7)])

>>> print(~b.ClosedOpen(0, 100))  # the ~-operator returns the complement
⟨-inf ; 0) | [100 ; +inf⟩

Typing

The beset classes are generic. Type checkers automatically infer the correct type.

>>> reveal_type(b.ClosedOpen(2.718, 6.283))  # Revealed type is beset.ClosedOpen[float]

You can use the beset classes to specify precisely what kind of interval your code expects. In the following inventory of classes we assume intervals with int bounds, but any suitable type will work.

a: b.IntervalSet[int | None]

IntervalSet matches any type of interval; atomic (single) intervals as well as unions of intervals or the empty interval. Including None will mean unbounded intervals, with plus or minus infinity as bounds, are also permitted.

b: b.IntervalSet[int]

Using a stricter IntervalSet, without None, will allow only bounded intervals, multiintervals and the empty interval, but no unbounded ones.

c: b.Interval[int | None]

The Interval class matches any type of atomic interval (Closed, Open, ClosedOpen, OpenClosed) and will allow unbounded ones as well, but not empty ones.

d: b.Interval[int]

The Interval class matches any type of interval (Closed, Open, ClosedOpen, OpenClosed) but will not allow unbounded intervals or empty ones.

e: b.Interval[int] | b.Empty

This matches all atomic intervals as well as the empty one. Note that the empty interval class takes no type argument because it has no bounds.

f: b.ClosedOpen[int]

Some applications strictly use ClosedOpen intervals.

g: b.ClosedOpenSet[int]

Union sets of closed-open intervals can also be specified. Such classes exist also for closed, open and open-closed intervals.

Intersections to get rid of None

Operations on intervals may return different types of intervals or intervals with different type arguments. For example, taking the complement of an Interval[int] will give you an IntervalSet[int | None].

>>> x = ~b.Closed(0, 10)
>>> print(x)
⟨-inf ; 0) | (10 ; +inf⟩

>>> reveal_type(x)  # Revealed type is beset.IntervalSet[int | None]

Getting rid of the union with None can be accomplished using the intersection operation. Continuing the example:

>>> y = x & b.Closed(-100, 100)
>>> print(y)
[-100 ; 0) | (10 ; 100]

>>> reveal_type(y)  # Revealed type is beset.IntervalSet[int]

Other libraries

There are already excellent Python libraries available that provide interval data structures and operations. They may suit your use case better, depending on your needs.

  • portion
    • A very mature interval library (and one of the main inspirations for beset)
  • intervaltree
    • Focused on speed and performance for large interval sets

Metadata

Release files for beset 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for beset 0.1.3
File Size Uploaded
beset-0.1.3.tar.gz 14.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for beset 0.1.3
File Interpreter ABI Platform
beset-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 30.7 kB

Release files / beset-0.1.3.tar.gz

Download URL beset-0.1.3.tar.gz
Size 14.6 kB
Tags Source
SHA-256 checksum
How to use checksums
c522f6dd82cc656f11ad4c6dfabab4abfc469476fb6e1caf3a810b696122207c
BLAKE2b-256 checksum
How to use checksums
0892b3585bbb8ae1abfc2a162a4023fb1ab9cc522260dac9ca559788d0b4743f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / beset-0.1.3-py3-none-any.whl

Download URL beset-0.1.3-py3-none-any.whl
Size 16.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5ed380a36f06e225be905abf75f53beb700858578270fd35dc5f6162efd3aa1a
BLAKE2b-256 checksum
How to use checksums
899345b1afa39a8aaf8edce9903b146ecf1e70cdec7fcfee95dbad27c0468e16
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page