CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-cookiecutter

A command-line utility that creates projects from project templates, e.g. creating a Python package project from a Python package project template.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

utilities-exceptions.mddocs/

Utilities and Exceptions

Helper functions, logging configuration, replay functionality, and comprehensive exception hierarchy. This module provides supporting utilities and error handling for all cookiecutter operations.

Capabilities

File System Utilities

File and directory management functions.

def rmtree(path):
    """
    Remove directory and contents like rm -rf.
    
    Parameters:
    - path: str - Directory path to remove
    """

def force_delete(func, path, exc_info):
    """
    Error handler for shutil.rmtree equivalent to rm -rf.
    
    Parameters:
    - func: callable - Function that failed
    - path: str - Path that caused the error
    - exc_info: tuple - Exception information
    """

def make_sure_path_exists(path):
    """
    Ensure directory exists.
    
    Parameters:
    - path: str - Directory path to create if needed
    """

def make_executable(script_path):
    """
    Make script executable.
    
    Parameters:
    - script_path: str - Path to script file
    """

Context Management

Utilities for working directory and environment management.

def work_in(dirname=None):
    """
    Context manager for changing working directory.
    
    Parameters:
    - dirname: str, optional - Directory to change to
    
    Returns:
    ContextManager - Context manager for directory change
    """

def create_tmp_repo_dir(repo_dir):
    """
    Create temporary directory with repo copy.
    
    Parameters:
    - repo_dir: str - Source repository directory
    
    Returns:
    str - Path to temporary directory copy
    """

def create_env_with_context(context):
    """
    Create Jinja2 environment with context.
    
    Parameters:
    - context: dict - Template context
    
    Returns:
    Environment - Configured Jinja2 environment
    """

Template Utilities

Utilities for template processing and Jinja2 integration.

def simple_filter(filter_function):
    """
    Decorator to wrap function in Jinja2 extension.
    
    Parameters:
    - filter_function: callable - Function to wrap as Jinja2 filter
    
    Returns:
    callable - Decorated function
    """

Logging Configuration

Logging setup and configuration for cookiecutter operations.

def configure_logger(stream_level='DEBUG', debug_file=None):
    """
    Configure logging for cookiecutter.
    
    Parameters:
    - stream_level: str - Logging level for console output
    - debug_file: str, optional - File path for debug logging
    """

Replay System

Session replay functionality for reusing previous configurations.

def get_file_name(replay_dir, template_name):
    """
    Get replay file name.
    
    Parameters:
    - replay_dir: str - Directory containing replay files
    - template_name: str - Name of template
    
    Returns:
    str - Full path to replay file
    """

def dump(replay_dir, template_name, context):
    """
    Write context data to replay file.
    
    Parameters:
    - replay_dir: str - Directory to store replay file
    - template_name: str - Name of template
    - context: dict - Context data to save
    """

def load(replay_dir, template_name):
    """
    Read context data from replay file.
    
    Parameters:
    - replay_dir: str - Directory containing replay files
    - template_name: str - Name of template
    
    Returns:
    dict - Loaded context data
    """

Logging Constants

LOG_LEVELS: dict  # Dictionary mapping level names to logging constants
# Contains: {'DEBUG': logging.DEBUG, 'INFO': logging.INFO, 'WARNING': logging.WARNING, 'ERROR': logging.ERROR}

LOG_FORMATS: dict  # Dictionary of log format strings
# Contains format strings for different logging levels

Exception Hierarchy

Comprehensive exception classes for error handling throughout cookiecutter.

Base Exception

class CookiecutterException(Exception):
    """Base exception class for all cookiecutter errors."""

Configuration Exceptions

class ConfigDoesNotExistException(CookiecutterException):
    """Missing config file."""

class InvalidConfiguration(CookiecutterException):
    """Invalid configuration file."""

Template Exceptions

class NonTemplatedInputDirException(CookiecutterException):
    """Input directory is not templated."""

class UnknownTemplateDirException(CookiecutterException):
    """Ambiguous project template directory."""

class MissingProjectDir(CookiecutterException):
    """Missing generated project directory."""

class ContextDecodingException(CookiecutterException):
    """Failed JSON context decoding."""

class UndefinedVariableInTemplate(CookiecutterException):
    """Template uses undefined variables."""

Repository Exceptions

class UnknownRepoType(CookiecutterException):
    """Unknown repository type."""

class RepositoryNotFound(CookiecutterException):
    """Repository doesn't exist."""

class RepositoryCloneFailed(CookiecutterException):
    """Repository can't be cloned."""

class InvalidZipRepository(CookiecutterException):
    """Invalid zip repository."""

Operational Exceptions

class VCSNotInstalled(CookiecutterException):
    """Version control system not available."""

class OutputDirExistsException(CookiecutterException):
    """Output directory already exists."""

class InvalidModeException(CookiecutterException):
    """Incompatible modes (no_input + replay)."""

class FailedHookException(CookiecutterException):
    """Hook script failures."""

class UnknownExtension(CookiecutterException):
    """Un-importable Jinja2 extension."""

Usage Examples

File System Operations

from cookiecutter.utils import rmtree, make_sure_path_exists, work_in
import os

# Ensure directory exists
make_sure_path_exists('./my-project/src')

# Work in different directory
with work_in('./my-project'):
    # Operations here happen in ./my-project
    print(os.getcwd())  # Shows full path to ./my-project
# Back to original directory

# Clean up directory
if os.path.exists('./temp-dir'):
    rmtree('./temp-dir')

Logging Configuration

from cookiecutter.log import configure_logger, LOG_LEVELS

# Basic logging setup
configure_logger(stream_level='INFO')

# Debug logging with file output
configure_logger(
    stream_level='DEBUG',
    debug_file='./cookiecutter-debug.log'
)

# Available log levels
print("Available log levels:", list(LOG_LEVELS.keys()))

Replay System

from cookiecutter.replay import dump, load, get_file_name

# Save context for replay
context = {
    'cookiecutter': {
        'project_name': 'my-awesome-project',
        'author': 'Jane Developer',
        'version': '1.0.0'
    }
}

dump(
    replay_dir='~/.cookiecutter_replay',
    template_name='python-package',
    context=context
)

# Load previous context
loaded_context = load(
    replay_dir='~/.cookiecutter_replay',
    template_name='python-package'
)

print("Loaded context:", loaded_context)

Error Handling

from cookiecutter.main import cookiecutter
from cookiecutter.exceptions import (
    CookiecutterException,
    OutputDirExistsException,
    RepositoryNotFound,
    RepositoryCloneFailed,
    ContextDecodingException,
    FailedHookException
)

def safe_cookiecutter(template, **kwargs):
    """Wrapper for cookiecutter with comprehensive error handling."""
    try:
        return cookiecutter(template, **kwargs)
        
    except OutputDirExistsException as e:
        print(f"Output directory exists: {e}")
        # Optionally retry with overwrite
        return cookiecutter(template, overwrite_if_exists=True, **kwargs)
        
    except RepositoryNotFound as e:
        print(f"Template repository not found: {e}")
        return None
        
    except RepositoryCloneFailed as e:
        print(f"Failed to clone repository: {e}")
        return None
        
    except ContextDecodingException as e:
        print(f"Invalid cookiecutter.json format: {e}")
        return None
        
    except FailedHookException as e:
        print(f"Hook execution failed: {e}")
        return None
        
    except CookiecutterException as e:
        print(f"Cookiecutter error: {e}")
        return None
        
    except Exception as e:
        print(f"Unexpected error: {e}")
        return None

# Usage
result = safe_cookiecutter('gh:audreyfeldroy/cookiecutter-pypackage')

Advanced Utilities

from cookiecutter.utils import (
    create_tmp_repo_dir,
    create_env_with_context,
    simple_filter,
    make_executable
)
import tempfile
import os

# Create temporary copy of repository
temp_dir = create_tmp_repo_dir('./my-template')
print(f"Temporary copy created at: {temp_dir}")

# Create Jinja2 environment with context
context = {'project_name': 'test-project', 'version': '1.0'}
env = create_env_with_context(context)

# Create custom Jinja2 filter
@simple_filter
def uppercase_filter(text):
    return text.upper()

# Apply filter in template
template = env.from_string('{{ project_name | uppercase }}')
result = template.render(project_name='hello world')
# Returns: 'HELLO WORLD'

# Make script executable
script_path = './setup-script.sh'
if os.path.exists(script_path):
    make_executable(script_path)

Context Manager Usage

from cookiecutter.utils import work_in
import os
import subprocess

# Complex operation in different directory
original_dir = os.getcwd()
print(f"Starting in: {original_dir}")

with work_in('./my-project'):
    print(f"Working in: {os.getcwd()}")
    
    # Run commands in the project directory
    subprocess.run(['pip', 'install', '-e', '.'], check=True)
    subprocess.run(['python', '-m', 'pytest'], check=True)
    
    # Create subdirectory
    os.makedirs('build', exist_ok=True)
    
print(f"Back to: {os.getcwd()}")  # Back to original directory

Exception Information

from cookiecutter.exceptions import UndefinedVariableInTemplate

# Exception with additional context
try:
    # Some template rendering operation
    pass
except UndefinedVariableInTemplate as e:
    print(f"Undefined variable error: {e.message}")
    print(f"Error details: {e.error}")
    print(f"Context: {e.context}")

Replay File Management

from cookiecutter.replay import get_file_name, load
import os
import json

# Check if replay file exists
replay_dir = '~/.cookiecutter_replay'
template_name = 'my-template'

replay_file = get_file_name(replay_dir, template_name)
if os.path.exists(replay_file):
    # Load and examine replay data
    replay_data = load(replay_dir, template_name)
    print(f"Previous configuration:")
    print(json.dumps(replay_data, indent=2))
else:
    print("No replay file found for this template")

Install with Tessl CLI

npx tessl i tessl/pypi-cookiecutter

docs

configuration.md

hooks-extensions.md

index.md

main-api.md

repository-handling.md

template-processing.md

user-interaction.md

utilities-exceptions.md

tile.json