Skip to main content

A fully typed cyclic integer type for Python with modular arithmetic and fixed [left; right) interval semantics.

Project description

LoopInt

PyPI version Python versions Tests Coverage License Typing Downloads Ruff Linter & Formatter basedpyright

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 int in:
    • comparisons
    • hashing
    • indexing (__index__)
    • formatting (__format__)
    • int() conversion
  • Safe arithmetic:
    • LoopInt + int supported
    • LoopInt += int supported
    • Adding two LoopInt objects 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 bound
  • left — 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

This version

1.0

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

loopint-1.0.tar.gz (5.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

loopint-1.0-py3-none-any.whl (5.3 kB view details)

Uploaded Python 3

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

Hashes for loopint-1.0.tar.gz
Algorithm Hash digest
SHA256 ce7c2299ca2b14805f05fa65b26dc7591d9010da22e73e3a05df433ce135a4df
MD5 f593099393eeac22f5db8475e416d0e6
BLAKE2b-256 46010be84d2981d95ea87596c99b3579de30a5af2802ef1d24e002698e386923

See more details on using hashes here.

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

Hashes for loopint-1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 653e377ccb0eb93577bec1079253daa5dad0e500b98274fb110d7559d8ab764c
MD5 d5bd26b919914db0430da9b5938a3a42
BLAKE2b-256 4f486b689a29e5439bbaabc27bf275e1659e84353d4e13c04abc90501d7da8c5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page