A library for rendering project templates from Git repositories with Jinja2 templating and interactive questionnaires.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive exception hierarchy for handling template processing errors, configuration issues, user interaction problems, and system-level failures in copier operations.
Foundation exception classes for all copier errors and warnings.
class CopierError(Exception):
"""Base class for all Copier errors."""
class CopierWarning(UserWarning):
"""Base class for all Copier warnings."""Exceptions that indicate user-level issues requiring user action or input.
class UserMessageError(CopierError):
"""Exit program with user message."""
class UnsupportedVersionError(CopierError):
"""Copier version doesn't support this template."""
class InteractiveSessionError(CopierError):
"""Interactive session required but not available."""Usage examples:
from copier import run_copy
from copier.errors import UserMessageError, UnsupportedVersionError
try:
worker = run_copy("template/", "project/")
except UserMessageError as e:
print(f"User error: {e}")
# Handle user-facing error gracefully
except UnsupportedVersionError as e:
print(f"Version compatibility issue: {e}")
# Suggest upgrading copier or using different template versionExceptions related to template configuration files and settings.
class ConfigFileError(CopierError):
"""Base class for config file problems."""
class InvalidConfigFileError(ConfigFileError):
"""Invalid config file format or content."""
class MultipleConfigFilesError(ConfigFileError):
"""Multiple config files found in template."""Usage examples:
from copier import run_copy
from copier.errors import ConfigFileError, InvalidConfigFileError
try:
worker = run_copy("template/", "project/")
except InvalidConfigFileError as e:
print(f"Template configuration error: {e}")
# Check copier.yml or copier.yaml in template
except MultipleConfigFilesError as e:
print(f"Conflicting config files: {e}")
# Remove duplicate configuration filesExceptions for file system path validation and access issues.
class PathError(CopierError):
"""Base class for path-related errors."""
class PathNotAbsoluteError(PathError):
"""Path should be absolute but is relative."""
class PathNotRelativeError(PathError):
"""Path should be relative but is absolute."""
class ForbiddenPathError(PathError):
"""Path is forbidden for security reasons."""Usage examples:
from copier import Worker
from copier.errors import PathError, ForbiddenPathError
try:
worker = Worker(
src_path="template/",
dst_path="../../../etc/passwd" # Dangerous path
)
worker.run_copy()
except ForbiddenPathError as e:
print(f"Security violation: {e}")
# Use safe destination path
except PathError as e:
print(f"Path issue: {e}")
# Validate and correct pathExceptions that occur during template processing and rendering.
class InvalidTypeError(CopierError):
"""Unsupported question type in template."""
class ExtensionNotFoundError(CopierError):
"""Template extensions couldn't be loaded."""
class UnsafeTemplateError(CopierError):
"""Template contains unsafe features without user consent."""
class YieldTagInFileError(CopierError):
"""Yield tag found in file content (not allowed)."""
class MultipleYieldTagsError(CopierError):
"""Multiple yield tags found in path name."""
class TaskError(CopierError):
"""Task execution failed during template processing."""
@classmethod
def from_process(cls, process: subprocess.CompletedProcess) -> TaskError:
"""Create TaskError from a failed subprocess."""Usage examples:
from copier import run_copy
from copier.errors import UnsafeTemplateError, TaskError
try:
worker = run_copy(
"suspicious-template/",
"project/",
unsafe=False # Reject unsafe templates
)
except UnsafeTemplateError as e:
print(f"Template safety issue: {e}")
# Review template or use unsafe=True if trusted
except TaskError as e:
print(f"Template task failed: {e}")
# Check template tasks configurationExceptions related to user input and interactive sessions.
class CopierAnswersInterrupt(CopierError):
"""Keyboard interrupt during questionnaire."""Usage examples:
from copier import run_copy
from copier.errors import CopierAnswersInterrupt
try:
worker = run_copy("template/", "project/")
except CopierAnswersInterrupt:
print("Operation cancelled by user")
# Clean up partial work if needed
except KeyboardInterrupt:
print("Process interrupted")
# Handle general interruptionWarning classes for non-fatal issues that don't stop processing.
class UnknownCopierVersionWarning(CopierWarning):
"""Cannot determine which Copier version was used."""
class OldTemplateWarning(CopierWarning):
"""Template was designed for an older Copier version."""
class DirtyLocalWarning(CopierWarning):
"""Uncommitted changes in local template directory."""
class ShallowCloneWarning(CopierWarning):
"""Template repository is a shallow clone."""
class MissingSettingsWarning(CopierWarning):
"""Settings file not found at expected location."""
class MissingFileWarning(CopierWarning):
"""Referenced file not found in template."""Usage examples:
import warnings
from copier import run_copy
from copier.errors import OldTemplateWarning, DirtyLocalWarning
# Configure warning handling
warnings.filterwarnings("always", category=OldTemplateWarning)
try:
with warnings.catch_warnings(record=True) as w:
worker = run_copy("old-template/", "project/")
for warning in w:
if issubclass(warning.category, DirtyLocalWarning):
print(f"Template has uncommitted changes: {warning.message}")
elif issubclass(warning.category, OldTemplateWarning):
print(f"Template compatibility: {warning.message}")
except Exception as e:
print(f"Processing failed: {e}")CopierError
├── UserMessageError
├── UnsupportedVersionError
├── ConfigFileError
│ ├── InvalidConfigFileError
│ └── MultipleConfigFilesError
├── PathError
│ ├── PathNotAbsoluteError
│ ├── PathNotRelativeError
│ └── ForbiddenPathError
├── InvalidTypeError
├── ExtensionNotFoundError
├── CopierAnswersInterrupt
├── UnsafeTemplateError
├── YieldTagInFileError
├── MultipleYieldTagsError
└── TaskError
CopierWarning
├── UnknownCopierVersionWarning
├── OldTemplateWarning
├── DirtyLocalWarning
├── ShallowCloneWarning
├── MissingSettingsWarning
├── MissingFileWarning
└── InteractiveSessionErrorfrom copier import run_copy
from copier.errors import CopierError, ConfigFileError, PathError
def safe_template_processing(template_path: str, output_path: str) -> bool:
"""Safely process template with comprehensive error handling."""
try:
worker = run_copy(template_path, output_path)
return True
except ConfigFileError as e:
print(f"Template configuration issue: {e}")
# Log for template author to fix
return False
except PathError as e:
print(f"Path validation failed: {e}")
# Sanitize and retry with safe paths
return False
except CopierError as e:
print(f"Copier processing error: {e}")
# General copier error handling
return False
except Exception as e:
print(f"Unexpected error: {e}")
# Handle unexpected system errors
return FalseInstall with Tessl CLI
npx tessl i tessl/pypi-copier