A fully typed cyclic integer type for Python with modular arithmetic and fixed [left; right) interval semantics.
Project description
LoopInt
LoopInt is a lightweight Python library that provides a cyclic integer type with precise range semantics [left; right) and natural integer-like behavior.
It behaves like a regular integer but wraps around within a fixed interval. This makes it useful for cyclic counters, circular buffers, modular arithmetic, clock-like values, and more.
🔧 Features
- Fixed interval semantics: [left; right)
- Modular wrap-around on
+,-,+=,-= - Behaves like
intin:- comparisons
- hashing
- indexing (
__index__) - formatting (
__format__) int()conversion
- Safe arithmetic:
LoopInt + intsupportedLoopInt += intsupported- Adding two
LoopIntobjects is intentionally forbidden
- Fully typed (Python ≥ 3.12)
📦 Installation
pip install loopint
Or with uv:
uv add loopint
🚀 Usage
from loopint import LoopInt
x = LoopInt(0, right=5)
print(int(x)) # 0
x += 7
print(int(x)) # 2 (wrap-around: 7 % 5 == 2)
y = x + 10
print(int(y)) # 2 (non-mutating)
assert x == 2
assert y == x
Custom range
x = LoopInt(0, right=2, left=-1)
print(int(x)) # 0
x += 1
print(int(x)) # 1
x += 2 # wraps in [-1; 2)
print(int(x)) # 0
📚 API Overview
LoopInt(current, /, right, *, left=0)
Create a cyclic integer constrained to the interval [left; right) with modular wrap-around.
Parameters:
current— initial value (any integer-like object supporting__index__)right— exclusive upper boundleft— inclusive lower bound (default:0)
Interval semantics:
value ∈ [left; right)
span = right − left
value = left + ((current − left) mod span)
🔹 Properties
value: int
Returns the visible integer value of the LoopInt instance.
Equivalent to:
int(loopint_instance)
Example:
x = LoopInt(5, right=8, left=2)
assert x.value == 5
left: int
Returns the inclusive lower bound of the interval.
Example:
LoopInt(0, right=5, left=-2).left # → -2
right: int
Returns the exclusive upper bound of the interval.
Example:
LoopInt(0, right=5).right # → 5
span: int
Size of the interval:
span = right - left
Example:
LoopInt(0, right=5, left=2).span # → 3
🔹 Methods
to_string() -> str
Return the value as a string. Equivalent to:
str(int(self))
Example:
x = LoopInt(4, right=10)
x.to_string() # → "4"
Arithmetic
__add__(other) -> LoopInt
Non-mutating addition with wrap-around.
x + n # returns a new LoopInt
__iadd__(other) -> Self
In-place addition (+=) with wrap-around.
x += 3
__sub__(other) -> LoopInt
Non-mutating subtraction.
__isub__(other) -> Self
In-place subtraction (-=).
__neg__() -> LoopInt
Modular negation:
int(-x) == (-int(x)) mod span
Example:
x = LoopInt(1, right=5)
y = -x # → 4
__radd__(other) -> LoopInt
Enables: int + LoopInt.
Example:
3 + LoopInt(2, right=5) # → 0
__rsub__(other) -> LoopInt
Implements: other - self using modular arithmetic.
other - x == -(x - other)
Example:
3 - LoopInt(1, right=5) # → 2
0 - LoopInt(1, right=5) # → 4
Comparison & hashing
__eq__(other)
LoopInt compares equal to anything whose integer value equals int(self).
Examples:
LoopInt(0, right=5) == 0 # True
LoopInt(3, right=10) == LoopInt(3, right=100) # True
__hash__() -> int
Hash is consistent with int(self):
hash(LoopInt(3, right=10)) == hash(3)
🧪 Testing
pytest .
Both unit tests and property-based tests (Hypothesis) are included.
📄 License
MIT License.
🤝 Contributing
Contributions are welcome! Feel free to open issues or pull requests.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file loopint-1.0.tar.gz.
File metadata
- Download URL: loopint-1.0.tar.gz
- Upload date:
- Size: 5.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce7c2299ca2b14805f05fa65b26dc7591d9010da22e73e3a05df433ce135a4df
|
|
| MD5 |
f593099393eeac22f5db8475e416d0e6
|
|
| BLAKE2b-256 |
46010be84d2981d95ea87596c99b3579de30a5af2802ef1d24e002698e386923
|
File details
Details for the file loopint-1.0-py3-none-any.whl.
File metadata
- Download URL: loopint-1.0-py3-none-any.whl
- Upload date:
- Size: 5.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
653e377ccb0eb93577bec1079253daa5dad0e500b98274fb110d7559d8ab764c
|
|
| MD5 |
d5bd26b919914db0430da9b5938a3a42
|
|
| BLAKE2b-256 |
4f486b689a29e5439bbaabc27bf275e1659e84353d4e13c04abc90501d7da8c5
|