A Python library for hierarchical file system operations with context management. Provides both standalone operations classes and context managers for files, directories, and archives with path resolution and rich console output.
- οΏ½ File Operations: Read, write, append, and manipulate files with context management
- π Directory Operations: Create, navigate, copy, and manage directories hierarchically
- π¦ Archive Support: Create, extract, and manipulate ZIP and TAR archives
- π Hierarchical Context: Automatic path resolution based on context stack
- β¨ Rich Output: Beautiful console output using Rich library
- π Method Chaining: Fluent API for chaining operations
- π Type Safety: Full type hints for better development experience
- π― Dual Interface: Both operations classes and context managers
- π§ͺ Dry Run Mode: Test operations without making changes
- π Global Functions: Optional global function injection for script-like usage
pip install hands-scaphoidfrom hands_scaphoid import FileContext, File
# Using context manager for hierarchical operations
with DirectoryContext('~') as home:
with DirectoryContext('projects/myproject') as project:
# Context-aware file operations
with FileContext('config.txt') as config:
config.write_content('debug=true\nversion=1.0')
config.add_heading('Settings')
# Read file with automatic path resolution
with FileContext('README.md') as readme:
content = readme.read_content()
print(content)
# Using operations class directly
File.write_content('path/to/file.txt', 'Hello, World!')
content = File.read_content('path/to/file.txt')from hands_scaphoid import DirectoryContext, Directory
# Context manager with hierarchical navigation
with DirectoryContext('~') as home:
with DirectoryContext('projects') as projects:
# All operations are relative to current context
projects.create_directory('newproject')
with DirectoryContext('newproject') as project:
# Nested context - operations are relative to projects/newproject
project.create_file('main.py', '#!/usr/bin/env python3\nprint("Hello, World!")')
files = project.list_contents()
print(f"Project files: {files}")
# Direct operations without context
Directory.create_directory('path/to/new/dir')
contents = Directory.list_contents('path/to/dir')from hands_scaphoid import ArchiveContext, Archive
# Context manager for archive operations
with DirectoryContext('~/projects') as projects:
# Create a ZIP archive
with ArchiveContext(source='myproject', target='backup.zip') as archive:
archive.add_file('README.md')
archive.add_directory('src')
# List archive contents
contents = archive.list_contents()
print(f"Archive contains: {contents}")
# Extract archive
with ArchiveContext(target='backup.zip') as archive:
archive.extract_all('restored_project')
# Direct archive operations
Archive.create_zip_archive('backup.zip', 'source_directory')
Archive.extract_archive('backup.zip', 'extracted_files')from hands_scaphoid import DirectoryContext
# Use global functions for script-like experience
with DirectoryContext('~/projects', enable_globals=True):
# Functions are available globally within the context
create_directory('newproject')
change_directory('newproject')
# Create files with content
create_file('setup.py', '''
from setuptools import setup, find_packages
setup(
name="myproject",
version="0.1.0",
packages=find_packages(),
)
''')
# Create project structure
create_directory('src/myproject')
create_file('src/myproject/__init__.py', '# My Project Package')
create_file('README.md', '# My Project\n\nA sample project.')
# List project structure
files = list_contents('.')
print(f"Project structure: {files}")from hands_scaphoid import DirectoryContext, ArchiveContext
# Create project backups with compression
with DirectoryContext('~/projects') as projects:
# Create multiple archive formats
with ArchiveContext(source='myproject', target='backup.tar.gz', archive_type='tar.gz') as archive:
# Archive automatically includes the entire directory
info = archive.get_archive_info()
print(f"Compression ratio: {info['compression_ratio']:.2f}")
# Selective archiving
with ArchiveContext(target='important_files.zip') as archive:
archive.add_file('myproject/README.md')
archive.add_file('myproject/setup.py')
archive.add_directory('myproject/src')Hands Scaphoid follows a clean separation of concerns:
File: Static methods for file I/O operationsDirectory: Static methods for directory operationsArchive: Static methods for archive operations
FileContext: Context manager that delegates to File operationsDirectoryContext: Context manager that delegates to Directory operationsArchiveContext: Context manager that delegates to Archive operations
This design allows you to use either approach:
- Direct operations:
File.read_content('path')for simple tasks - Context managers:
with FileContext('path') as f: f.read_content()for hierarchical operations
- Project Setup: Create consistent project structures with files and directories
- File Processing: Read, process, and write files with automatic path resolution
- Backup Systems: Create and manage archive files with compression
- Build Tools: Automate file operations in build processes
- Data Processing: Handle file operations in data pipelines
- Configuration Management: Manage configuration files across different environments
For comprehensive documentation, visit: https://42sol-eu.github.io/hands_scaphoid
- Hierarchical Contexts: Context managers maintain a stack of current directories
- Path Resolution: All paths are resolved relative to the current context
- Method Chaining: Most operations return
selffor fluent interfaces - Rich Output: Operations provide colored console feedback
- Dry Run Mode: Test operations without making file system changes
#!/usr/bin/env python3
"""
Project generator using Hands/Scaphoid
"""
from hands_scaphoid import DirectoryContext, FileContext
def create_python_project(project_name: str, base_dir: str = "~/projects"):
"""Create a new Python project structure."""
with DirectoryContext(base_dir) as projects:
with DirectoryContext(project_name, create=True) as project:
# Create project structure
project.create_directory('src')
project.create_directory('tests')
project.create_directory('docs')
# Create setup files
with FileContext('pyproject.toml') as pyproject:
pyproject.write_content(f'''[build-system]
requires = ["setuptools>=45", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "{project_name}"
version = "0.1.0"
description = "A new Python project"
authors = [{{name = "Your Name", email = "[email protected]"}}]
''')
with FileContext('README.md') as readme:
readme.write_content(f'# {project_name.title()}\n\nA new Python project.')
# Create source package
with DirectoryContext('src') as src:
with DirectoryContext(project_name, create=True) as pkg:
with FileContext('__init__.py') as init:
init.write_content(f'"""The {project_name} package."""\n__version__ = "0.1.0"')
with FileContext('main.py') as main:
main.write_content('''#!/usr/bin/env python3
"""Main module."""
def main():
"""Main function."""
print("Hello from {project_name}!")
if __name__ == "__main__":
main()
''')
# Create test file
with DirectoryContext('tests') as tests:
with FileContext('test_main.py') as test:
test.write_content(f'''"""Tests for {project_name}."""
import pytest
from {project_name} import main
def test_main():
"""Test the main function."""
# Test implementation here
pass
''')
print(f"β
Created Python project: {project_name}")
# Create backup
with ArchiveContext(source='.', target=f'{project_name}_backup.zip') as backup:
print(f"β
Created backup: {project_name}_backup.zip")
if __name__ == "__main__":
create_python_project("my_awesome_project")- Python 3.11+
- Rich library for console output
- pathlib for path operations
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
git clone https://github.com/42sol-eu/hands_scaphoid.git
cd hands_scaphoid
pip install -e ".[dev]"pytestmkdocs serveThis project is licensed under the MIT License - see the LICENSE file for details.
Andreas HΓ€berle - 42sol-eu
If you find this project helpful, please consider giving it a star on GitHub! β
See CHANGELOG.md for a list of changes and version history.
- https://pypi.org/project/rich-click/
- https://docs.github.com/en/copilot/get-started/best-practices
- https://code.visualstudio.com/docs/copilot/customization/custom-instructions
- enable
github.copilot.chat.codeGeneration.useInstructionFiles - define
chat.instructionsFilesLocationsto include the paths to.gitlab/instructions/instruction files - enable
chat.useAgentsMdFile-->AGENTS.mdfile for agent instructions
- enable
"github.copilot.chat.pullRequestDescriptionGeneration.instructions": [
{ "text": "Always include a list of key changes." }
],
"github.copilot.chat.reviewSelection.instructions": [
{ "file": "guidance/backend-review-guidelines.md" },
{ "file": "guidance/frontend-review-guidelines.md" }
]