WARPCLEAN
Organize Your Files at Warp Speed
pip install warpclean
WARPCLEAN is a deterministic, rule-based Python CLI for organizing files. It is built for speed, safety, and reversibility. No machine learning. No unpredictable heuristics. Just a fast, reliable pipeline that does exactly what you expect.
Point it at any directory. Preview what will happen. Execute when ready. Undo if needed.
The Problem
Your Downloads folder is a disaster. Your Desktop is cluttered. Your photo library is a mess of IMG_0001.jpg duplicates scattered across five folders.
You need to organize, but:
- You don't want to lose files
- You don't want to spend hours doing it manually
- You don't trust tools that move things without showing you first
- You need a way to undo if something goes wrong
The Solution
WARPCLEAN gives you complete control:
| Feature | What It Does |
|---|---|
| Dry Run | See exactly what will happen before any file is touched |
| Undo System | Every operation is logged and fully reversible |
| Copy Mode | Organize into a new folder without moving originals |
| Warp Drive Mode | Skip deep content analysis for maximum speed |
| Duplicate Detection | Identify and skip duplicate files automatically |
| Date Organization | Sort photos and videos by year, month, and day |
| Related File Grouping | Keep sequences and versions together |
| Progress Tracking | Visual progress bars for large operations |
| Depth Control | Limit recursion with --depth N |
| Exclude Patterns | Skip files/dirs via --exclude, --exclude-file, or .warpcleanignore |
| Confirmation Prompt | Real runs summarize the plan and ask before touching anything |
| Config File | Per-user and per-directory .toml defaults and custom categories |
| Run Statistics | --stats prints counts, bytes, per-category breakdown, elapsed time |
| Idempotent | A second run on an organized directory does nothing at all |
Installation
Requirements: Python 3.11 or newer (the config loader uses the stdlib tomllib module)
pip install warpclean
Once installed, the warpclean command is available globally in your terminal. You can also check what you have:
warpclean --version
Development Setup
See CONTRIBUTING.md for setup, tests, lint, and the module layout.
Bundled Dependencies
These are installed automatically. You do not need to add them yourself.
| Package | Purpose |
|---|---|
rich |
Colored terminal output, formatted tables, and progress bars |
python-magic |
Deep MIME-type detection using file content signatures |
On Windows, python-magic-bin is installed instead of python-magic. If either import fails at runtime, WARPCLEAN degrades gracefully: output falls back to plain text, and classification falls back to file extensions.
Quick Start
Preview Before You Organize
Run a dry run to see what WARPCLEAN would do without touching any files:
warpclean ~/Downloads --dry-run
This executes the full classification and planning pipeline, then displays a complete report of all proposed moves. Nothing is changed on disk.
Organize For Real
When you are ready:
warpclean ~/Downloads
WARPCLEAN builds the plan, prints how many files land in which folder, and asks:
About to move 42 file(s) into /home/you/Downloads:
Pictures: 21 file(s)
Documents: 14 file(s)
Archives: 7 file(s)
Proceed? [y/N]
Anything other than y/yes aborts without touching a file. Pass --yes (or -y) to skip the prompt. See Confirmation Prompt for the scripting rules.
Once confirmed, files are moved into structured category folders. Every operation is logged for undo.
Keep Your Originals
If you want to organize without moving the source files:
warpclean ~/Downloads --copy
This creates a warpclean/ subdirectory containing the organized structure. Your original files remain exactly where they were.
How It Works
WARPCLEAN runs a strict six-stage pipeline:
SCAN >>> CLASSIFY >>> PLAN >>> CONFIRM >>> EXECUTE >>> LOG
Stage 1: Scan
Recursively discovers all files in the target directory. Hidden files and system files are respected. Symbolic links are handled safely. A top-level directory named warpclean is always skipped, which is what makes --copy idempotent.
Stage 2: Classify
Each file is analyzed to determine its type. Classification uses:
- MIME type detection (preferred, uses file content signatures)
- File extension (fallback when MIME detection is unavailable)
- Explicit category rules (for special file types like installers)
In Warp Drive Mode (--fast), content analysis is skipped and extensions are trusted directly.
Stage 3: Plan
A complete operation plan is built before any changes occur. The plan includes:
- Source and destination paths for every file
- Skip decisions for files already in their correct locations
- Collision resolution (automatic renaming if a different file already holds the destination name)
The identity check runs before collision resolution, which is what makes WARPCLEAN idempotent. See Idempotency.
Stage 4: Confirm
On a real run, the operation count and a per-folder breakdown are printed and you are asked to confirm. Dry runs skip this stage entirely. --yes skips it, and it is skipped automatically when stdin is a genuine pipe or redirect. If the prompt is shown and the read hits end-of-input, the run aborts. See Confirmation Prompt.
Stage 5: Execute
Moves or copies are performed file by file. If an individual operation fails (e.g. a permission error), it is logged with an error status and the pipeline continues with the remaining files rather than aborting.
Stage 6: Log
Every successful operation is recorded to .warpclean_undo.jsonl in the target directory. The log is written incrementally, one line per file, as each operation completes. Pressing Ctrl+C mid-run therefore still leaves a complete, reversible record of everything that actually moved.
Organization Categories
Files are sorted into these default categories:
| Category | File Types |
|---|---|
Pictures/ |
JPEG, PNG, GIF, WebP, SVG, RAW formats, PSD, HEIC |
Videos/ |
MP4, MKV, AVI, MOV, WebM, FLV, WMV |
Audio/ |
MP3, FLAC, WAV, AAC, OGG, M4A, AIFF |
Documents/ |
PDF, DOCX, XLSX, PPTX, TXT, MD, ODT, EPUB |
Archives/ |
ZIP, RAR, 7Z, TAR, GZ, BZ2, XZ |
Installers/ |
EXE, MSI, DMG, DEB, RPM, AppImage |
Misc/ |
Everything else |
Classification is deterministic. The same file will always be placed in the same category.
You can add your own categories, or steal extensions away from the built-ins, with a config file.
Feature Reference
Dry Run Mode
warpclean ~/Downloads --dry-run
Simulates the entire organization process without modifying any files. Displays a detailed table showing:
- Source file name
- Action (move/copy direction)
- Destination path
This is the recommended first step for any new directory.
Tree View
warpclean ~/Downloads --dry-run --tree
Displays dry run results as a visual directory tree instead of a table. Useful for understanding the final folder structure before committing.
Copy Mode
warpclean ~/Downloads --copy
Instead of moving files, creates organized copies in a warpclean/ subdirectory:
~/Downloads/
├── original_file.pdf # untouched
├── another_file.jpg # untouched
└── warpclean/
├── Documents/
│ └── original_file.pdf # organized copy
└── Pictures/
└── another_file.jpg # organized copy
Perfect for organizing without risk, or for creating a parallel organized structure.
Copy mode is idempotent. The scanner always skips a top-level directory named warpclean, so running --copy twice does not produce warpclean/warpclean/. The second run only sees files that are still loose in the target directory.
Caveat: that skip is unconditional and name-based. If you already have your own folder named warpclean at the top level of the target directory, its contents will never be scanned or organized, with or without --copy. Rename it, or point WARPCLEAN somewhere else.
Warp Drive Mode
warpclean ~/Downloads --fast
Skips content-based MIME detection and trusts file extensions directly. This dramatically increases throughput for large directories.
Use when:
- Processing thousands of files
- Extensions are reliable
- Speed is more important than deep content inspection
Avoid when:
- Files have incorrect or missing extensions
- You need precise content-based classification
Date-Based Organization
warpclean ~/Photos --date-based
Organizes images and videos into a date-based folder hierarchy:
Pictures/
└── 2024/
└── 01/
└── 15/
├── IMG_0001.jpg
└── IMG_0002.jpg
Uses file modification time to determine dates. Ideal for camera dumps, screenshots, and media archives.
Date organization keys off the file's media type, not the folder name. A file classified as image or video gets YYYY/MM/DD subfolders whether it landed in a built-in folder or in a custom [categories] folder. Everything else stays flat. Files with no usable timestamp fall back to the flat folder. See Config File.
Duplicate Detection
warpclean ~/Files --detect-duplicates
Detects duplicate files using a two-stage process:
- Size filtering: Files with unique sizes are immediately cleared
- MD5 hashing: Files with matching sizes are hashed and compared
Behavior:
- First occurrence is organized normally
- Subsequent duplicates are skipped
- No files are deleted automatically
- Duplicate count is reported at the end
Related File Grouping
warpclean ~/Projects --group-related
Identifies and groups files that belong together:
| Pattern | Example |
|---|---|
| Numbered sequences | img_001.jpg, img_002.jpg, img_003.jpg |
| Versioned files | report_v1.docx, report_v2.docx, report_final.docx |
| Sidecar files | photo.jpg, photo.xmp, photo.jpg.json |
Grouped files are placed together in a collection folder to prevent separation.
Progress Bars
warpclean ~/Downloads --progress
Displays visual progress bars during scanning, classification, and execution.
Shows:
- Current operation
- Files processed / total files
- Elapsed time
- Estimated time remaining
Progress bars stay opt-in, and they additionally require a real terminal. When stdout is piped, redirected, or running under CI, --progress is silently ignored so log files do not fill with animation frames.
Depth Control
warpclean ~/Downloads --depth 0
Limits how deep WARPCLEAN scans into subdirectories:
| Value | Behavior |
|---|---|
--depth 0 |
Only files in the root directory (no subdirs) |
--depth 1 |
Root + immediate subdirectories |
--depth 2 |
Up to 2 levels deep |
| (default) | Unlimited depth (scan everything) |
Use when:
- You only want to organize files at the top level
- You want to avoid touching deeply nested project folders
- You need fine control over which directories are processed
Example: Organize only files directly in Downloads, ignoring subfolders:
warpclean ~/Downloads --depth 0 --dry-run
Exclude Patterns
warpclean ~/Downloads --exclude node_modules --exclude "*.tmp"
Skips files and directories matching gitignore-lite patterns. Patterns come from three sources, merged together:
| Source | How |
|---|---|
--exclude PATTERN |
Repeatable flag, one pattern per use |
--exclude-file PATH |
A file with one pattern per line |
.warpcleanignore |
Auto-discovered in the target directory, no flag needed |
Pattern syntax (gitignore-lite, no negation / ! support):
| Pattern | Behavior |
|---|---|
# comment |
Ignored, as are blank lines |
node_modules |
No / — matches this basename anywhere |
build/ |
Trailing / — matches directories only |
src/tmp |
Contains / — matches against the path relative to the scan root |
Example .warpcleanignore:
# build artifacts
node_modules
*.tmp
dist/
Use when:
- You want to skip version control or dependency folders
- You have temp/cache files that shouldn't be organized
- You want a reusable, per-directory ignore file instead of repeating flags
Config File
WARPCLEAN reads TOML config files so you do not have to retype the same flags. Discovery order, later wins:
| Order | Location | Scope |
|---|---|---|
| 1 | ~/.config/warpclean/config.toml |
Per-user, applies everywhere |
| 2 | .warpclean.toml in the target directory |
Per-directory |
| 3 | Explicit CLI flags | Always win |
A flag you actually typed always beats both files. A flag you did not type falls back to the config, then to the built-in default.
[defaults]
progress = true
depth = 1
detect_duplicates = true
[categories]
Pictures = [".jpg", ".png", ".heic"]
Code = [".py", ".rs", ".go"]
[defaults] is an allowlist of run-shaping flags, spelled as long-form flag names with dashes turned into underscores. Exactly these 15 keys are accepted:
group_related, fast, clean_empty_dirs, copy, detect_duplicates, date_based, progress, verbose, color, no_color, tree, depth, exclude, exclude_file, stats
Booleans take true/false, depth takes an integer, exclude takes a string or a list of strings.
Six real flags are refused from a config file, each with a warning naming the key and the reason: dry_run, undo, yes, no_config, help, version. The reasoning is that a config file must not be able to change what a command is. dry_run = true would silently neuter every run in that directory so nothing would ever actually be organized; yes = true would disable the confirmation prompt for a tool that moves files; undo is a one-off recovery command, not a persistent default; no_config cannot ask for config files to be ignored; help and version are not settings. Pass those on the command line instead.
[categories] adds to or overrides the extension-to-folder mapping. Each key is a destination folder name, each value is a list of extensions (the leading dot is optional and case is ignored). An extension listed here beats whatever built-in rule would otherwise claim it. Extensions you do not list keep their built-in behavior completely.
Custom categories participate in --date-based on the same terms as the built-ins. Date organization is decided by the file's media type, not by the folder name:
| Config entry | Without --date-based |
With --date-based |
|---|---|---|
Photos = [".png"] |
Photos/x.png |
Photos/2026/08/09/x.png |
Code = [".py"] |
Code/x.py |
Code/x.py (not media, flat) |
This is the same rule the built-ins follow: Pictures/ and Videos/ gain date subfolders, Documents/ stays flat.
Error handling:
| Situation | Behavior |
|---|---|
Refused key in [defaults] |
Warning naming the key and why, key ignored, run continues |
Unknown key in [defaults] |
Warning printed, key ignored, run continues |
| Malformed TOML, or unreadable file | Error printed, exits with code 2 |
| No config files present | Silently uses built-in defaults |
To ignore every config file for a single run:
warpclean ~/Downloads --no-config
Colored Output
Color is automatic. Rich output with formatted tables is on by default when stdout is a terminal, and off when output is piped, redirected, or running in CI. You do not need a flag for the common case.
Two flags override the detection:
| Flag | Effect |
|---|---|
--no-color |
Force color off, even on a terminal |
--color |
Force color on, even when not a terminal (useful when piping into a pager) |
warpclean ~/Downloads --no-color # plain text on a terminal
warpclean ~/Downloads --color | less -R # keep color through a pipe
If both are passed, --no-color wins.
Confirmation Prompt
A real (non-dry-run) run summarizes the plan and asks Proceed? [y/N] before moving anything. Only y or yes proceeds; anything else aborts with exit code 1 and no files touched.
warpclean ~/Downloads --yes # skip the prompt
warpclean ~/Downloads -y # same
The decision is made in this order:
| Order | Situation | Result |
|---|---|---|
| 1 | --yes / -y was passed |
Proceeds. Nothing is read from stdin at all. |
| 2 | stdin is a genuine pipe or redirect (not a terminal) | Proceeds, and logs that it did. |
| 3 | The prompt was shown and the read hit end-of-input | Aborts. Exit code 1, no files touched. |
Case 3 is a deliberate refusal, and it changed: an end-of-input read used to be treated as consent. This tool moves files, and an ambiguous read is not consent. It shows up on stdin that looks interactive but yields nothing, such as an inherited Windows NUL handle that reports isatty() as true. You get an explicit message rather than a silent mass move:
No answer could be read from stdin (end of input).
Refusing to proceed: this tool moves files, so an ambiguous read is not consent.
Pass --yes for an unattended run.
If you automate warpclean, pass --yes explicitly. Do not rely on stdin detection to infer it for you.
Upgrading from 0.1.x? This is the one behavior change that will surprise you. The same command you ran last week now stops and asks. Add
--yesto restore the old behavior.
Version
warpclean --version
Prints the installed version and exits. It works without a path argument.
Verbose Logging
warpclean ~/Downloads --verbose
Enables detailed debug output. Shows:
- Every file discovered during scan
- Classification decisions and reasoning
- Plan generation details
- Individual operation results
Empty Directory Cleanup
warpclean ~/Downloads --clean-empty-dirs
After organization (or undo), recursively removes any empty directories left behind. Only removes directories that are completely empty.
Run Statistics
warpclean ~/Downloads --stats
Prints a summary block after the run: files scanned, planned, moved (or copied), skipped, errors, duplicates skipped when --detect-duplicates is on, a per-category breakdown with file counts and byte totals, the total bytes in human units, and elapsed wall-clock time.
RUN SUMMARY
Files scanned: 6
Files planned: 6
Files moved: 6
Files skipped: 0
Errors: 0
Bytes moved: 308 B
Elapsed: 0.04s
== Per-category breakdown =
Folder | Files | Size
---------------------------
Documents |3 |54 B
Pictures |2 |240 B
Archives |1 |14 B
===========================
It works on dry runs too, where every count is what would have happened and the block says so:
RUN SUMMARY (DRY RUN - nothing was written; counts are what WOULD happen)
Files scanned: 6
Files planned: 6
Files that would be moved: 6
Files skipped: 0
Errors: 0
Bytes that would be moved: 308 B
Elapsed: 0.04s
The per-category table follows it unchanged in shape.
When nothing was organized, the breakdown states so explicitly rather than printing nothing:
Per-category breakdown: none (no files were organized).
Settable from a config file as stats = true.
Idempotency
Running WARPCLEAN twice on the same directory is a no-op the second time:
$ warpclean ~/Downloads --yes
Done. 6 file(s) moved successfully.
$ warpclean ~/Downloads --yes
Found 6 files.
Classifying...
Planning moves...
No moves necessary. Everything is clean!
A file already sitting in its correct category folder is recognized as already placed and dropped from the plan before collision resolution ever looks at it.
Fixed in 0.2.0. Every 0.1.x release had this backwards: the source-equals-destination check ran after collision resolution, so an already-organized file collided with itself and was renamed. A second
warpclean ~/Downloadsrenamed every organized file toname_1.ext, a third toname_1_1.ext, and so on. If you are on 0.1.x, upgrade; if a past run left_1-suffixed files behind,--undowill reverse them.
Undo System
Every operation batch is logged to .warpclean_undo.jsonl in the target directory.
List Batches
warpclean ~/Downloads --undo --list-batches
Lists what is in the undo log without reversing anything: the N you would pass to --undo N, the batch timestamp, its operation count, and whether the batch is complete or was interrupted.
2 batch(es) in C:\...\demo\.warpclean_undo.jsonl (newest first):
N TIMESTAMP OPS STATE
1 2026-08-09T07:30:40.646463 1 complete
2 2026-08-09T07:30:34.235895 6 complete
Pass the N above to --undo N to reverse that many of the newest batches (--undo 0 reverses all).
A missing log, an empty log, and a log with no batch markers each get their own message rather than silence.
--list-batches is only a modifier of --undo. Passing it on its own is an error and exits with code 2:
[ERROR] --list-batches only works together with --undo. Try: warpclean ~/Downloads --undo --list-batches
Undo Last Operation
warpclean ~/Downloads --undo
Reverses the most recent batch of operations. Files are moved back to their original locations.
Undo Multiple Batches
warpclean ~/Downloads --undo 3
Reverses the last 3 batches of operations.
Undo Everything
warpclean ~/Downloads --undo 0
Reverses all logged operations. Returns the directory to its original state.
Preview an Undo
warpclean ~/Downloads --undo --dry-run
warpclean ~/Downloads --undo 0 --dry-run
Shows exactly what the undo would reverse without touching anything on disk. Works with any --undo count.
How Undo Works
- Operations are replayed in reverse order
- Destination directories created during organization are cleaned up
- The undo itself is not logged (prevents infinite loops)
- If a file has been modified or deleted since organization, undo will skip it safely
- Because the log is written incrementally, an interrupted run is still fully undoable
Command Reference
warpclean <path> [options]
Positional Arguments
| Argument | Description |
|---|---|
path |
Target directory to organize |
Options
| Flag | Description |
|---|---|
--dry-run |
Simulate operations without moving files (also previews --undo) |
--group-related |
Keep related files (sequences, versions, sidecars) together |
--undo [N] |
Undo last N operation batches (default: 1, use 0 for all) |
--fast |
Warp drive mode: trust extensions, skip content detection |
--clean-empty-dirs |
Remove empty directories after organizing |
--copy |
Copy files to warpclean/ subdirectory instead of moving |
--detect-duplicates |
Identify and skip duplicate files |
--date-based |
Organize images and videos by date (YYYY/MM/DD structure) |
--progress |
Show progress bars (requires a terminal) |
--verbose, -v |
Enable detailed debug logging |
--color |
Force colored output on (default: on when stdout is a tty) |
--no-color |
Force colored output off |
--tree |
Display dry run results as a directory tree |
--depth N |
Limit scan depth (0 = root only; default unlimited) |
--exclude PATTERN |
Gitignore-style exclude pattern (repeatable, no negation) |
--exclude-file PATH |
File with one gitignore-style exclude pattern per line |
--stats |
Print a run summary (counts, bytes, per-category, elapsed) |
--list-batches |
With --undo: list undo batches instead of reversing |
--yes, -y |
Skip the confirmation prompt before a real run |
--no-config |
Ignore all config files |
--version |
Print version and exit |
--help, -h |
Show help message |
Exit Codes
| Code | Meaning |
|---|---|
0 |
Success (including a dry run, or nothing to do) |
1 |
Target directory not found, or the confirmation was declined (including an end-of-input read at the prompt) |
2 |
A config file was malformed or unreadable, or --list-batches was passed without --undo |
130 |
Interrupted with Ctrl+C (completed operations remain undoable) |
Safety Guarantees
WARPCLEAN is built with safety as a core design principle:
| Guarantee | Description |
|---|---|
| No overwrites | Destination files are never overwritten. Name collisions are resolved automatically (file.txt becomes file_1.txt). |
| No deletions | Files are never deleted. Duplicates are skipped, not removed. |
| No surprises | Dry run shows exactly what will happen, and a real run asks Proceed? [y/N] before the first file moves. An unreadable answer aborts rather than proceeding. |
| Idempotent | Files already in their correct category folder are skipped, not re-collided. A second run reports No moves necessary. Everything is clean! |
| Full reversibility | Every operation is logged. Undo restores files to their exact original locations. |
| Clean failures | If an operation fails, it is logged as an error and the pipeline continues. Completed operations can be undone. |
| Interrupt-safe | The undo log is written incrementally as each file moves, so Ctrl+C mid-run still leaves a complete, reversible record. |
Real-World Examples
Clean Up a Downloads Folder
warpclean ~/Downloads --progress --clean-empty-dirs
Organizes all files into categories, shows progress, and removes empty folders afterward.
Organize Years of Photos
warpclean ~/Photos --date-based --copy --detect-duplicates --progress
Creates a date-organized copy of your photo library, skipping duplicates and showing progress.
Preview a Project Folder
warpclean ~/Projects --dry-run --tree --group-related
Shows what organization would look like, with related files grouped and displayed as a tree.
Full-Featured Organization
warpclean ~/Messy --copy --date-based --detect-duplicates --group-related --progress
Uses every major feature: copies instead of moves, organizes by date, detects duplicates, groups related files, and shows progress. Color comes on automatically on a terminal.
Unattended or CI Run
warpclean ~/Downloads --yes --no-color --no-config
No prompt, no ANSI escapes in the log, no config file surprises from the machine it happens to run on.
Undo After Testing
warpclean ~/Downloads --undo 0
Reverses all operations and returns the directory to its original state.
License
MIT License
One Last Thing
Always run a dry run first.
warpclean ~/YourFolder --dry-run
Warp speed is powerful. Control keeps it safe.
Metadata
Release files for warpclean 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 | |
|---|---|---|---|
| warpclean-0.2.0.tar.gz | 89.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| warpclean-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 141.9 kB
Release files / warpclean-0.2.0.tar.gz
| Download URL | warpclean-0.2.0.tar.gz |
|---|---|
| Size | 89.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ead94dffbce60d369573a926f8433399825b02f591ec3aefbbeb11bf4955c1d3
|
|
BLAKE2b-256 checksum How to use checksums |
30e0be33c415aee23a0bf4304f541d4fd72f5d4bfe1cb539ebc3df4087b957a0
|
| 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 Aug 9, 2026.
Transparency logRelease files / warpclean-0.2.0-py3-none-any.whl
| Download URL | warpclean-0.2.0-py3-none-any.whl |
|---|---|
| Size | 52.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
87e5e6067bb3353c4747c9f95d88b707abec8e19f2b7e7d6b5619f93d7b44866
|
|
BLAKE2b-256 checksum How to use checksums |
fe99c160d53a106df3271bc6cf2132021ce4b9e2f739755298f8e46d53f5f0fd
|
| 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 Aug 9, 2026.
Transparency log