Pre-release
This release is a pre-release and may not be stable for production use.
canonical-interval
Self-normalizing interval data structure that automatically maintains valid form with useful utility methods.
The CanonicalInterval class represents left-closed, right-open intervals ([start, stop)) that, given a comparator (default: operator.lt), automatically enforce the following standardized valid form:
- Guarantees
start <= stopaccording to the comparator- Empty intervals become
[start, start)
- Empty intervals become
- All operations maintain canonical form
Key Features:
- Automatic Canonicalization
- Custom Comparison: Supports any comparator function
- Useful Utility Methods:
__bool__: Determines if the current interval is empty.relative_position_of(item): Determines ifitemis before/within/after the current interval.three_way_split(target): Split a target interval into three parts:- Parts of
targetbefore current interval - Overlapping parts between
targetand current interval - Parts of
targetafter current interval
- Parts of
- Supports Python 2+
Installation
pip install canonical-interval
Examples
from canonical_interval import CanonicalInterval
# Automatically becomes [20, 20) (empty interval)
assert CanonicalInterval(20, 10).start == 20
assert CanonicalInterval(20, 10).stop == 20
assert not CanonicalInterval(20, 10)
assert 15 not in CanonicalInterval(20, 10)
# Automatically becomes ['z', 'z') (empty interval)
assert CanonicalInterval('z', 'a').start == 'z'
assert CanonicalInterval('z', 'a').stop == 'z'
assert not CanonicalInterval('z', 'a')
assert 'm' not in CanonicalInterval('z', 'a')
# Respects custom comparator
# [20, 10) (non-empty interval)
assert CanonicalInterval(20, 10, comparator=lambda a, b: a > b).start == 20
assert CanonicalInterval(20, 10, comparator=lambda a, b: a > b).stop == 10
assert CanonicalInterval(20, 10, comparator=lambda a, b: a > b)
assert 15 in CanonicalInterval(20, 10, comparator=lambda a, b: a > b)
# Respects custom comparator
# ['z', 'a') (non-empty interval)
assert CanonicalInterval('z', 'a', comparator=lambda a, b: a > b).start == 'z'
assert CanonicalInterval('z', 'a', comparator=lambda a, b: a > b).stop == 'a'
assert CanonicalInterval('z', 'a', comparator=lambda a, b: a > b)
assert 'm' in CanonicalInterval('z', 'a', comparator=lambda a, b: a > b)
# Various three-way splits
## Non-empty current
non_empty_current = CanonicalInterval(0, 2)
### Non-empty targets
assert non_empty_current.three_way_split(CanonicalInterval(-3, -1)) == (
CanonicalInterval(-3, -1), CanonicalInterval(0, 0), CanonicalInterval(2, 2)
)
assert non_empty_current.three_way_split(CanonicalInterval(-2, 0)) == (
CanonicalInterval(-2, 0), CanonicalInterval(0, 0), CanonicalInterval(2, 2)
)
assert non_empty_current.three_way_split(CanonicalInterval(-1, 1)) == (
CanonicalInterval(-1, 0), CanonicalInterval(0, 1), CanonicalInterval(2, 2)
)
assert non_empty_current.three_way_split(CanonicalInterval(0, 2)) == (
CanonicalInterval(0, 0), CanonicalInterval(0, 2), CanonicalInterval(2, 2)
)
assert non_empty_current.three_way_split(CanonicalInterval(0.5, 1.5)) == (
CanonicalInterval(0, 0), CanonicalInterval(0.5, 1.5), CanonicalInterval(2, 2)
)
assert non_empty_current.three_way_split(CanonicalInterval(1, 3)) == (
CanonicalInterval(0, 0), CanonicalInterval(1, 2), CanonicalInterval(2, 3)
)
assert non_empty_current.three_way_split(CanonicalInterval(2, 4)) == (
CanonicalInterval(0, 0), CanonicalInterval(2, 2), CanonicalInterval(2, 4)
)
assert non_empty_current.three_way_split(CanonicalInterval(3, 5)) == (
CanonicalInterval(0, 0), CanonicalInterval(2, 2), CanonicalInterval(3, 5)
)
### Empty targets
assert non_empty_current.three_way_split(CanonicalInterval(-1, -1)) == (
CanonicalInterval(-1, -1), CanonicalInterval(0, 0), CanonicalInterval(2, 2)
)
assert non_empty_current.three_way_split(CanonicalInterval(0, 0)) == (
CanonicalInterval(0, 0), CanonicalInterval(0, 0), CanonicalInterval(2, 2)
)
assert non_empty_current.three_way_split(CanonicalInterval(1, 1)) == (
CanonicalInterval(0, 0), CanonicalInterval(1, 1), CanonicalInterval(2, 2)
)
assert non_empty_current.three_way_split(CanonicalInterval(2, 2)) == (
CanonicalInterval(0, 0), CanonicalInterval(2, 2), CanonicalInterval(2, 2)
)
assert non_empty_current.three_way_split(CanonicalInterval(3, 3)) == (
CanonicalInterval(0, 0), CanonicalInterval(2, 2), CanonicalInterval(3, 3)
)
## Empty current
empty_current = CanonicalInterval(0, 0)
### Non-empty targets
assert empty_current.three_way_split(CanonicalInterval(-3, -1)) == (
CanonicalInterval(-3, -1), CanonicalInterval(0, 0), CanonicalInterval(0, 0)
)
assert empty_current.three_way_split(CanonicalInterval(-2, 0)) == (
CanonicalInterval(-2, 0), CanonicalInterval(0, 0), CanonicalInterval(0, 0)
)
assert empty_current.three_way_split(CanonicalInterval(-1, 1)) == (
CanonicalInterval(-1, 0), CanonicalInterval(0, 0), CanonicalInterval(0, 1)
)
assert empty_current.three_way_split(CanonicalInterval(0, 2)) == (
CanonicalInterval(0, 0), CanonicalInterval(0, 0), CanonicalInterval(0, 2)
)
assert empty_current.three_way_split(CanonicalInterval(1, 3)) == (
CanonicalInterval(0, 0), CanonicalInterval(0, 0), CanonicalInterval(1, 3)
)
### Empty targets
assert empty_current.three_way_split(CanonicalInterval(-1, -1)) == (
CanonicalInterval(-1, -1), CanonicalInterval(0, 0), CanonicalInterval(0, 0)
)
assert empty_current.three_way_split(CanonicalInterval(0, 0)) == (
CanonicalInterval(0, 0), CanonicalInterval(0, 0), CanonicalInterval(0, 0)
)
assert empty_current.three_way_split(CanonicalInterval(1, 1)) == (
CanonicalInterval(0, 0), CanonicalInterval(0, 0), CanonicalInterval(1, 1)
)
Contributing
Contributions are welcome! Please submit pull requests or open issues on the GitHub repository.
License
This project is licensed under the MIT License.
Release files for canonical-interval 0.1.0a2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| canonical_interval-0.1.0a2.tar.gz | 4.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| canonical_interval-0.1.0a2-py2.py3-none-any.whl | Python 3, Python 2 | none | any | Details |
Total release size: 9.7 kB
Release files / canonical_interval-0.1.0a2.tar.gz
| Download URL | canonical_interval-0.1.0a2.tar.gz |
|---|---|
| Size | 4.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5f59c044c276fc6d076f175d9e32b4b731d44925bf95c5a0b8ed49685e0d1b11
|
|
BLAKE2b-256 checksum How to use checksums |
c63e7efb4a10863eb11abf59cf056c9520a023ee916ed35766ebff76a7dbd16e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.2
|
Release files / canonical_interval-0.1.0a2-py2.py3-none-any.whl
| Download URL | canonical_interval-0.1.0a2-py2.py3-none-any.whl |
|---|---|
| Size | 5.0 kB |
| Tags | Python 2 Python 3 |
|
SHA-256 checksum How to use checksums |
8ca8eee4ac9b5b1f352a7c03e91ebd273df01f30741dd4f9162e05f2f66766e4
|
|
BLAKE2b-256 checksum How to use checksums |
1c8b8bb40d329aa08bc98befa1d0a11e0bd6096da77fcc0dfbc92bfb42dfe56c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.2
|