Generate unused file and directory paths by auto-incrementing numeric suffixes. Similar to how browsers handle duplicate downloads.
Project description
unused-path
Generate unused file and directory paths by auto-incrementing numeric suffixes. Similar to how browsers handle duplicate downloads.
Features
- Automatic numbering: Appends numeric suffixes like "file (1).txt", "file (2).txt" to avoid conflicts
- Intelligent sequencing: Continues from existing numbered files/directories
- Custom formatting: Support for custom formatter functions
- Zero dependencies: Lightweight with no external dependencies
- Type safe: Full type hints for excellent IDE support
- Robust: Handles edge cases, gaps in sequences, and special characters
Installation
pip install unused-path
Usage Examples
Basic Usage
from unused_path import unused_filename, unused_directory
# Generate unused filename
path = unused_filename("document.pdf")
print(path) # 'document.pdf' (if available)
# If file exists, automatically increments
path = unused_filename("document.pdf")
print(path) # 'document (1).pdf'
# Same for directories
dir_path = unused_directory("backup")
print(dir_path) # 'backup' or 'backup (1)' if exists
Atomic Creation (Race-Safe)
# Atomically create file if it doesn't exist
path = unused_filename("download.zip", create=True)
# File is created atomically, safe for concurrent access
# Same for directories
dir_path = unused_directory("exports", create=True)
Custom Formatting
# Custom formatter for files
formatter = lambda base, ext, n: f"{base}_v{n:03d}{ext}"
path = unused_filename("log.txt", formatter=formatter)
print(path) # 'log_v001.txt'
# Custom formatter for directories
formatter = lambda base, n: f"{base}_v{n}"
dir_path = unused_directory("backup", formatter=formatter)
print(dir_path) # 'backup_v1'
Handling Existing Numbered Files
# If you have: test.txt, test (1).txt, test (3).txt
# The function will intelligently use test (2).txt
path = unused_filename("test.txt")
print(path) # 'test (2).txt'
API Reference
| Function | Description |
|---|---|
unused_filename(path, *, formatter=None, max_tries=10000, create=False) |
Generate unused filename by appending numeric suffix if needed |
unused_directory(path, *, formatter=None, max_tries=10000, create=False) |
Generate unused directory name by appending numeric suffix if needed |
Parameters
path: Desired file or directory path (str or PathLike)formatter: Optional custom formatter function- For files:
(base: str, ext: str, n: int) -> str - For directories:
(base: str, n: int) -> str
- For files:
max_tries: Safety limit to avoid infinite loops (default: 10,000)create: If True, atomically create the file/directory (race-safe)
Returns
- Unused path (str) - absolute or relative, matching input format
Raises
RuntimeError: If no unused path is found within max_triesOSError: If file/directory creation fails (when create=True)
Why unused-path?
When working with file operations, you often need to avoid overwriting existing files:
- ❌ Downloading files that might already exist
- ❌ Creating backup directories with the same name
- ❌ Exporting data to files that may already be present
- ❌ Generating temporary files without conflicts
unused-path handles this automatically, similar to how browsers handle duplicate downloads.
Changelog
See CHANGELOG.md for a detailed list of changes and version history.
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Support
If you find this library helpful:
- ⭐ Star the repository
- 🐛 Report issues
- 🔀 Submit pull requests
- 💝 Sponsor on GitHub
License
MIT © Y. Siva Sai Krishna - see LICENSE file for details.
Author's GitHub • Author's LinkedIn • Report Issues • Package on PyPI
Project details
Release history Release notifications | RSS feed
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 unused_path-1.0.0.tar.gz.
File metadata
- Download URL: unused_path-1.0.0.tar.gz
- Upload date:
- Size: 20.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7fe4f21f04b3763f81644f90014cf80d46b837af4065c39a4ea3a049438aae24
|
|
| MD5 |
4e9b30cb0eaae5cb2b886c534fa67057
|
|
| BLAKE2b-256 |
0b62ca6728968df8127174da4f8b89195cb26ff79e0d395f529fdd538288f31e
|
File details
Details for the file unused_path-1.0.0-py3-none-any.whl.
File metadata
- Download URL: unused_path-1.0.0-py3-none-any.whl
- Upload date:
- Size: 7.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e12d9909c87fbfa8a5d6a22f6e7c9046dd44d14c79387ee9becd23b3c6848cfd
|
|
| MD5 |
b22d82e4de31dfac36a90c8bc32447b3
|
|
| BLAKE2b-256 |
d4ccd8ef9056a1d801261ba55dd0735c70b39a8cafca95aa8464df91fa2e02b5
|