or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdarguments-parameters.mdconfiguration.mdcore-app.mdexceptions.mdindex.mdtypes-validation.md

exceptions.mddocs/

0

# Exception Handling

1

2

Comprehensive exception hierarchy for precise error handling and debugging in CLI applications.

3

4

## Capabilities

5

6

### Base Exception

7

8

Root exception class for all Cyclopts errors.

9

10

```python { .api }

11

class CycloptsError(Exception):

12

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

13

14

def __init__(self, message: str = ""):

15

"""

16

Create a Cyclopts exception.

17

18

Parameters

19

----------

20

message

21

Error message

22

"""

23

```

24

25

### Argument and Parameter Errors

26

27

Exceptions related to argument parsing and validation.

28

29

```python { .api }

30

class ArgumentOrderError(CycloptsError):

31

"""Error when positional arguments are in wrong order."""

32

33

class MissingArgumentError(CycloptsError):

34

"""Error when required argument is missing."""

35

36

class MixedArgumentError(CycloptsError):

37

"""Error when incompatible argument types are mixed."""

38

39

class RepeatArgumentError(CycloptsError):

40

"""Error when an argument is repeated inappropriately."""

41

42

class UnknownOptionError(CycloptsError):

43

"""Error when an unknown option is provided."""

44

45

class UnusedCliTokensError(CycloptsError):

46

"""Error when CLI tokens are not consumed during parsing."""

47

```

48

49

### Type Conversion Errors

50

51

Exceptions related to type coercion and conversion.

52

53

```python { .api }

54

class CoercionError(CycloptsError):

55

"""Error when type coercion fails."""

56

57

def __init__(

58

self,

59

message: str = "",

60

*,

61

type_: type | None = None,

62

value: Any = None,

63

tokens: list[Token] | None = None

64

):

65

"""

66

Create a coercion error.

67

68

Parameters

69

----------

70

message

71

Error message

72

type_

73

Target type that failed conversion

74

value

75

Value that failed conversion

76

tokens

77

Tokens that caused the error

78

"""

79

```

80

81

### Validation Errors

82

83

Exceptions related to value validation.

84

85

```python { .api }

86

class ValidationError(CycloptsError):

87

"""Error during value validation."""

88

89

def __init__(

90

self,

91

message: str = "",

92

*,

93

value: Any = None,

94

validator: Callable | None = None

95

):

96

"""

97

Create a validation error.

98

99

Parameters

100

----------

101

message

102

Error message

103

value

104

Value that failed validation

105

validator

106

Validator that rejected the value

107

"""

108

```

109

110

### Command and Option Errors

111

112

Exceptions related to command configuration and option handling.

113

114

```python { .api }

115

class CommandCollisionError(CycloptsError):

116

"""Error when command names collide."""

117

118

class InvalidCommandError(CycloptsError):

119

"""Error when a command is invalid or malformed."""

120

121

class CombinedShortOptionError(CycloptsError):

122

"""Error when combined short options are invalid."""

123

```

124

125

### Documentation Errors

126

127

Exceptions related to docstring parsing and help generation.

128

129

```python { .api }

130

class DocstringError(CycloptsError):

131

"""Error parsing function docstrings."""

132

133

def __init__(

134

self,

135

message: str = "",

136

*,

137

func: Callable | None = None,

138

docstring: str | None = None

139

):

140

"""

141

Create a docstring error.

142

143

Parameters

144

----------

145

message

146

Error message

147

func

148

Function with problematic docstring

149

docstring

150

The problematic docstring content

151

"""

152

```

153

154

### Editor Errors

155

156

Exceptions related to interactive text editing.

157

158

```python { .api }

159

class EditorError(CycloptsError):

160

"""Base error for editor operations."""

161

162

class EditorNotFoundError(EditorError):

163

"""Error when text editor is not found."""

164

165

def __init__(self, editor: str | None = None):

166

"""

167

Create editor not found error.

168

169

Parameters

170

----------

171

editor

172

Editor command that was not found

173

"""

174

175

class EditorDidNotSaveError(EditorError):

176

"""Error when user did not save in editor."""

177

178

class EditorDidNotChangeError(EditorError):

179

"""Error when user did not change content in editor."""

180

```

181

182

## Usage Examples

183

184

### Handling Specific Exceptions

185

186

```python

187

from cyclopts import App, run

188

from cyclopts import ValidationError, CoercionError, MissingArgumentError

189

190

app = App()

191

192

@app.command

193

def process_data(input_file: str, threshold: float):

194

"""Process data with error handling."""

195

print(f"Processing {input_file} with threshold {threshold}")

196

197

def main():

198

try:

199

app()

200

except ValidationError as e:

201

print(f"Validation failed: {e}")

202

return 1

203

except CoercionError as e:

204

print(f"Type conversion failed: {e}")

205

return 1

206

except MissingArgumentError as e:

207

print(f"Required argument missing: {e}")

208

return 1

209

except Exception as e:

210

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

211

return 1

212

return 0

213

214

if __name__ == "__main__":

215

exit(main())

216

```

217

218

### Custom Exception Handling

219

220

```python

221

from cyclopts import App, CycloptsError

222

import logging

223

224

logging.basicConfig(level=logging.INFO)

225

logger = logging.getLogger(__name__)

226

227

app = App()

228

229

@app.command

230

def risky_operation(count: int):

231

"""Operation that might fail."""

232

if count < 0:

233

raise ValueError("Count must be positive")

234

print(f"Processing {count} items")

235

236

def main():

237

try:

238

app()

239

except CycloptsError as e:

240

# Handle all Cyclopts-specific errors

241

logger.error(f"CLI error: {e}")

242

return 1

243

except ValueError as e:

244

# Handle application-specific errors

245

logger.error(f"Application error: {e}")

246

return 2

247

except KeyboardInterrupt:

248

logger.info("Operation cancelled by user")

249

return 130

250

return 0

251

252

if __name__ == "__main__":

253

exit(main())

254

```

255

256

### Editor Error Handling

257

258

```python

259

from cyclopts import App, edit

260

from cyclopts import EditorError, EditorNotFoundError, EditorDidNotSaveError

261

262

app = App()

263

264

@app.command

265

def edit_message():

266

"""Edit message with comprehensive error handling."""

267

try:

268

content = edit(

269

text="Enter your message here...",

270

require_save=True,

271

require_change=True

272

)

273

print("Message created successfully:")

274

print(content)

275

276

except EditorNotFoundError as e:

277

print(f"No editor available: {e}")

278

print("Please set the EDITOR environment variable")

279

return 1

280

281

except EditorDidNotSaveError:

282

print("Editor session cancelled - no changes saved")

283

return 1

284

285

except EditorError as e:

286

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

287

return 1

288

289

return 0

290

```

291

292

### Validation Error with Context

293

294

```python

295

from cyclopts import App, Parameter

296

from cyclopts.validators import Number

297

from cyclopts import ValidationError

298

299

def validate_even_number(value: int) -> int:

300

"""Validate that number is even."""

301

if value % 2 != 0:

302

raise ValidationError(f"Value {value} must be even", value=value)

303

return value

304

305

app = App()

306

307

@app.command

308

def process_batch(

309

batch_size: int = Parameter(

310

validator=[Number(min=1, max=1000), validate_even_number],

311

help="Batch size (1-1000, must be even)"

312

)

313

):

314

"""Process data in batches."""

315

print(f"Processing with batch size {batch_size}")

316

317

def main():

318

try:

319

app()

320

except ValidationError as e:

321

print(f"Invalid input: {e}")

322

if hasattr(e, 'value') and e.value is not None:

323

print(f"Problematic value: {e.value}")

324

return 1

325

return 0

326

327

if __name__ == "__main__":

328

exit(main())

329

```

330

331

### Comprehensive Error Handler

332

333

```python

334

from cyclopts import App, CycloptsError

335

from cyclopts import (

336

ValidationError, CoercionError, MissingArgumentError,

337

CommandCollisionError, DocstringError

338

)

339

import sys

340

341

def handle_cyclopts_error(error: CycloptsError) -> int:

342

"""Handle Cyclopts errors with appropriate messages and exit codes."""

343

344

if isinstance(error, ValidationError):

345

print(f"❌ Validation Error: {error}", file=sys.stderr)

346

return 2

347

348

elif isinstance(error, CoercionError):

349

print(f"❌ Type Error: {error}", file=sys.stderr)

350

return 3

351

352

elif isinstance(error, MissingArgumentError):

353

print(f"❌ Missing Argument: {error}", file=sys.stderr)

354

return 4

355

356

elif isinstance(error, CommandCollisionError):

357

print(f"❌ Configuration Error: {error}", file=sys.stderr)

358

return 5

359

360

elif isinstance(error, DocstringError):

361

print(f"❌ Documentation Error: {error}", file=sys.stderr)

362

return 6

363

364

else:

365

print(f"❌ CLI Error: {error}", file=sys.stderr)

366

return 1

367

368

app = App()

369

370

@app.command

371

def example(value: int):

372

"""Example command."""

373

print(f"Value: {value}")

374

375

def main():

376

try:

377

app()

378

return 0

379

except CycloptsError as e:

380

return handle_cyclopts_error(e)

381

except KeyboardInterrupt:

382

print("\n⚠️ Operation cancelled", file=sys.stderr)

383

return 130

384

except Exception as e:

385

print(f"💥 Unexpected error: {e}", file=sys.stderr)

386

return 1

387

388

if __name__ == "__main__":

389

exit(main())

390

```