or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

autocomplete-paths.mdcore-classes.mdexecution-control.mdforms.mdindex.mdselection-prompts.mdtext-input.md

core-classes.mddocs/

0

# Core Classes and Configuration

1

2

Essential classes for building and customizing prompts, including choice configuration, styling, validation, conditional logic, and utility functions for enhanced prompt functionality.

3

4

## Capabilities

5

6

### Question Class

7

8

Core question class that serves as the foundation for all interactive prompts with execution methods and conditional logic.

9

10

```python { .api }

11

class Question:

12

application: Application[Any]

13

should_skip_question: bool

14

default: Any

15

16

def __init__(self, application: Application[Any]) -> None:

17

"""

18

Initialize question with prompt_toolkit application.

19

20

Args:

21

application: Configured prompt_toolkit Application instance

22

"""

23

24

def ask(self, patch_stdout: bool = False,

25

kbi_msg: str = DEFAULT_KBI_MESSAGE) -> Any:

26

"""

27

Execute question synchronously with error handling.

28

29

Args:

30

patch_stdout: Patch stdout to prevent interference

31

kbi_msg: Message displayed on keyboard interrupt

32

33

Returns:

34

User response value

35

36

Raises:

37

KeyboardInterrupt: User cancelled with appropriate message

38

"""

39

40

def unsafe_ask(self, patch_stdout: bool = False) -> Any:

41

"""

42

Execute question synchronously without error handling.

43

44

Args:

45

patch_stdout: Patch stdout to prevent interference

46

47

Returns:

48

User response value

49

"""

50

51

def ask_async(self, patch_stdout: bool = False,

52

kbi_msg: str = DEFAULT_KBI_MESSAGE) -> Any:

53

"""

54

Execute question asynchronously with error handling.

55

56

Args:

57

patch_stdout: Patch stdout to prevent interference

58

kbi_msg: Message displayed on keyboard interrupt

59

60

Returns:

61

User response value

62

63

Raises:

64

KeyboardInterrupt: User cancelled with appropriate message

65

"""

66

67

def unsafe_ask_async(self, patch_stdout: bool = False) -> Any:

68

"""

69

Execute question asynchronously without error handling.

70

71

Args:

72

patch_stdout: Patch stdout to prevent interference

73

74

Returns:

75

User response value

76

"""

77

78

def skip_if(self, condition: bool, default: Any = None) -> Question:

79

"""

80

Conditionally skip question execution.

81

82

Args:

83

condition: If True, skip question and return default

84

default: Value to return when question is skipped

85

86

Returns:

87

Self for method chaining

88

"""

89

```

90

91

### Choice Configuration

92

93

Advanced choice configuration for selection prompts with custom values, descriptions, shortcuts, and states.

94

95

```python { .api }

96

class Choice:

97

title: FormattedText

98

value: Optional[Any]

99

disabled: Optional[str]

100

checked: Optional[bool]

101

shortcut_key: Optional[Union[str, bool]]

102

description: Optional[str]

103

104

def __init__(self, title: FormattedText, value: Optional[Any] = None,

105

disabled: Optional[str] = None, checked: Optional[bool] = False,

106

shortcut_key: Optional[Union[str, bool]] = True,

107

description: Optional[str] = None) -> None:

108

"""

109

Configure a choice for selection prompts.

110

111

Args:

112

title: Display text for the choice (can be formatted text)

113

value: Return value when choice is selected (defaults to title)

114

disabled: Reason text if choice is disabled (None = enabled)

115

checked: Initially selected state for checkbox prompts

116

shortcut_key: Keyboard shortcut (True = auto-generate, str = custom, False = none)

117

description: Additional description text shown with choice

118

"""

119

120

@staticmethod

121

def build(c: Union[str, Choice, Dict]) -> Choice:

122

"""

123

Build Choice from string, existing Choice, or dictionary.

124

125

Args:

126

c: Choice specification as string, Choice instance, or dict

127

128

Returns:

129

Choice instance

130

"""

131

132

def get_shortcut_title(self) -> str:

133

"""

134

Get formatted shortcut display text.

135

136

Returns:

137

Formatted string showing shortcut key with title

138

"""

139

140

@property

141

def shortcut_key(self) -> Optional[str]:

142

"""Get the shortcut key for this choice."""

143

144

@property

145

def auto_shortcut(self) -> bool:

146

"""Check if shortcut is auto-generated."""

147

```

148

149

### Separator Class

150

151

Visual separators for organizing choice lists in selection prompts.

152

153

```python { .api }

154

class Separator(Choice):

155

default_separator: str = "-" * 15

156

line: str

157

158

def __init__(self, line: Optional[str] = None) -> None:

159

"""

160

Create a visual separator for choice lists.

161

162

Args:

163

line: Custom separator text (default: 15 dashes)

164

"""

165

```

166

167

### Form Classes

168

169

Form container and field definition classes for multi-question workflows.

170

171

```python { .api }

172

class FormField(NamedTuple):

173

key: str

174

question: Question

175

"""

176

Named tuple representing a question within a form.

177

178

Attributes:

179

key: Field identifier for result dictionary

180

question: Question instance to execute

181

"""

182

183

class Form:

184

form_fields: Sequence[FormField]

185

186

def __init__(self, *form_fields: FormField) -> None:

187

"""

188

Initialize form with FormField instances.

189

190

Args:

191

*form_fields: FormField instances defining the form structure

192

"""

193

194

def ask(self, patch_stdout: bool = False,

195

kbi_msg: str = DEFAULT_KBI_MESSAGE) -> Dict[str, Any]:

196

"""

197

Execute form synchronously with error handling.

198

199

Args:

200

patch_stdout: Patch stdout to prevent interference

201

kbi_msg: Message displayed on keyboard interrupt

202

203

Returns:

204

Dictionary mapping field keys to user responses

205

"""

206

207

def unsafe_ask(self, patch_stdout: bool = False) -> Dict[str, Any]:

208

"""Execute form synchronously without error handling."""

209

210

def ask_async(self, patch_stdout: bool = False,

211

kbi_msg: str = DEFAULT_KBI_MESSAGE) -> Dict[str, Any]:

212

"""Execute form asynchronously with error handling."""

213

214

def unsafe_ask_async(self, patch_stdout: bool = False) -> Dict[str, Any]:

215

"""Execute form asynchronously without error handling."""

216

```

217

218

## Utility Functions

219

220

### Formatted Text Output

221

222

Enhanced text output with styling support.

223

224

```python { .api }

225

def print(text: str, style: Optional[str] = None, **kwargs) -> None:

226

"""

227

Print formatted text with optional styling.

228

229

Args:

230

text: Text to print

231

style: Style specification for the text

232

**kwargs: Additional formatting arguments

233

"""

234

235

def press_any_key_to_continue(message: Optional[str] = None,

236

style: Optional[Style] = None,

237

**kwargs) -> Question:

238

"""

239

Create a prompt that waits for any key press.

240

241

Args:

242

message: Custom message to display (default: "Press any key to continue...")

243

style: Custom styling configuration

244

**kwargs: Additional prompt_toolkit arguments

245

246

Returns:

247

Question instance that waits for key press

248

"""

249

```

250

251

### Style and Validation Utilities

252

253

Helper functions for styling and validation configuration.

254

255

```python { .api }

256

def merge_styles_default(styles: List[Optional[Style]]) -> Style:

257

"""

258

Merge custom styles with default questionary styling.

259

260

Args:

261

styles: List of Style instances to merge

262

263

Returns:

264

Merged Style instance

265

"""

266

267

def build_validator(validate: Any) -> Optional[Validator]:

268

"""

269

Convert validation input to Validator instance.

270

271

Args:

272

validate: Validation function, Validator instance, or None

273

274

Returns:

275

Validator instance or None

276

"""

277

```

278

279

## Constants and Configuration

280

281

### UI Constants

282

283

```python { .api }

284

# Response constants

285

YES: str = "Yes"

286

NO: str = "No"

287

YES_OR_NO: str = "(Y/n)"

288

NO_OR_YES: str = "(y/N)"

289

290

# UI element constants

291

DEFAULT_SELECTED_POINTER: str = "»"

292

INDICATOR_SELECTED: str = "●"

293

INDICATOR_UNSELECTED: str = "○"

294

DEFAULT_QUESTION_PREFIX: str = "?"

295

296

# Message constants

297

DEFAULT_KBI_MESSAGE: str = "\nCancelled by user\n"

298

INVALID_INPUT: str = "Invalid input"

299

INSTRUCTION_MULTILINE: str = "Press ESC then ENTER to submit"

300

301

# Style constants

302

DEFAULT_STYLE: Style # Default prompt styling configuration

303

```

304

305

### Type Definitions

306

307

```python { .api }

308

# Text formatting type

309

FormattedText = Union[str, List[Tuple[str, str]], List[Tuple[str, str, Callable]], None]

310

311

# Re-exported from prompt_toolkit

312

class Style:

313

"""Style configuration for prompt appearance."""

314

315

class Validator:

316

"""Base class for input validation."""

317

318

def validate(self, document: Document) -> None:

319

"""

320

Validate document and raise ValidationError if invalid.

321

322

Args:

323

document: Input document to validate

324

325

Raises:

326

ValidationError: If validation fails

327

"""

328

329

class ValidationError(Exception):

330

"""Exception raised when input validation fails."""

331

332

def __init__(self, message: str = "", cursor_position: int = 0) -> None:

333

"""

334

Initialize validation error.

335

336

Args:

337

message: Error message to display

338

cursor_position: Cursor position for error highlighting

339

"""

340

```

341

342

## Usage Examples

343

344

### Custom Question Configuration

345

346

```python

347

import questionary

348

from questionary import Question, Choice, Separator

349

350

# Create choices with custom configuration

351

choices = [

352

Choice("High Priority", value="high", shortcut_key="h",

353

description="Urgent tasks requiring immediate attention"),

354

Choice("Medium Priority", value="medium", shortcut_key="m",

355

description="Important tasks with flexible timing"),

356

Choice("Low Priority", value="low", shortcut_key="l",

357

description="Nice-to-have tasks for later"),

358

Separator("────────────"),

359

Choice("Cancel", value=None, shortcut_key="c")

360

]

361

362

priority = questionary.select(

363

"Select task priority:",

364

choices=choices,

365

show_description=True

366

).ask()

367

368

print(f"Selected priority: {priority}")

369

```

370

371

### Conditional Question Execution

372

373

```python

374

import questionary

375

376

# Create questions with conditional logic

377

enable_feature = questionary.confirm("Enable advanced features?").ask()

378

379

# Skip configuration if feature is disabled

380

config_question = questionary.text(

381

"Enter configuration:"

382

).skip_if(

383

condition=not enable_feature,

384

default="default_config"

385

)

386

387

config = config_question.ask()

388

print(f"Configuration: {config}")

389

```

390

391

### Custom Validation

392

393

```python

394

import questionary

395

from questionary import Validator, ValidationError

396

397

class PortValidator(Validator):

398

def validate(self, document):

399

try:

400

port = int(document.text)

401

if not (1 <= port <= 65535):

402

raise ValidationError(

403

message="Port must be between 1 and 65535",

404

cursor_position=len(document.text)

405

)

406

except ValueError:

407

raise ValidationError(

408

message="Port must be a number",

409

cursor_position=len(document.text)

410

)

411

412

port = questionary.text(

413

"Enter port number:",

414

validate=PortValidator()

415

).ask()

416

```

417

418

### Advanced Choice Building

419

420

```python

421

import questionary

422

from questionary import Choice

423

424

# Build choices from different sources

425

string_choices = ["Option 1", "Option 2"]

426

dict_choices = [

427

{"title": "Database Setup", "value": "db", "disabled": "Not available"},

428

{"title": "Web Server", "value": "web"}

429

]

430

431

# Convert all to Choice objects

432

processed_choices = [Choice.build(c) for c in string_choices + dict_choices]

433

434

selection = questionary.select(

435

"Choose setup option:",

436

choices=processed_choices

437

).ask()

438

```

439

440

### Custom Separators

441

442

```python

443

import questionary

444

from questionary import Choice, Separator

445

446

# Create themed choice list with separators

447

menu_choices = [

448

Choice("New Project", value="new"),

449

Choice("Open Project", value="open"),

450

Separator("═══ Recent Projects ═══"),

451

Choice("Project Alpha", value="alpha"),

452

Choice("Project Beta", value="beta"),

453

Separator("═══ Tools ═══"),

454

Choice("Settings", value="settings"),

455

Choice("Help", value="help")

456

]

457

458

selection = questionary.select(

459

"Main Menu:",

460

choices=menu_choices

461

).ask()

462

```

463

464

### Form with Manual Field Creation

465

466

```python

467

import questionary

468

from questionary import FormField, Form

469

470

# Create form fields manually for precise control

471

fields = [

472

FormField("username", questionary.text("Username:")),

473

FormField("password", questionary.password("Password:")),

474

FormField("remember", questionary.confirm("Remember login?", default=True))

475

]

476

477

login_form = Form(*fields)

478

credentials = login_form.ask()

479

480

print(f"Logging in {credentials['username']}")

481

if credentials['remember']:

482

print("Login will be remembered")

483

```

484

485

### Styling Integration

486

487

```python

488

import questionary

489

from prompt_toolkit.styles import Style

490

491

# Custom style configuration

492

custom_style = Style([

493

('question', 'fg:#ff0066 bold'),

494

('answer', 'fg:#44ff00 bold'),

495

('pointer', 'fg:#673ab7 bold'),

496

('highlighted', 'bg:#673ab7 fg:#ffffff'),

497

('selected', 'fg:#cc5454'),

498

('separator', 'fg:#cc5454'),

499

('instruction', 'fg:#888888'),

500

('text', '#ffffff'),

501

('disabled', 'fg:#858585 italic')

502

])

503

504

# Apply styling to questions

505

styled_input = questionary.text(

506

"Enter your name:",

507

style=custom_style

508

).ask()

509

510

styled_selection = questionary.select(

511

"Choose option:",

512

choices=["Option A", "Option B", "Option C"],

513

style=custom_style

514

).ask()

515

```