A Python path library that gives filesystem operations superpowers
Project description
nb_path: A Python Path Library with Filesystem Superpowers
[English](README.md) | [简体中文](README.zh.md)
nb_path is a super-enhanced version of Python's standard pathlib.Path. It fully inherits all the elegant features of pathlib (including the / operator) and seamlessly integrates advanced file operations from shutil, compression/decompression from zipfile, hash calculation from hashlib, dynamic module loading from importlib, and even includes powerful built-in features like grep search and rsync-style directory synchronization.
Its design philosophy is: to turn all common path-related operations into methods of the path object itself, enabling an extremely fluid chain of calls.
🆚 Comparison with pathlib
nb_path is not just a simple wrapper around pathlib; it's a powerful superset.
pathlib is a path package, while nb_path is a path and file operation all-in-one package. nb_path not only represents paths but also includes the most commonly used, high-frequency file operations.
| Feature | pathlib.Path |
nb_path.NbPath |
Advantage |
|---|---|---|---|
| Basic Path Operations | ✅ | ✅ | nb_path fully inherits and is compatible with all pathlib features |
| Advanced File/Dir Ops | ❌ | ✅ | Built-in methods like copy_to, move_to, delete, empty |
| Ensure Parent Exists | ❌ | ✅ | ensure_parent() method prevents FileNotFoundError |
| Compression/Decompression | ❌ | ✅ | zip_to() and unzip_to() for easy archive handling |
| Content Search (grep) | ❌ | ✅ | grep() method for efficient text search in files or directories |
| Intelligent Dir Sync | ❌ | ✅ | sync_to() method for rsync-style incremental synchronization |
| Network File Download | ❌ | ✅ | download_from_url() method to download a file directly to the path |
| Project Root Discovery | ❌ | ✅ | find_project_root() and find_git_root() to end path headaches |
| Dynamic Module Import | ❌ | ✅ | import_as_module() is a powerful tool for plugin development |
| Convenient Temp Files/Dirs | ❌ | ✅ | tempfile() and tempdir() context managers with auto-cleanup |
| Process-Safe File Locking | ❌ | ✅ | lock() context manager for safe concurrent file access |
| Utility Toolkit | ❌ | ✅ | Built-in utilities like hash(), size_human(), expand() |
✨ Core Features
- Fully
pathlibCompatible: Seamless migration, zero learning curve. - Powerful File/Directory Operations:
copy_to,move_to,delete,empty,ensure_parent, etc., are more intuitive thanshutil. - Smart Compression & Decompression:
zip_to()andunzip_to()for easy handling of ZIP files. - Built-in
grepFunctionality: Thegrep()method allows for efficient text/regex searches in files or entire directories. - Intelligent Directory Sync: The
sync_to()method, a lightweightrsync, can intelligently synchronize two directories. - Network File Download:
download_from_url()downloads a file from a URL directly to the specified path. - Project Root Discovery:
find_project_root()andfind_git_root()eliminate tedious relative path calculations. - Dynamic Module Import:
import_as_module()can dynamically import any.pyfile as a module, a powerful tool for plugin-based development. - Convenient Temp Files/Dirs:
tempfile()andtempdir()context managers return fully-featuredNbPathobjects and handle cleanup automatically. - Utility Toolkit:
hash(),size_human(),expand(), and more to meet various daily development needs.
🚀 Installation
pip install nb-path
⚡ Quick Start: Elegant Chaining
Imagine this common automation task: download a ZIP archive, extract it, find a specific file, process its content, and then save it to the project's output directory.
With nb_path, the entire process can be done in one go:
from nb_path import NbPath
# Simulate a data source URL
MOCK_URL = "https://example.com/data.zip"
# Perform all operations in a temporary, auto-cleaning workspace
with NbPath.tempdir(prefix="data-processing-") as workspace:
print(f"Created temporary workspace: {workspace}")
# Core operations: download -> unzip -> find in unzipped dir -> read -> process
unzipped_dir = (
(workspace / "downloaded.zip")
.download_from_url(MOCK_URL, overwrite=True)
.unzip_to(workspace / "unzipped")
)
processed_content = (
unzipped_dir.rglob_files("data.txt")[0].read_text().upper()
)
# Save the processed result to the project's output directory
output_file = (
(NbPath.self_py_dir() / "output" / "report.txt")
.ensure_parent()
.write_text(processed_content)
)
print(f"Processing complete, result saved to: {output_file}")
print("Temporary workspace has been automatically cleaned up.")
This example perfectly demonstrates the core advantages of nb_path: high cohesion, high readability, and high efficiency.
📖 API Guide
Here is a detailed guide to the main features of nb_path with examples.
1. File and Directory Operations
from nb_path import NbPath
# Ensure parent directory exists, then create an empty file
p = NbPath("data/reports/2024/sales.csv").ensure_parent().touch()
# Copy the file
p_copy = p.copy_to("data/reports/2024/sales_backup.csv")
# Move the file
p_moved = p_copy.move_to("data/archive/sales_2024.csv")
# Delete the file
p_moved.delete()
# Create a directory and then empty it
report_dir = NbPath("data/reports").empty()
# Recursively delete the entire directory tree
report_dir.delete()
2. Text and Data I/O
nb_path inherits read_text/write_text and read_bytes/write_bytes from pathlib and defaults to utf-8 encoding for text operations.
p = NbPath("config.txt")
# Write text
p.write_text("setting=enabled")
# Read text
content = p.read_text()
print(content) # "setting=enabled"
3. Search and Discovery
Recursively Find Files/Directories
src_dir = NbPath("./my_project")
# Find all Python files
py_files = src_dir.rglob_files("*.py")
# Find all directories named 'tests'
test_dirs = src_dir.rglob_dirs("tests")
grep: Search for Content in Files
This is one of nb_path's "killer features".
import sys
project_dir = NbPath("./my_project")
# 1. Search for the string "import requests" in all .py files
for result in project_dir.grep("import requests", file_pattern="*.py", is_regex=False):
print(f"{result.path.name}:{result.line_number}: {result.line_content.strip()}")
# 2. Use a regular expression to find all Flask routes
for result in project_dir.grep(r"@app\.route\(['\"](.*?)['\"]\)", file_pattern="*.py"):
print(f"Found route: {result.match.group(1)}")
# 3. Search with 2 lines of context before and after
for result in project_dir.grep("important_logic", context=2, file_pattern="*.py"):
print("-" * 20)
for num, line_text in result.context_lines:
prefix = ">>" if num == result.line_number else " "
sys.stdout.write(f"{prefix} {num:4d}: {line_text.rstrip()}\n")
4. Project and Path Navigation
# Automatically find the root of the Git repository containing the current file
git_root = NbPath(__file__).find_git_root()
# Find the project root based on marker files (e.g., 'pyproject.toml')
project_root = NbPath().find_project_root()
# Dynamically get the caller's file path or directory path
current_file = NbPath.self_py_file()
current_dir = NbPath.self_py_dir()
# Expand environment variables and user directories
# NbPath('$HOME/.config/my_app').expand() -> /home/user/.config/my_app
# NbPath('~/.bashrc').expand() -> /home/user/.bashrc
config_path = NbPath("$HOME/.config").expand()
5. Compression and Decompression
assets_dir = NbPath("./assets")
# Compress the entire directory into a ZIP file
zip_file = assets_dir.zip_to("assets_archive.zip", overwrite=True)
# Extract the ZIP file to a specified directory
unzipped_dir = zip_file.unzip_to("./unzipped_assets")
6. Network and Synchronization
Download a File from a URL
# Download an image and display a progress bar
image_path = NbPath("python_logo.png").download_from_url(
"https://www.python.org/static/community_logos/python-logo-master-v3-TM.png",
overwrite=True
)
print(f"Image downloaded to: {image_path}, Size: {image_path.size_human()}")
sync_to: Intelligent Directory Synchronization
This method only copies new or modified files, making it highly efficient.
source_dir = NbPath("./src")
deploy_dir = NbPath("./deploy")
# Synchronize the source directory to the deployment directory
# delete_extraneous=True will delete extra files in the destination (mirroring)
source_dir.sync_to(deploy_dir, delete_extraneous=True, ignore_patterns=['*.pyc', '__pycache__'])
# Perform a dry run to see what would change without actually modifying any files
print("\n--- Performing a dry run ---")
source_dir.sync_to(deploy_dir, delete_extraneous=True, dry_run=True)
7. Temporary Files and Directories
nb_path provides more user-friendly context managers than the standard library, and they return NbPath objects.
# Create a temporary configuration file
with NbPath.tempfile(suffix=".txt", prefix="config_") as tmp_file:
print(f"Temporary file: {tmp_file}")
tmp_file.write_text("temporary setting")
# The file is automatically deleted when this block is exited
# Create a temporary plugin workspace
with NbPath.tempdir(prefix="plugin_") as tmp_dir:
print(f"Temporary directory: {tmp_dir}")
(tmp_dir / "plugin.py").write_text("print('hello from plugin')")
# The directory and all its contents are automatically deleted here
# For debugging, you can prevent cleanup
with NbPath.tempdir(cleanup=False) as persistent_tmp_dir:
persistent_tmp_dir.joinpath("log.txt").write_text("some debug info")
print(f"This directory will NOT be deleted: {persistent_tmp_dir}")
assert persistent_tmp_dir.exists()
8. Dynamic Module Import (Advanced Feature)
This is one of the most unique features of nb_path, very useful for building plugin systems or dynamically loading scripts.
from nb_path import NbPathPyImporter
# Import any .py file as a module
plugin_path = NbPathPyImporter("./plugins/my_plugin.py")
my_plugin_module = plugin_path.import_as_module()
# Call a function from the plugin
my_plugin_module.run()
# Automatically import all .py files in a directory
plugins_dir = NbPathPyImporter("./plugins")
plugins_dir.auto_import_pyfiles_in_dir()
9. Utilities
p = NbPath("my_large_file.dat")
p.write_bytes(b"0" * 5 * 1024 * 1024) # Write 5MB of data
# Get file size in bytes
print(p.size()) # 5242880
# Get human-readable file size
print(p.size_human()) # "5.0 MB"
# Calculate file hash
print(p.hash()) # 'f3a3535...' (sha256)
print(p.hash('md5')) # 'a74f6...' (md5)
Contributing
Contributions of any kind are welcome! If you have good ideas, feature suggestions, or have found a bug, please feel free to submit an Issue or Pull Request.
License
This project is open-sourced under the MIT License.
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 nb_path-2.5.tar.gz.
File metadata
- Download URL: nb_path-2.5.tar.gz
- Upload date:
- Size: 25.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e892d7b3760249e4afbaad4e86fa80b23711677e8db2d5dacbfeda46ea5d6a5
|
|
| MD5 |
b5139df7ab226314905453e5ae1fe43a
|
|
| BLAKE2b-256 |
d8cffe77c35a7ff8994011a9fba17931527b28763c0407c8df99d00eb28e92df
|
File details
Details for the file nb_path-2.5-py3-none-any.whl.
File metadata
- Download URL: nb_path-2.5-py3-none-any.whl
- Upload date:
- Size: 17.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7270bc77b22331e9ae4f5c8741f366ca7d23030bb14206cff4e1adc07a10412
|
|
| MD5 |
ac3a2799412d112ab53611ae9feeeee2
|
|
| BLAKE2b-256 |
43b30c0879cad7fedb1d68dd94ec17488dc2f8278ae8ebdec373e3f71d1ba3b2
|