find-itch-games (Python)
Find the itch.io app, its install locations, and the games installed in them.
- PyPI:
find-itch-games - API reference: https://sparr.github.io/find-itch-games/python/api/
See the root README for how itch stores its data, where it installs games, and the shared definitions both language implementations are built against. This page covers the Python API.
Install
pip install find-itch-games
Requires Python 3.10 or newer. No runtime dependencies — sqlite3, gzip and
json are all in the standard library. Unlike the JavaScript package, whose
floor is set by node:sqlite, there is no version constraint beyond Python
itself.
Usage
import find_itch_games as fig
fig.find_itch_path()
# => PosixPath('/home/you/.config/itch')
fig.find_itch_libraries_paths()
# => [PosixPath('/home/you/.config/itch/apps'), # the built-in `appdata` location
# PosixPath('/home/you/Games')] # one the user added
fig.find_itch_app_by_id(4225297)
# => PosixPath('/home/you/Games/distributrains')
fig.find_itch_app_by_name("Distributrains")
# => PosixPath('/home/you/Games/distributrains')
# the game's title, its url slug ("distributrains") and its install folder
# name all work
fig.has_itch_app(4225297)
# => True
Everything returns pathlib.Path, and the API is synchronous — unlike the
JavaScript package, which is async because Node's filesystem API is.
Looking games up by name
By default a name must match the title, url slug or install folder name
exactly. Pass exact=False for a search that ignores case, spacing and
punctuation:
fig.find_itch_app_by_name("Cosmic Collapse, a suika-like") # exact title
fig.find_itch_app_by_name("cosmic-collapse") # exact slug
fig.find_itch_app_by_name("cosmic collapse", exact=False) # fuzzy
A fuzzy search can match similarly named games, and the same game can be
installed in two locations. Use the plural forms to see every match, or
strict=True to fail rather than guess:
fig.find_itch_apps_by_name("reboot", exact=False) # -> list[App]
fig.find_itch_apps_by_id(4225297) # every install of that game
fig.find_itch_app_by_name("reboot", exact=False) # first match
fig.find_itch_app_by_name("reboot", exact=False, strict=True) # raises AmbiguousAppError
find_itch()
The whole picture in one call:
itch = fig.find_itch()
# Libraries(
# itch_path=PosixPath('/home/you/.config/itch'),
# database_path=PosixPath('/home/you/.config/itch/db/butler.db'),
# database_available=True,
# strategy='merge',
# libraries=[
# Library(id='appdata', path=..., is_default=False, exists=True, source='db', apps=[]),
# Library(id='87c69020-…', path=PosixPath('/home/you/Games'), is_default=True,
# exists=True, source='db',
# apps=[App(game_id=4225297, path=..., manifest=AppManifest(...))]),
# ])
find_itch_app_manifest(game_id)
The itch answer to Steam's appmanifest_*.acf: the cave row and the receipt,
merged and flattened into an AppManifest dataclass.
manifest = fig.find_itch_app_manifest(1323129)
manifest.title # 'Godot PCK Explorer'
manifest.slug # 'godot-pck-explorer'
manifest.author # 'dmitriysalnikov'
manifest.version # '1.6.0'
manifest.channel_name # 'native-console-linux-64'
manifest.installed_size # 15783510
manifest.source # 'db+receipt'
fig.get_launch_candidate_paths(manifest)
# => [PosixPath('/home/you/Games/godot-pck-explorer/GodotPCKExplorer.Console')]
candidates is butler's own scan of the folder, so it is how you find the
binary to run without guessing. It is empty for games butler has not
configured yet.
Options
Every entry point takes the same keyword arguments.
| Option | Default | Meaning |
|---|---|---|
itch_path |
auto-detected | Use this itch user-data directory instead of searching. |
strategy |
"merge" |
Which of itch's records to read — see below. |
check_exists |
True |
Drop games whose install folder no longer exists. |
extra_libraries |
None |
Additional install locations to scan. |
ignore_database |
False |
Never open butler.db, not even for install locations. |
lookup |
None |
A PathLookup — search as another user, environment or OS. |
The lookup functions take two more: exact (name lookups only) and strict.
Strategies
merge— readbutler.db, confirm each game against the receipt in its install folder, then add any receipt with no matching row. Most complete.db— readbutler.dbonly. Fastest, and the only source of play times, launch candidates and custom install folders.receipts— ignore thecavestable and scan the install locations. Useful when the database is stale. Install locations still come from the database, since nothing on disk records them.
manifest.source tells you which record each result came from: "db",
"receipt" or "db+receipt". The valid strategies are exported as
ITCH_STRATEGIES; anything else raises ValueError rather than being silently
treated as merge.
Searching as another user
PathLookup overrides the home directory, environment and platform the search
is based on — for scanning several user profiles, or a mounted disk:
from find_itch_games import PathLookup, get_itch_path_candidates
get_itch_path_candidates(PathLookup(
home="/mnt/disk/Users/someone",
env={"APPDATA": "/mnt/disk/Users/someone/AppData/Roaming"},
platform="win32",
))
fig.find_itch(lookup=PathLookup(home="/mnt/disk/Users/someone"))
Each field defaults to Path.home(), os.environ and sys.platform.
Errors
ItchNotFoundError— no itch user-data directory found.AppNotFoundError— raised byfind_itch_app_by_id/find_itch_app_by_name.AmbiguousAppError— several games matched andstrict=True;.pathslists them.ItchDatabaseError—butler.dbexists but cannot be read.ValueError—strategywas not one ofITCH_STRATEGIES.
Development
pip install -e ".[dev]"
python -m pytest
The tests build the shared installation described by
shared/fixtures.json, using the schema in
shared/butler-schema.sql, and assert against
the vocabulary in shared/definitions.json — the
same three files the JavaScript suite uses.
tests/test_parity.py additionally runs both implementations against the real
itch installation on the machine and compares their output. It skips itself
when itch is not installed, or when the JavaScript package has not been built.
Building and publishing use hatchling:
python -m build # sdist + wheel into dist/
pipx run twine check dist/*
The version is single-sourced from __version__ in
src/find_itch_games/__init__.py, and is
kept in lockstep with the JavaScript package by npm run version:sync in
node/. Because Python was added after the first JavaScript
release, PyPI has no 0.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
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 find_itch_games-0.1.1.tar.gz.
File metadata
- Download URL: find_itch_games-0.1.1.tar.gz
- Upload date:
- Size: 21.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a091c92d4f7ce71548674868a64eb9e98b32fe4c003bef6dd9a32de8e3da09e8
|
|
| MD5 |
d692259ba328cd85e33a843c1e8ab887
|
|
| BLAKE2b-256 |
f61c5966859bca79cb89775e56093e2101064a808cb420ed8da6269ed635de78
|
File details
Details for the file find_itch_games-0.1.1-py3-none-any.whl.
File metadata
- Download URL: find_itch_games-0.1.1-py3-none-any.whl
- Upload date:
- Size: 26.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc94bbbf43453e66bf1e02f9bf992b8fddd6d3ddb17cdd3b81c05b1a936163ae
|
|
| MD5 |
f834b4bc5139acfc4f4de64e1774b00d
|
|
| BLAKE2b-256 |
cc4919ced5ffac41d52900b77f819255cec98f20421be698bba593922aa27cc3
|