py-geometry-utils
Provides utilities for working with coordinates, rectangles, and grids.
[!WARNING] This library is still in beta, breaking changes between releases are likely for 0.x versions.
Initially part of a different project, I wanted to use it in a few other projects so I decided to separate it out into its own package.
PyPI: https://pypi.org/project/py-geometry-utils/
Documentation: https://py-geometry-utils.readthedocs.io/en/latest/
Changelog: https://github.com/svioletg/py-geometry-utils/blob/main/CHANGELOG.md
Usage
Install with pip or include as a dependency as py-geometry-utils, the package will be available as
the geometry module.
Construct a 2D coordinate: Coord2(1, 2)
Construct a rectangle: Rect(0, 0, 10, 10)
Construct a 2D grid: Grid2(-10, -10, 10, 10, step=(1, 1), origin=(0, 0)) (step and origin
optional, defaults to Coord2(1, 1) and the center coordinate of the rectangle respectively)
Features
Immutability
All geometry classes are immutable by default, meaning their attributes (such as x and y) cannot
be reassigned after constructing the instance.
p = Coord2(0, 0)
p.x = 1
# TypeError: Cannot modify attribute of immutable Coord2 instance
r = Rect(0, 0, 10, 10)
r.x1 = 1
# TypeError: Cannot modify attribute of immutable Rect instance
g = Grid2(-10, -10, 10, 10, step=(1, 1), origin=(0, 0))
g.step = Coord2(2, 2)
# TypeError: Cannot modify attribute of immutable Coord2 instance
To make them mutable, mut=True must be passed to their constructors:
p = Coord2(0, 0, mut=True)
p.x = 1
assert p.x == 1
r = Rect(0, 0, 10, 10, mut=True)
r.x1 = 1
assert r.x1 == 1
g = Grid2(-10, -10, 10, 10, step=(1, 1), origin=(0, 0), mut=True)
g.step = Coord2(2, 2)
assert g.step == Coord2(2, 2)
When Grid2 is constructed with mut=False, the passed step and origin values are always
copied as new immutable Coord2 instances. Otherwise, the objects are used as-is if they are
already Coord2 instances (meaning in Grid2(..., step=Coord2(1, 1, mut=False), mut=True)
the step value will maintain its immutability); if they're tuples, they are converted to
new mutable Coord2 objects.
Type coercion
All Coord2 and Rect methods which take a second coordinate or rectangle as an argument will
also accept their respective tuple of values. If a method's argument takes Coord2, it will also
accept tuple[float, float]; if it takes Rect, it will accept
tuple[float, float, float, float].
assert Coord2(0, 0).distance(Coord2(10, 10)) == 20
assert Coord2(0, 0).distance((10, 10)) == 20
Grid2.step and Grid2.origin's setters will accept a plain tuple of two numbers in addition to a
Coord2 instance, those values being converted to Coord2 implicitly:
g = Grid2(-10, -10, 10, 10, mut=True)
g.step = (10, 10)
# g.step == Coord2(10, 10)
Math & other combining operations
Coord2 supports the operators +, -, *, /, //, %, and ** between either other
Coord2 instances, tuple[float, float], or single numbers (which gets treated as (n, n)).
assert Coord2(1, 1) + 1 == Coord2(2, 2)
assert Coord2(1, 1) + (1, 2) == Coord2(2, 4)
assert Coord2(1, 1) + Coord2(1, 2) == Coord2(2, 4)
assert Coord2(1, 1) - 1 == Coord2(0, 0)
assert Coord2(1, 1) - (1, 2) == Coord2(0, -1)
assert Coord2(1, 1) - Coord2(1, 2) == Coord2(0, -1)
# and so on...
You can also use the Coord2.zip_with()
method to combine two coordinates together using a given function, where a new Coord2 instance is
constructed using the result of applying fn to both original coordinates' x and y values
individually:
assert Coord2(0, 1).zip_with(max, (1, 0)) == Coord2(1, 1)
Coord2.map()
returns a new Coord2 applying a function to the original coordinates' values:
assert Coord2(1, 2).map(lambda n: (n * 10) if n % 2 == 0 else (n / 10)) == Coord2(0.1, 20)
Coord2.as_tuple()
by default returns the x and y values of a coordinate as a simple tuple, but can optionally
take a function argument to transform those values before returning it:
assert Coord2(1, 2).as_tuple() == (1, 2)
assert Coord2(1, 2).as_tuple(str) == ('1', '2')
Rect and Grid2 also have as_tuple, map, and zip_with methods that behave the same way with
their respective classes. Grid2 is a subclass of Rect and so simply inherits the former two
methods, but has its own implementation of zip_with
which allows specifying the step and origin values to set for the returned new instance.
Copying
Coord2, Rect, and Grid2 all implement __copy__ by having it return a new instance with the
same coordinate values, with Grid2.__copy__() also copying the step and origin values (which
are Coord2 instances, so Coord2.__copy__() is invoked for them).
Iteration & other magic method implementations
Coord2, Rect, and Grid2 all support both __iter__ and __getitem__. __iter__ yields the
coordinate values for the class, meaning x and y for Coord2, and x1, y1, x2, and y2
for Rect and Grid2. This is also the order of attributes returned for as_tuple() on each of
these classes. __getitem__ acts as a shortcut for .as_tuple()[n].
Comparing
All classes support ==, comparing each instance's coordinate values. They can also be compared
with tuples:
assert Coord2(1, 2) == Coord2(1, 2)
assert Coord2(1, 2) == (1, 2)
assert Rect(0, 0, 10, 10) == Rect(0, 0, 10, 10)
assert Rect(0, 0, 10, 10) == (0, 0, 10, 10)
[!NOTE] Comparing two
Grid2instances will not take into account theirstepandoriginvalues.
Coord2 additionally supports the >=, >, <=, and < operators, comparing it and another
coordinate's values the same way that tuples are compared (e.g. Coord2(x, y) > Coord2(x, y) will
always equal the outcome of (x, y) > (x, y)).
Release files for py-geometry-utils 0.8.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| py_geometry_utils-0.8.0.tar.gz | 71.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| py_geometry_utils-0.8.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 85.0 kB
Release files / py_geometry_utils-0.8.0.tar.gz
| Download URL | py_geometry_utils-0.8.0.tar.gz |
|---|---|
| Size | 71.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
46cbd4a78c77c8362db4bcd7733fa80e848cf7793a8461ac2a5793ee642eec63
|
|
BLAKE2b-256 checksum How to use checksums |
d2fcc22180731474331f445e10455eb8713bb11aac82824cfef9c87993ac78dc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency logRelease files / py_geometry_utils-0.8.0-py3-none-any.whl
| Download URL | py_geometry_utils-0.8.0-py3-none-any.whl |
|---|---|
| Size | 13.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
939d5f1e92347923241aff51943bd2c79b133b375ca52e7e978fee8b78902071
|
|
BLAKE2b-256 checksum How to use checksums |
1328f5d53ba638299eac6a94ec69839a8bd776382196f429bba16310ee0f5674
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.
Transparency log