semita
Shortest and cheapest paths and distances on a grid, in C, for Python: jump point search for one path, A* for one where tiles cost differently, and Dijkstra for the cheapest paths from a point to every tile. Semita is Latin for a footpath.
Written for NachOS, a StarCraft II bot library, though nothing in it is about StarCraft.
import numpy
import semita
passable = numpy.ones((5, 5), dtype=bool)
passable[2, :4] = False # a wall, open at its far end
path = semita.cheapest_path(passable, (0, 0), (4, 0))
assert round(path.distance, 2) == 10.83 # round the wall's end
assert path.tiles[:3].tolist() == [[0, 0], [1, 1], [1, 2]]
assert semita.cheapest_path(passable, (0, 0), (2, 1)) is None # the end is blocked
paths = semita.cheapest_paths_from(passable, (0, 0)) # to every tile, in one pass
assert paths.distances[4, 0] == path.distance
assert paths.distances[2, 1] == float("inf")
assert paths.path_to((4, 0)).cost == path.cost
# Costs: each value is the cost of moving a unit of distance across its tile, 1 on normal ground and more where it
# is best avoided; 0 blocks, as False does.
costs = numpy.ones((7, 7))
costs[2:5, 2:5] = 10.0 # a patch to keep out of
around = semita.cheapest_path(costs, (3, 0), (3, 6))
assert round(around.cost, 2) == round(around.distance, 2) == 7.66 # round the patch, on ground costing 1
assert semita.cheapest_path(numpy.ones((7, 7), dtype=bool), (3, 0), (3, 6)).distance == 6.0 # straight, on bools
The rules
- A grid is a 2-D numpy array of bools or real numbers, or anything numpy reads as one, indexed
[i, j]. Its values are the tiles' costs: the cost of moving one unit of distance across each, 1 for normal ground, less where movement is faster, more where it is slower or best avoided. - 0 and
infblock a tile. A grid of bools is the simplest:Truecosts 1 andFalseblocks. Otherwise a cost is positive; NaN and negatives raiseValueError. - A step goes to one of the eight neighboring tiles, 1 long straight and √2 diagonally, and only between passable tiles. A diagonal step needs both tiles beside it passable too, so no path cuts a corner. A step costs its length times the mean of the costs of the two tiles it joins, so a path costs the same both ways.
- The start is a path to itself, costing nothing, even on a blocked tile, but no step leaves or enters a blocked one.
- A start or an end outside the grid raises
IndexError; a negative index counts as outside. cheapest_pathreturns aPath, itsdistance, itscostand itstilesfrom the start to the end, orNoneif there is no path. Of several equally cheap paths it returns one, but which is not part of the contract.cheapest_paths_fromreturns the cheapest path from the start to every tile, found in one pass, asCheapestPaths: theircostsand theirdistances, two read-only arrays of the grid's shape,infwhere no path reaches, andpath_to(tile), a tile's path as aPath, orNonewhere none reaches. Where several paths to a tile cost the same, it holds one of them. On a grid of bools the distances are the costs.- A grid whose passable tiles all cost the same, a grid of bools included, is searched by jump point search; any other by A*, which visits more tiles, the more so the cheaper the cheapest tile is, since its estimate of what is left is the straight distance times that cost.
- A grid of bools, or a C-contiguous one of float64, is read as it is; any other is converted on each call, so one searched often is best kept as one of those.
Each search allocates its own memory and releases the GIL, so searches run in parallel on threads. A grid must not be written to while a search reads it.
Building
semita is a C extension on Python's stable ABI, so one wheel serves every Python from 3.12 on a platform. Installing from source compiles it with the platform's own compiler: MSVC on Windows, gcc or clang elsewhere.
uv sync --extra dev
uv run pytest
The tests check every search against scipy's Dijkstra over the same steps.
Releasing
Publish a GitHub release tagged v and the new version, such as v0.2.0. The version is the tag, which
setuptools-scm reads from git; no file holds it.
The release workflow then builds the sdist, builds from it a wheel for Linux x86_64 and aarch64, Windows AMD64 and
macOS arm64 and x86_64, tests and audits each for the stable ABI alone, checks that the tag is a version,
and uploads them to PyPI. Every pull request builds and checks the same files without uploading them.
PyPI trusts the workflow through trusted publishing, from the repository's pypi environment, so no token is stored
anywhere.
Metadata
Release files for semita 0.2.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 | Provenance | |
|---|---|---|---|---|
| semita-0.2.0.tar.gz | 43.0 kB | With provenance | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| semita-0.2.0-cp312-abi3-win_amd64.whl | CPython 3.12 | abi3 | Windows x86-64 | Details |
| semita-0.2.0-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl | CPython 3.12 | abi3 | Linux glibc 2.17+ ARM64, Linux glibc 2.28+ ARM64 | Details |
| semita-0.2.0-cp312-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl | CPython 3.12 | abi3 | Linux glibc 2.5+ x86-64, Linux glibc 2.28+ x86-64 | Details |
| semita-0.2.0-cp312-abi3-macosx_11_0_arm64.whl | CPython 3.12 | abi3 | macOS 11.0+ ARM64 | Details |
| semita-0.2.0-cp312-abi3-macosx_10_13_x86_64.whl | CPython 3.12 | abi3 | macOS 10.13+ x86-64 | Details |
Total release size: 219.1 kB
Release files / semita-0.2.0.tar.gz
| Download URL | semita-0.2.0.tar.gz |
|---|---|
| Size | 43.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0b017a9a2be3076ba17a126e8e4e819da47e90e83376eb81eaf3459148ec1cba
|
|
BLAKE2b-256 checksum How to use checksums |
e76d7d12af3e23f9931c0b1ba9e3c816b5497402e71c917e47163840dc631443
|
| 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 Oct 21, 2026.
Transparency logRelease files / semita-0.2.0-cp312-abi3-win_amd64.whl
| Download URL | semita-0.2.0-cp312-abi3-win_amd64.whl |
|---|---|
| Size | 19.9 kB |
| Tags | CPython 3.12 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
670960e24a920782773c1b67d85c1f6f638c327b43984f298e24331ca00a44e3
|
|
BLAKE2b-256 checksum How to use checksums |
8147db54b14bd71d5cfe0798776311ec5655c65691d8224ac066aef7b4a14b39
|
| 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 Oct 21, 2026.
Transparency logRelease files / semita-0.2.0-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
| Download URL | semita-0.2.0-cp312-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 59.3 kB |
| Tags | CPython 3.12 Linux glibc 2.17+ ARM64 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
a3a399bc5a4aad0992ec5fe0509ee7bc590f94757a74da94fa686731855773bc
|
|
BLAKE2b-256 checksum How to use checksums |
da01d982479381cda28e05a66139d69da7a96b25d75e01e5996e1c49a47909e1
|
| 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 Oct 21, 2026.
Transparency logRelease files / semita-0.2.0-cp312-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
| Download URL | semita-0.2.0-cp312-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl |
|---|---|
| Size | 57.7 kB |
| Tags | CPython 3.12 Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
31943f026e167a215969c7bf9e901a9e1a59022ce5de30d134bcb9b163df8305
|
|
BLAKE2b-256 checksum How to use checksums |
59cf008bed7e4eb70eaf6462c1d4c4b361c1d01d10f6b651c5df60643edd4692
|
| 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 Oct 21, 2026.
Transparency logRelease files / semita-0.2.0-cp312-abi3-macosx_11_0_arm64.whl
| Download URL | semita-0.2.0-cp312-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 19.5 kB |
| Tags | CPython 3.12 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
cc99091c4ba6165c9aef713fb7256ac2bfa70ab3c8fc2a08be8c49908cb07ea2
|
|
BLAKE2b-256 checksum How to use checksums |
4d98a0a0d97801dfd4317d53270fbb20ef49ed114e6669bbb751e335dcb5bd7b
|
| 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 Oct 21, 2026.
Transparency logRelease files / semita-0.2.0-cp312-abi3-macosx_10_13_x86_64.whl
| Download URL | semita-0.2.0-cp312-abi3-macosx_10_13_x86_64.whl |
|---|---|
| Size | 19.8 kB |
| Tags | CPython 3.12 abi3 macOS 10.13+ x86-64 |
|
SHA-256 checksum How to use checksums |
56496745c540dc926bacf4e1df56b61a897cf2e144980e474ecce3942f1682e4
|
|
BLAKE2b-256 checksum How to use checksums |
ceca8bee323e460ee26c46ce4006425001818b670cea6e904dd20139df3d59c0
|
| 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 Oct 21, 2026.
Transparency logSecurity for semita 0.2.0
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.
Full provenance
All 6 files in this release have been uploaded with provenance metadata.
Attestation for semita-0.2.0.tar.gz
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 Oct 21, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.