pathlib3
Extended pathlib with 40+ additional utility methods for Python 3.6+
pathlib3 is a powerful extension of Python's standard pathlib module. It provides a Path3 class that inherits ALL functionality from pathlib.Path while adding 40+ convenient methods for common file and directory operations.
🚀 Features
- ✅ 100% Compatible - All
pathlib.Pathmethods work exactly as before - ✅ 40+ New Methods - Additional utilities for everyday file operations
- ✅ Type Hints - Full type hint support for better IDE experience
- ✅ Method Chaining - Chainable methods for fluent API style
- ✅ Zero Dependencies - Only uses Python standard library
- ✅ Well Documented - Comprehensive docstrings with examples
📦 Installation
pip install pathlib3
Or install from source:
git clone https://github.com/cumulus13/pathlib3.git
cd pathlib3
pip install -e .
🎯 Quick Start
from pathlib3 import Path3 as Path
# Use all standard pathlib.Path methods
p = Path("myfile.txt")
p.exists() # Standard pathlib
p.read_text() # Standard pathlib
p.write_text("hi") # Standard pathlib
# Plus 40+ new methods!
p.ext() # Get extension: "txt"
p.basename() # Get filename: "myfile.txt"
p.size_human() # Get size: "1.5 KB"
p.ensure_parent().touch() # Create parent dirs and file
p.copy_to("backup.txt") # Copy file
p.append_text("more content") # Append to file
p.hash() # Get SHA256 hash
📚 Documentation
Basic Utilities
Get file information easily:
from pathlib3 import Path3 as Path
p = Path("/home/user/documents/report.pdf")
# File name operations
p.ext() # "pdf" - extension without dot
p.basename() # "report.pdf" - filename with extension
p.base() # "report" - filename without extension
p.dirname() # "/home/user/documents" - directory path
# Path operations
p.abspath() # Get absolute path as string
p.normpath() # Normalize path (remove redundant separators)
Handling None Values
pathlib3 safely handles None values:
from pathlib3 import Path
# Path(None) returns current directory
p = Path(None) # Path('.')
other_dir = None # if some variable is None
p = Path(other_dir, "my_dir") # Path('my_dir')
# Use safe() for explicit None handling
p = Path.safe(None) # Path('.')
p = Path.safe(None, '/tmp') # Path('/tmp')
# Use from_optional() to preserve None
p = Path.from_optional(None) # None
p = Path.from_optional("file.txt") # Path('file.txt')
Path Manipulation
Manipulate paths with convenient methods:
# Join paths
p = Path("/home").join("user", "documents", "file.txt")
# Result: /home/user/documents/file.txt
# Change extension
Path("file.txt").change_ext("md") # file.md
Path("file.txt").change_ext(".json") # file.json
# Split path
Path("/home/user/file.txt").split_ext() # ("/home/user/file", ".txt")
Path("/home/user/file.txt").split_path() # ["/", "home", "user", "file.txt"]
Directory Operations
Work with directories efficiently:
# Create directories
Path("/tmp/new/folder").ensure_dir() # Create if doesn't exist
Path("/tmp/new/file.txt").ensure_parent() # Create parent directories
# List directory contents
Path("/tmp").ls() # List all
Path("/tmp").ls("*.txt") # List text files only
Path("/tmp").ls(only_files=True) # Only files
Path("/tmp").ls(only_dirs=True) # Only directories
# Display directory tree
print(Path("/project").tree(max_depth=2))
# Output:
# /project
# ├── src/
# │ ├── main.py
# │ └── utils.py
# ├── tests/
# │ └── test_main.py
# └── README.md
# Find files recursively
Path("/tmp").find("*.py") # Find all Python files
Path("/tmp").find_files("*.txt") # Find text files only
Path("/tmp").find_dirs("test*") # Find directories starting with "test"
File Operations
Perform file operations with ease:
# Copy and move
Path("source.txt").copy_to("dest.txt")
Path("source.txt").copy_to("dest.txt", overwrite=True)
Path("old.txt").move_to("new.txt")
# Create backup
Path("important.txt").backup() # Creates important.txt.bak
Path("important.txt").backup(".backup") # Creates important.txt.backup
# Remove files/directories
Path("file.txt").rm() # Remove file
Path("folder").rm(recursive=True) # Remove directory recursively
Path("file.txt").rm(missing_ok=True) # Don't error if doesn't exist
# Append content
Path("log.txt").append_text("New log entry\n")
Path("data.bin").append_bytes(b'\x00\x01')
# Create file with parent directories
Path("/tmp/new/folder/file.txt").touch_parent()
File Information
Get detailed file information:
# File size
Path("file.txt").size() # 1024 (bytes)
Path("file.txt").size_human() # "1.0 KB"
Path("folder").size() # Total size of all files in folder
# Timestamps
Path("file.txt").mtime() # Modification time
Path("file.txt").ctime() # Creation time
Path("file.txt").atime() # Access time
Path("file.txt").age() # Age in seconds since last modification
# Checks
Path("file.txt").is_empty() # True if file is empty
Path("new.txt").is_newer_than("old.txt") # Compare modification times
Path("old.txt").is_older_than("new.txt") # Compare modification times
Content Operations
Read and write various file formats:
# Read/write text with lines
lines = Path("file.txt").lines() # Read as list of lines
lines = Path("file.txt").lines(strip=False) # Keep whitespace
# JSON support
data = Path("config.json").read_json()
Path("output.json").write_json({"key": "value"})
Path("output.json").write_json(data, indent=4)
# Pickle support
data = Path("data.pkl").read_pickle()
Path("data.pkl").write_pickle({"key": "value"})
# File hashing
Path("file.txt").hash() # SHA256 by default
Path("file.txt").hash("md5") # MD5 hash
Path("file.txt").checksum() # Alias for hash()
# Count lines
Path("code.py").count_lines() # Number of lines in file
Music tag info
Get music file metadata easily:
from pathlib3 import Path
music_file = Path("/mnt/musics/album/file.mp3")
music_file.music_tag() # return dict
music_file.show_info() # print music tag info
music_dir = Path("/mnt/musics/album")
music_dir.music_tag() # return list of dict
music_dir.music_tag(exts=['mp4','m4a']) # return list of dict for specified extensions
music_dir.show_info() # print music tag info for all music files
music_dir.show_info(exts=['mp4','m4a']) # print music tag info for specified extensions
Comparison Operations
Compare files easily:
# Check if files have same content
Path("file1.txt").same_content("file2.txt") # True if identical
File Validation
Validate configuration files:
from pathlib3 import Path
# Validate JSON (built-in, always available)
is_valid, error = Path("config.json").validate()
# Validate YAML (requires: pip install pyyaml)
is_valid, error = Path("config.yaml").validate(strict=False)
# Validate TOML (built-in Python 3.11+, or: pip install tomli)
is_valid, error = Path("settings.toml").validate()
# Validate INI (built-in, always available)
is_valid, error = Path("app.ini").validate()
Optional Dependencies:
- YAML support:
pip install pyyaml - TOML support (Python <3.11):
pip install tomli
Get Metadata
from pathlib3 import Path, PIL_AVAILABLE, PYPDF2_AVAILABLE
# Check available libraries
print(f"Image support: {PIL_AVAILABLE}")
print(f"PDF support: {PYPDF2_AVAILABLE}")
# Get image metadata
meta = Path("photo.jpg").metadata()
print(meta['width'], meta['height'])
print(meta['exif']['camera_make'])
# Get PDF metadata
meta = Path("document.pdf").metadata()
print(f"Pages: {meta['pages']}")
print(f"Author: {meta['author']}")
# Get audio metadata
meta = Path("song.mp3").metadata()
print(f"Artist: {meta['artist']}")
print(f"Duration: {meta['length_human']}")
# Simple summary
print(Path("photo.jpg").metadata_simple())
# Raw metadata
meta = Path("photo.jpg").metadata(raw=True)
print(meta['exif_raw']) # All EXIF data
Email Support
Send files via email easily:
from pathlib3 import Path, EmailConfig
# Setup Gmail config (requires App Password)
config = EmailConfig.gmail('you@gmail.com', 'app_password')
# Send single file
Path('report.pdf').email_as_attachment(
to='boss@company.com',
subject='Monthly Report',
body='Please review.',
config=config
)
# Send multiple attachments
Path.send_email(
to=['client@company.com', 'manager@company.com'],
subject='Project Files',
body='All deliverables attached.',
config=config,
attachments=['report.pdf', 'data.xlsx', 'chart.png']
)
Supported Email Providers:
- Gmail (requires App Password)
- Outlook/Hotmail
- Office 365
- Yahoo
- Custom SMTP servers
from pathlib3 import Path, EmailConfig
# Setup email config (Gmail example)
config = EmailConfig.gmail(
username='your.email@gmail.com',
password='your_app_password' # Get from: https://myaccount.google.com/apppasswords
)
# Send single file
Path('report.pdf').email_as_attachment(
to='boss@company.com',
subject='Monthly Report',
body='Please find the monthly report attached.',
config=config
)
# Send to multiple people
Path('invoice.pdf').email_as_attachment(
to=['client@company.com', 'manager@company.com'],
subject='Invoice #12345',
body='Your invoice is attached.',
cc='accounting@company.com',
bcc='archive@company.com',
config=config
)
html_body = """
<html>
<body>
<h2>Monthly Report</h2>
<p>Dear Boss,</p>
<p>Please find the <strong>monthly report</strong> attached.</p>
<p>Best regards,<br>Your Name</p>
</body>
</html>
"""
Path('report.pdf').email_as_attachment(
to='boss@company.com',
subject='Monthly Report',
body='Plain text version',
body_html=html_body,
config=config
)
# Send email with multiple files
Path.send_email(
to='client@company.com',
subject='Project Deliverables',
body='Please find all project files attached.',
config=config,
attachments=[
'report.pdf',
'presentation.pptx',
'data.xlsx',
Path('images/chart.png')
]
)
# Gmail
config_gmail = EmailConfig.gmail('user@gmail.com', 'app_password')
# Outlook/Hotmail
config_outlook = EmailConfig.outlook('user@outlook.com', 'password')
# Office 365
config_o365 = EmailConfig.office365('user@company.com', 'password')
# Yahoo
config_yahoo = EmailConfig.yahoo('user@yahoo.com', 'password')
# Custom SMTP server
config_custom = EmailConfig(
smtp_server='mail.mycompany.com',
smtp_port=587,
username='user@mycompany.com',
password='password',
use_tls=True
)
html_with_image = """
<html>
<body>
<h2>Check out this chart:</h2>
<img src="cid:chart.png" alt="Sales Chart">
</body>
</html>
"""
Path('chart.png').email_as_attachment(
to='team@company.com',
subject='Sales Chart',
body_html=html_with_image,
config=config,
inline_images=True
)
try:
Path('report.pdf').email_as_attachment(
to='boss@company.com',
subject='Report',
body='Attached.',
config=config
)
print("Email sent successfully!")
except ConnectionError as e:
print(f"Failed to send: {e}")
except ValueError as e:
print(f"Invalid input: {e}")
Image Manipulation
Perform basic image operations:
from pathlib3 import Path
# Multiple ICO files (one per size)
Path('logo.png').to_ico()
# Creates: logo_16.ico, logo_32.ico, logo_48.ico, ...
# Single multi-size ICO (Windows style)
Path('app.png').to_ico(multi_size=True)
# Creates: app.ico (contains all sizes)
# Custom sizes
Path('icon.png').to_ico(
sizes=[16, 32, 64, 128],
multi_size=True
)
# Favicon for website
Path('logo.png').to_ico(
sizes=[16, 32, 48],
output_path='favicon.ico',
multi_size=True
)
# Resize to width (auto height)
Path('photo.jpg').resize(width=1920)
# Resize to fit in 1024x1024
Path('image.png').resize(max_size=1024)
# Exact dimensions (may distort)
Path('banner.jpg').resize(
width=1200,
height=400,
keep_aspect=False
)
# Create thumbnail
Path('photo.jpg').resize(
max_size=300,
output_path='thumb.jpg',
quality=85
)
# Quick thumbnail
Path('photo.jpg').thumbnail() # photo_thumb.jpg (256px max)
# Small square thumbnail
Path('image.png').thumbnail(size=128, square=True)
# Custom output
Path('photo.jpg').thumbnail(
size=200,
output_path='thumbnails/photo_small.jpg'
)
# PNG to JPEG
Path('transparent.png').convert_format('jpg')
# JPEG to WebP (smaller file size)
Path('photo.jpg').convert_format('webp', quality=80)
# Any to PNG (lossless)
Path('image.bmp').convert_format('png')
# JPEG to PNG (preserve transparency)
Path('logo.jpg').convert_format('png')
# Batch resize
for img in Path('photos').find_files('*.jpg'):
img.resize(max_size=1920, output_path=f'resized/{img.name}')
# Create thumbnails for all images
for img in Path('.').find_files('*.png'):
img.thumbnail(size=256)
# Convert all PNG to WebP
for png in Path('images').find_files('*.png'):
png.convert_format('webp', quality=85)
Advanced Usage
Walk directory tree:
# Similar to os.walk()
for dirpath, dirnames, filenames in Path("/project").walk():
print(f"Directory: {dirpath}")
print(f"Subdirs: {dirnames}")
print(f"Files: {filenames}")
Method chaining for fluent API:
# Chain multiple operations
(Path("/tmp/report/data.txt")
.ensure_parent()
.write_text("Report data")
.copy_to("/backup/data.txt"))
# Create, write, and backup in one go
(Path("config.json")
.write_json({"setting": "value"})
.backup())
🔄 Complete Method List
Inherited from pathlib.Path
All standard methods are available: exists(), is_file(), is_dir(), mkdir(), read_text(), write_text(), glob(), rglob(), and many more.
New Methods in Path3
Basic Utilities:
.ext()- Get extension without dot.basename()- Get filename with extension.base()- Get filename without extension.dirname()- Get directory path.abspath()- Get absolute path as string
Hanle None Values:
Path(None, DEFAULT_PATH)- Create Path with default if None.safe(*args)- Create Path, treating None as current dir.from_optional(value)- Create Path or return None if value is None
Path Manipulation:
.normpath()- Normalize path.join(*args)- Join path components.split_ext()- Split into base and extension.split_path()- Split into components list.change_ext(new_ext)- Change file extension
Directory Operations:
.ensure_dir()- Create directory if doesn't exist.ensure_parent()- Create parent directory.touch_parent()- Create parent dirs and touch file.ls(pattern, only_files, only_dirs)- List contents.tree(max_depth)- Display directory tree.find(pattern, recursive)- Find files matching pattern
File Operations:
.rm(recursive, missing_ok)- Remove file/directory.copy_to(dest, overwrite)- Copy to destination.move_to(dest)- Move to destination.append_text(text, encoding, newline)- Append text.append_bytes(data)- Append bytes.backup(suffix)- Create backup copy
File Information:
.size()- Get size in bytes.size_human()- Get human-readable size.mtime()- Get modification time.ctime()- Get creation time.atime()- Get access time.age()- Get age in seconds.is_empty()- Check if empty.is_newer_than(other)- Compare modification times.is_older_than(other)- Compare modification times.metadata(raw)- Get file metadata (images, pdfs, audio).metadata_simple()- Get simplified metadata summary.music_tag(exts)- Get music file tags.show_info(exts)- Print music file tags
Content Operations:
.lines(encoding, strip)- Read lines as list.read_json(encoding)- Read JSON file.write_json(data, indent)- Write JSON file.read_pickle()- Read pickle file.write_pickle(data)- Write pickle file.hash(algorithm)- Calculate file hash.checksum(algorithm)- Alias for hash.count_lines()- Count lines in file
Search & Filter:
.find_files(pattern)- Find files recursively.find_dirs(pattern)- Find directories recursively.walk()- Walk directory tree (like os.walk)
Comparison:
.same_content(other)- Check if files have same content
🆚 Comparison with Standard pathlib
| Operation | Standard pathlib |
pathlib3 |
|---|---|---|
| Get extension | p.suffix.lstrip('.') |
p.ext() |
| Get directory | str(p.parent) |
p.dirname() |
| Absolute path | str(p.absolute()) |
p.abspath() |
| Create parent | p.parent.mkdir(parents=True, exist_ok=True) |
p.ensure_parent() |
| File size | p.stat().st_size |
p.size() |
| Human size | Custom function needed | p.size_human() |
| List files | list(p.glob('*')) |
p.ls() |
| Copy file | shutil.copy2(p, dest) |
p.copy_to(dest) |
| Append text | Open file, write, close | p.append_text(text) |
| JSON read | json.loads(p.read_text()) |
p.read_json() |
| File hash | Custom implementation | p.hash() |
| Directory tree | Custom recursive function | p.tree() |
💡 Tips & Best Practices
Use Method Chaining
# Create a file with all parent directories
(Path("/deep/nested/structure/file.txt")
.ensure_parent()
.write_text("content"))
# Process and backup config
(Path("config.json")
.read_json()
# ... process data ...
.write_json(processed_data)
.backup())
Import as Path for Drop-in Replacement
# Instead of: from pathlib import Path
from pathlib3 import Path3 as Path
# Now use Path as normal, with extra methods available!
Combine with Standard pathlib Features
# Use pathlib features with Path3 extensions
p = Path.home() / "documents" / "report.txt"
p.ensure_parent().write_text("Report content")
# Glob patterns with extensions
for file in Path("/logs").find("*.log"):
if file.age() > 86400: # Older than 1 day
print(f"Old log: {file.basename()} - {file.size_human()}")
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
📝 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built on top of Python's excellent
pathlibmodule - Inspired by the need for more convenient path operations
- Thanks to all contributors!
📮 Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Documentation: Read the Docs
🔗 Links
- PyPI: https://pypi.org/project/pathlib3/
- GitHub: https://github.com/cumulus13/pathlib3
- Documentation: https://pathlib3.readthedocs.io
Author
Metadata
Release files for pathlib3 1.0.15
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pathlib3-1.0.15.tar.gz | 47.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pathlib3-1.0.15-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 77.1 kB
Release files / pathlib3-1.0.15.tar.gz
| Download URL | pathlib3-1.0.15.tar.gz |
|---|---|
| Size | 47.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
221189c3d8a6ec02fd695f9d9556f3dcb8e5a2b9ee908b4afc8cda9a6f376a2b
|
|
BLAKE2b-256 checksum How to use checksums |
e3fcbb9e6f97dde66897146ad335f722fbadd98b8a861afd9a9d740c902facfc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/4.0.2 CPython/3.11.4
|
Release files / pathlib3-1.0.15-py3-none-any.whl
| Download URL | pathlib3-1.0.15-py3-none-any.whl |
|---|---|
| Size | 30.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
79e67d2ab05a75ae83b1ff3bebb81a7663f1d40a4ba1d3c9a45786bb6338bd6d
|
|
BLAKE2b-256 checksum How to use checksums |
f2a9f2a1bc4265af9dfd81b17a217e8721be61ae9512688f1801ff725d72d215
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/4.0.2 CPython/3.11.4
|