or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mdhooks-extensions.mdindex.mdmain-api.mdrepository-handling.mdtemplate-processing.mduser-interaction.mdutilities-exceptions.md

utilities-exceptions.mddocs/

0

# Utilities and Exceptions

1

2

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

3

4

## Capabilities

5

6

### File System Utilities

7

8

File and directory management functions.

9

10

```python { .api }

11

def rmtree(path):

12

"""

13

Remove directory and contents like rm -rf.

14

15

Parameters:

16

- path: str - Directory path to remove

17

"""

18

19

def force_delete(func, path, exc_info):

20

"""

21

Error handler for shutil.rmtree equivalent to rm -rf.

22

23

Parameters:

24

- func: callable - Function that failed

25

- path: str - Path that caused the error

26

- exc_info: tuple - Exception information

27

"""

28

29

def make_sure_path_exists(path):

30

"""

31

Ensure directory exists.

32

33

Parameters:

34

- path: str - Directory path to create if needed

35

"""

36

37

def make_executable(script_path):

38

"""

39

Make script executable.

40

41

Parameters:

42

- script_path: str - Path to script file

43

"""

44

```

45

46

### Context Management

47

48

Utilities for working directory and environment management.

49

50

```python { .api }

51

def work_in(dirname=None):

52

"""

53

Context manager for changing working directory.

54

55

Parameters:

56

- dirname: str, optional - Directory to change to

57

58

Returns:

59

ContextManager - Context manager for directory change

60

"""

61

62

def create_tmp_repo_dir(repo_dir):

63

"""

64

Create temporary directory with repo copy.

65

66

Parameters:

67

- repo_dir: str - Source repository directory

68

69

Returns:

70

str - Path to temporary directory copy

71

"""

72

73

def create_env_with_context(context):

74

"""

75

Create Jinja2 environment with context.

76

77

Parameters:

78

- context: dict - Template context

79

80

Returns:

81

Environment - Configured Jinja2 environment

82

"""

83

```

84

85

### Template Utilities

86

87

Utilities for template processing and Jinja2 integration.

88

89

```python { .api }

90

def simple_filter(filter_function):

91

"""

92

Decorator to wrap function in Jinja2 extension.

93

94

Parameters:

95

- filter_function: callable - Function to wrap as Jinja2 filter

96

97

Returns:

98

callable - Decorated function

99

"""

100

```

101

102

### Logging Configuration

103

104

Logging setup and configuration for cookiecutter operations.

105

106

```python { .api }

107

def configure_logger(stream_level='DEBUG', debug_file=None):

108

"""

109

Configure logging for cookiecutter.

110

111

Parameters:

112

- stream_level: str - Logging level for console output

113

- debug_file: str, optional - File path for debug logging

114

"""

115

```

116

117

### Replay System

118

119

Session replay functionality for reusing previous configurations.

120

121

```python { .api }

122

def get_file_name(replay_dir, template_name):

123

"""

124

Get replay file name.

125

126

Parameters:

127

- replay_dir: str - Directory containing replay files

128

- template_name: str - Name of template

129

130

Returns:

131

str - Full path to replay file

132

"""

133

134

def dump(replay_dir, template_name, context):

135

"""

136

Write context data to replay file.

137

138

Parameters:

139

- replay_dir: str - Directory to store replay file

140

- template_name: str - Name of template

141

- context: dict - Context data to save

142

"""

143

144

def load(replay_dir, template_name):

145

"""

146

Read context data from replay file.

147

148

Parameters:

149

- replay_dir: str - Directory containing replay files

150

- template_name: str - Name of template

151

152

Returns:

153

dict - Loaded context data

154

"""

155

```

156

157

## Logging Constants

158

159

```python { .api }

160

LOG_LEVELS: dict # Dictionary mapping level names to logging constants

161

# Contains: {'DEBUG': logging.DEBUG, 'INFO': logging.INFO, 'WARNING': logging.WARNING, 'ERROR': logging.ERROR}

162

163

LOG_FORMATS: dict # Dictionary of log format strings

164

# Contains format strings for different logging levels

165

```

166

167

## Exception Hierarchy

168

169

Comprehensive exception classes for error handling throughout cookiecutter.

170

171

### Base Exception

172

173

```python { .api }

174

class CookiecutterException(Exception):

175

"""Base exception class for all cookiecutter errors."""

176

```

177

178

### Configuration Exceptions

179

180

```python { .api }

181

class ConfigDoesNotExistException(CookiecutterException):

182

"""Missing config file."""

183

184

class InvalidConfiguration(CookiecutterException):

185

"""Invalid configuration file."""

186

```

187

188

### Template Exceptions

189

190

```python { .api }

191

class NonTemplatedInputDirException(CookiecutterException):

192

"""Input directory is not templated."""

193

194

class UnknownTemplateDirException(CookiecutterException):

195

"""Ambiguous project template directory."""

196

197

class MissingProjectDir(CookiecutterException):

198

"""Missing generated project directory."""

199

200

class ContextDecodingException(CookiecutterException):

201

"""Failed JSON context decoding."""

202

203

class UndefinedVariableInTemplate(CookiecutterException):

204

"""Template uses undefined variables."""

205

```

206

207

### Repository Exceptions

208

209

```python { .api }

210

class UnknownRepoType(CookiecutterException):

211

"""Unknown repository type."""

212

213

class RepositoryNotFound(CookiecutterException):

214

"""Repository doesn't exist."""

215

216

class RepositoryCloneFailed(CookiecutterException):

217

"""Repository can't be cloned."""

218

219

class InvalidZipRepository(CookiecutterException):

220

"""Invalid zip repository."""

221

```

222

223

### Operational Exceptions

224

225

```python { .api }

226

class VCSNotInstalled(CookiecutterException):

227

"""Version control system not available."""

228

229

class OutputDirExistsException(CookiecutterException):

230

"""Output directory already exists."""

231

232

class InvalidModeException(CookiecutterException):

233

"""Incompatible modes (no_input + replay)."""

234

235

class FailedHookException(CookiecutterException):

236

"""Hook script failures."""

237

238

class UnknownExtension(CookiecutterException):

239

"""Un-importable Jinja2 extension."""

240

```

241

242

## Usage Examples

243

244

### File System Operations

245

246

```python

247

from cookiecutter.utils import rmtree, make_sure_path_exists, work_in

248

import os

249

250

# Ensure directory exists

251

make_sure_path_exists('./my-project/src')

252

253

# Work in different directory

254

with work_in('./my-project'):

255

# Operations here happen in ./my-project

256

print(os.getcwd()) # Shows full path to ./my-project

257

# Back to original directory

258

259

# Clean up directory

260

if os.path.exists('./temp-dir'):

261

rmtree('./temp-dir')

262

```

263

264

### Logging Configuration

265

266

```python

267

from cookiecutter.log import configure_logger, LOG_LEVELS

268

269

# Basic logging setup

270

configure_logger(stream_level='INFO')

271

272

# Debug logging with file output

273

configure_logger(

274

stream_level='DEBUG',

275

debug_file='./cookiecutter-debug.log'

276

)

277

278

# Available log levels

279

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

280

```

281

282

### Replay System

283

284

```python

285

from cookiecutter.replay import dump, load, get_file_name

286

287

# Save context for replay

288

context = {

289

'cookiecutter': {

290

'project_name': 'my-awesome-project',

291

'author': 'Jane Developer',

292

'version': '1.0.0'

293

}

294

}

295

296

dump(

297

replay_dir='~/.cookiecutter_replay',

298

template_name='python-package',

299

context=context

300

)

301

302

# Load previous context

303

loaded_context = load(

304

replay_dir='~/.cookiecutter_replay',

305

template_name='python-package'

306

)

307

308

print("Loaded context:", loaded_context)

309

```

310

311

### Error Handling

312

313

```python

314

from cookiecutter.main import cookiecutter

315

from cookiecutter.exceptions import (

316

CookiecutterException,

317

OutputDirExistsException,

318

RepositoryNotFound,

319

RepositoryCloneFailed,

320

ContextDecodingException,

321

FailedHookException

322

)

323

324

def safe_cookiecutter(template, **kwargs):

325

"""Wrapper for cookiecutter with comprehensive error handling."""

326

try:

327

return cookiecutter(template, **kwargs)

328

329

except OutputDirExistsException as e:

330

print(f"Output directory exists: {e}")

331

# Optionally retry with overwrite

332

return cookiecutter(template, overwrite_if_exists=True, **kwargs)

333

334

except RepositoryNotFound as e:

335

print(f"Template repository not found: {e}")

336

return None

337

338

except RepositoryCloneFailed as e:

339

print(f"Failed to clone repository: {e}")

340

return None

341

342

except ContextDecodingException as e:

343

print(f"Invalid cookiecutter.json format: {e}")

344

return None

345

346

except FailedHookException as e:

347

print(f"Hook execution failed: {e}")

348

return None

349

350

except CookiecutterException as e:

351

print(f"Cookiecutter error: {e}")

352

return None

353

354

except Exception as e:

355

print(f"Unexpected error: {e}")

356

return None

357

358

# Usage

359

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

360

```

361

362

### Advanced Utilities

363

364

```python

365

from cookiecutter.utils import (

366

create_tmp_repo_dir,

367

create_env_with_context,

368

simple_filter,

369

make_executable

370

)

371

import tempfile

372

import os

373

374

# Create temporary copy of repository

375

temp_dir = create_tmp_repo_dir('./my-template')

376

print(f"Temporary copy created at: {temp_dir}")

377

378

# Create Jinja2 environment with context

379

context = {'project_name': 'test-project', 'version': '1.0'}

380

env = create_env_with_context(context)

381

382

# Create custom Jinja2 filter

383

@simple_filter

384

def uppercase_filter(text):

385

return text.upper()

386

387

# Apply filter in template

388

template = env.from_string('{{ project_name | uppercase }}')

389

result = template.render(project_name='hello world')

390

# Returns: 'HELLO WORLD'

391

392

# Make script executable

393

script_path = './setup-script.sh'

394

if os.path.exists(script_path):

395

make_executable(script_path)

396

```

397

398

### Context Manager Usage

399

400

```python

401

from cookiecutter.utils import work_in

402

import os

403

import subprocess

404

405

# Complex operation in different directory

406

original_dir = os.getcwd()

407

print(f"Starting in: {original_dir}")

408

409

with work_in('./my-project'):

410

print(f"Working in: {os.getcwd()}")

411

412

# Run commands in the project directory

413

subprocess.run(['pip', 'install', '-e', '.'], check=True)

414

subprocess.run(['python', '-m', 'pytest'], check=True)

415

416

# Create subdirectory

417

os.makedirs('build', exist_ok=True)

418

419

print(f"Back to: {os.getcwd()}") # Back to original directory

420

```

421

422

### Exception Information

423

424

```python

425

from cookiecutter.exceptions import UndefinedVariableInTemplate

426

427

# Exception with additional context

428

try:

429

# Some template rendering operation

430

pass

431

except UndefinedVariableInTemplate as e:

432

print(f"Undefined variable error: {e.message}")

433

print(f"Error details: {e.error}")

434

print(f"Context: {e.context}")

435

```

436

437

### Replay File Management

438

439

```python

440

from cookiecutter.replay import get_file_name, load

441

import os

442

import json

443

444

# Check if replay file exists

445

replay_dir = '~/.cookiecutter_replay'

446

template_name = 'my-template'

447

448

replay_file = get_file_name(replay_dir, template_name)

449

if os.path.exists(replay_file):

450

# Load and examine replay data

451

replay_data = load(replay_dir, template_name)

452

print(f"Previous configuration:")

453

print(json.dumps(replay_data, indent=2))

454

else:

455

print("No replay file found for this template")

456

```