Python CLI tools for photography workflows
Project description
Photo Tools CLI
Command-line tools for organising photos by date, managing RAW/JPG pairs, and optimising images.
Changelog
See CHANGELOG.md for release history.
Supported formats
- RAW:
.cr2,.cr3,.nef,.arw,.raf,.orf,.rw2,.dng,.pef,.srw,.x3f - JPG:
.jpg,.jpeg
⚠️ Note: Detection is based on file extensions only (case-insensitive). Files with incorrect or missing extensions may not be handled correctly.
Prerequisites - System Tools
This project depends on external system tools in addition to Python.
ExifTool
Used for extracting image metadata (including RAW formats).
- Supports all major image formats, including RAW
- Provides consistent metadata fields across formats
- More reliable than Python-only EXIF libraries
If exiftool is not installed, the CLI will fail with a clear error message and exit code 1.
Install (macOS)
brew install exiftool
On Linux, install via your package manager (e.g. apt install exiftool).
Installation
Using pipx (recommended)
pipx install photo-tools-cli
Installs the CLI in an isolated environment and makes photo-tools available globally, avoiding dependency conflicts.
Check installed version:
photo-tools --version
Using pip (if pipx not available)
pip install photo-tools-cli
Local development
Clone the repository and install:
pip install -e .
pip install --group dev -e .
Usage
List available commands:
photo-tools --help
Each command provides detailed usage, including arguments and options:
photo-tools <command> --help
Note: All commands currently process files in the top-level input directory only.
Global flags
All commands support:
--dry-run— preview changes without modifying files--verbose/-v— show per-file output
Flags can be combined:
photo-tools <command> ... --dry-run --verbose
Organise by date (by-date)
- Organise images into date-based folders (
YYYY-MM-DD, optional suffix) - Files are moved (not copied) into the output directory
- If a destination file already exists, it is skipped (no overwrite)
photo-tools by-date <INPUT_DIR> <OUTPUT_DIR>
photo-tools by-date <INPUT_DIR> <OUTPUT_DIR> --suffix <SUFFIX>
Separate RAW files (raws)
- Move RAW images into a
raws/subfolder within the input directory - Non-RAW files are left unchanged
- Files are moved (not copied) in place
- If a destination file already exists, it is skipped (no overwrite)
photo-tools raws <INPUT_DIR>
Clean unpaired RAW files (clean-raws)
- Move RAW files to
raws-to-delete/if no matching JPG (same prefix) exists - Matching is based on filename prefix (e.g.
abcd.RAFmatchesabcd_edit.jpg) - Files are moved (not deleted), making the operation reversible
photo-tools clean-raws <RAW_DIR> <JPG_DIR>
Keep RAW files for 5-star JPGs (keep-5star-raws)
- Move RAW files to raws-5-star/ if a matching JPG has a 5-star rating
- Ratings are read from the JPG files, not the RAW files
- Matching is based on filename prefix (e.g. abcd.RAF matches abcd.jpg or abcd_edit.jpg)
- Files are moved (not copied), making the operation reversible
photo-tools keep-5star-raws <RAW_DIR> <JPG_DIR>
Optimise images (optimise)
- Resize images to a maximum width of
2500px - Choose the highest quality that results in a file size ≤
500 KB(never below70%) - Saves optimised images with prefix
lq_in the same directory (overwrites existing files)
photo-tools optimise <INPUT_DIR>
Local Development Setup
Data
For convenience during development, you can create a local structure:
mkdir -p data/input data/output
Place test photos in:
data/input/
Running the CLI
You can run the CLI module directly for testing:
python -m photo_tools.cli by-date ./data/input ./data/output
Running tests
This project uses pytest:
pytest
Makefile
Common development tasks are available via the Makefile.
Project details
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 photo_tools_cli-0.3.1.tar.gz.
File metadata
- Download URL: photo_tools_cli-0.3.1.tar.gz
- Upload date:
- Size: 14.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d143156aba04a1543d9a90beba61138516e2e7eac900e7785ed0621c7eafede1
|
|
| MD5 |
7eb0c497483d4fcd68749d4dd7852ef3
|
|
| BLAKE2b-256 |
1d18ceb82dbc14f82e6f12a13b51900326c05bbf68c912257d17d227a42f9ef5
|
Provenance
The following attestation bundles were made for photo_tools_cli-0.3.1.tar.gz:
Publisher:
publish.yml on aga87/python-photo-tools
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
photo_tools_cli-0.3.1.tar.gz -
Subject digest:
d143156aba04a1543d9a90beba61138516e2e7eac900e7785ed0621c7eafede1 - Sigstore transparency entry: 1328147060
- Sigstore integration time:
-
Permalink:
aga87/python-photo-tools@b9522c4671affab1a173da264922158b597b5c59 -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/aga87
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b9522c4671affab1a173da264922158b597b5c59 -
Trigger Event:
push
-
Statement type:
File details
Details for the file photo_tools_cli-0.3.1-py3-none-any.whl.
File metadata
- Download URL: photo_tools_cli-0.3.1-py3-none-any.whl
- Upload date:
- Size: 15.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea636e0120ef892a1f96e88cd00beba6ced414bd6f3523a86776a791ed835742
|
|
| MD5 |
e35c9713daaf0b41b035d8d80c48d8b9
|
|
| BLAKE2b-256 |
62811952fd712ee4cf80c129d29caf433e3fbd479afa51c961c947a8d4e61ffb
|
Provenance
The following attestation bundles were made for photo_tools_cli-0.3.1-py3-none-any.whl:
Publisher:
publish.yml on aga87/python-photo-tools
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
photo_tools_cli-0.3.1-py3-none-any.whl -
Subject digest:
ea636e0120ef892a1f96e88cd00beba6ced414bd6f3523a86776a791ed835742 - Sigstore transparency entry: 1328147075
- Sigstore integration time:
-
Permalink:
aga87/python-photo-tools@b9522c4671affab1a173da264922158b597b5c59 -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/aga87
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b9522c4671affab1a173da264922158b597b5c59 -
Trigger Event:
push
-
Statement type: