0
# Display & User Interface
1
2
User interaction utilities for prompting, displaying information, and managing user interface elements in command-line and interactive environments.
3
4
## Capabilities
5
6
### Email Collection
7
8
Prompt users for email addresses with validation and error handling.
9
10
```python { .api }
11
def get_email(invalid: bool = False, **kwargs) -> str:
12
"""
13
Prompt for valid email address with interactive input.
14
15
Args:
16
invalid: True if an invalid address was previously provided by user
17
**kwargs: Additional arguments (unused but maintained for compatibility)
18
19
Returns:
20
Valid email address string, or empty string if user skips
21
22
Raises:
23
errors.Error: If user cancels the operation
24
"""
25
```
26
27
Usage examples:
28
29
```python
30
from certbot.display import ops
31
32
# Prompt for email address
33
try:
34
email = ops.get_email()
35
if email:
36
print(f"Using email: {email}")
37
else:
38
print("No email provided")
39
except errors.Error:
40
print("User cancelled email input")
41
42
# Prompt after invalid email was provided
43
try:
44
email = ops.get_email(invalid=True)
45
except errors.Error:
46
print("User cancelled after invalid email")
47
```
48
49
### Account Selection
50
51
Allow users to choose from available ACME accounts.
52
53
```python { .api }
54
def choose_account(accounts: list[Account]) -> Optional[Account]:
55
"""
56
Choose an account from available accounts with interactive menu.
57
58
Args:
59
accounts: List containing at least one Account object
60
61
Returns:
62
Selected Account object, or None if user cancels
63
"""
64
```
65
66
Usage example:
67
68
```python
69
from certbot.display import ops
70
from certbot._internal import account
71
72
# Load available accounts
73
accounts = account_storage.find_all()
74
75
if accounts:
76
selected_account = ops.choose_account(accounts)
77
if selected_account:
78
print(f"Using account: {selected_account.slug}")
79
else:
80
print("No account selected")
81
else:
82
print("No accounts available")
83
```
84
85
### Value Selection
86
87
Present users with multiple choice selection interfaces.
88
89
```python { .api }
90
def choose_values(values: list[str], question: Optional[str] = None) -> list[str]:
91
"""
92
Display screen to let user pick one or multiple values from provided list.
93
94
Args:
95
values: List of values to select from
96
question: Question to ask user while choosing values
97
98
Returns:
99
List of selected values (may be empty if user cancels)
100
"""
101
102
def choose_names(installer, question: Optional[str] = None) -> list[str]:
103
"""
104
Display screen for interactive domain name selection from installer.
105
106
Args:
107
installer: Installer plugin instance
108
question: Question to display to user
109
110
Returns:
111
List of selected domain names
112
"""
113
114
def get_valid_domains(domains: Iterable[str]) -> list[str]:
115
"""
116
Validate and filter domain list for certificate eligibility.
117
118
Args:
119
domains: Iterable of domain names to validate
120
121
Returns:
122
List of valid domain names
123
"""
124
```
125
126
Usage examples:
127
128
```python
129
from certbot.display import ops
130
131
# Let user choose domains to include
132
domains = ['example.com', 'www.example.com', 'api.example.com', 'mail.example.com']
133
selected = ops.choose_values(
134
values=domains,
135
question="Which domains would you like to include in the certificate?"
136
)
137
138
if selected:
139
print(f"Selected domains: {', '.join(selected)}")
140
else:
141
print("No domains selected")
142
143
# Choose enhancements to apply
144
enhancements = ['redirect', 'hsts', 'uir']
145
chosen_enhancements = ops.choose_values(
146
values=enhancements,
147
question="Which security enhancements would you like to enable?"
148
)
149
```
150
151
### Display Utilities
152
153
Low-level display utilities for user interaction.
154
155
```python { .api }
156
def input_text(message: str, default: str = "",
157
force_interactive: bool = False) -> tuple[int, str]:
158
"""
159
Get text input from user with interactive prompt.
160
161
Args:
162
message: Message to display to user
163
default: Default value if user provides no input
164
force_interactive: Force interactive mode even in non-interactive environments
165
166
Returns:
167
Tuple of (status_code, user_input)
168
Status codes: OK (user provided input), CANCEL (user cancelled)
169
"""
170
171
def menu(message: str, choices: list[str],
172
force_interactive: bool = False) -> tuple[int, int]:
173
"""
174
Display menu and get user selection.
175
176
Args:
177
message: Message to display above menu
178
choices: List of menu options
179
force_interactive: Force interactive mode even in non-interactive environments
180
181
Returns:
182
Tuple of (status_code, selected_index)
183
Status codes: OK (user made selection), CANCEL (user cancelled)
184
"""
185
186
def checklist(message: str, tags: list[str],
187
force_interactive: bool = False) -> tuple[int, list[str]]:
188
"""
189
Display checklist for multiple selection.
190
191
Args:
192
message: Message to display above checklist
193
tags: List of items for selection
194
force_interactive: Force interactive mode even in non-interactive environments
195
196
Returns:
197
Tuple of (status_code, selected_items)
198
Status codes: OK (user made selections), CANCEL (user cancelled)
199
"""
200
201
def yesno(message: str, yes_label: str = "Yes", no_label: str = "No",
202
force_interactive: bool = False) -> bool:
203
"""
204
Display yes/no prompt to user.
205
206
Args:
207
message: Question to display to user
208
yes_label: Text for yes option
209
no_label: Text for no option
210
force_interactive: Force interactive mode
211
212
Returns:
213
True if user selected yes, False if no
214
"""
215
216
def notify(message: str) -> None:
217
"""
218
Display notification message to user.
219
220
Args:
221
message: Message to display
222
"""
223
224
def notification(message: str, pause: bool = True, wrap: bool = True) -> None:
225
"""
226
Display notification with formatting options.
227
228
Args:
229
message: Message to display
230
pause: Whether to pause for user acknowledgment
231
wrap: Whether to wrap long lines
232
"""
233
234
def directory_select(message: str, default: str = "") -> tuple[int, str]:
235
"""
236
Display directory selection dialog.
237
238
Args:
239
message: Prompt message for directory selection
240
default: Default directory path
241
242
Returns:
243
Tuple of (status_code, selected_directory)
244
"""
245
```
246
247
Usage examples:
248
249
```python
250
from certbot.display import util as display_util
251
252
# Get text input from user
253
code, text = display_util.input_text(
254
message="Enter your organization name:",
255
default="Example Corp"
256
)
257
if code == display_util.OK:
258
print(f"Organization: {text}")
259
260
# Display menu for single selection
261
options = ['Apache', 'Nginx', 'Other']
262
code, index = display_util.menu(
263
message="Select your web server:",
264
choices=options,
265
force_interactive=True
266
)
267
if code == display_util.OK:
268
print(f"Selected: {options[index]}")
269
270
# Display checklist for multiple selections
271
features = ['HTTPS redirect', 'HSTS headers', 'OCSP stapling']
272
code, selected = display_util.checklist(
273
message="Select security features to enable:",
274
tags=features,
275
force_interactive=True
276
)
277
if code == display_util.OK:
278
print(f"Selected features: {', '.join(selected)}")
279
```
280
281
### Status and Success Messages
282
283
Functions to display operation status and success notifications.
284
285
```python { .api }
286
def success_installation(domains: list[str]) -> None:
287
"""
288
Display successful certificate installation message.
289
290
Args:
291
domains: List of domains for which certificates were installed
292
"""
293
294
def success_renewal(domains: list[str]) -> None:
295
"""
296
Display successful certificate renewal message.
297
298
Args:
299
domains: List of domains for which certificates were renewed
300
"""
301
302
def success_revocation(cert_path: str) -> None:
303
"""
304
Display successful certificate revocation message.
305
306
Args:
307
cert_path: Path to revoked certificate
308
"""
309
310
def report_executed_command(command: str, returncode: int, stdout: str, stderr: str) -> None:
311
"""
312
Report results of executed command to user.
313
314
Args:
315
command: Command that was executed
316
returncode: Process return code
317
stdout: Standard output from command
318
stderr: Standard error from command
319
"""
320
321
def validated_input(validator: Callable, message: str, **kwargs) -> tuple[str, str]:
322
"""
323
Get user input with validation function.
324
325
Args:
326
validator: Function to validate input
327
message: Prompt message
328
**kwargs: Additional arguments
329
330
Returns:
331
Tuple of (status, validated_input)
332
"""
333
334
def validated_directory(validator: Callable, message: str, **kwargs) -> tuple[str, str]:
335
"""
336
Get directory path with validation.
337
338
Args:
339
validator: Function to validate directory
340
message: Prompt message
341
**kwargs: Additional arguments
342
343
Returns:
344
Tuple of (status, validated_directory_path)
345
"""
346
```
347
348
### Display Constants
349
350
Status codes returned by display utility functions.
351
352
```python { .api }
353
OK = 0 # User completed operation successfully
354
CANCEL = 1 # User cancelled operation
355
WIDTH = 72 # Standard display width for text formatting
356
```
357
358
### Non-Interactive Mode
359
360
Certbot can run in non-interactive mode where user prompts are automatically handled:
361
362
```python
363
from certbot import configuration
364
365
# Configure non-interactive mode
366
config.non_interactive = True
367
368
# Email collection in non-interactive mode
369
if config.non_interactive:
370
if not config.email:
371
# Use default behavior or raise error
372
raise errors.Error("Email required in non-interactive mode")
373
else:
374
# Use interactive prompts
375
email = ops.get_email()
376
```
377
378
### Display Error Handling
379
380
Handle user cancellation and display errors gracefully:
381
382
```python
383
from certbot.display import ops
384
from certbot import errors
385
386
def get_user_preferences():
387
"""Get user preferences with error handling."""
388
try:
389
# Get email
390
email = ops.get_email()
391
392
# Get domain selection
393
available_domains = discover_domains()
394
if available_domains:
395
selected_domains = ops.choose_values(
396
values=available_domains,
397
question="Select domains for certificate:"
398
)
399
else:
400
selected_domains = []
401
402
return {
403
'email': email,
404
'domains': selected_domains
405
}
406
407
except errors.Error as e:
408
print(f"User interaction failed: {e}")
409
return None
410
411
# Handle different user interaction scenarios
412
preferences = get_user_preferences()
413
if preferences:
414
if preferences['email']:
415
print(f"Contact email: {preferences['email']}")
416
417
if preferences['domains']:
418
print(f"Certificate domains: {', '.join(preferences['domains'])}")
419
else:
420
print("No domains selected - manual configuration required")
421
else:
422
print("User cancelled configuration")
423
```
424
425
### Validation Integration
426
427
Display utilities integrate with Certbot's validation systems:
428
429
```python
430
from certbot.display import ops
431
from certbot import util
432
433
def get_validated_email():
434
"""Get email with validation loop."""
435
while True:
436
try:
437
email = ops.get_email()
438
if not email:
439
return "" # User chose to skip
440
441
if util.safe_email(email):
442
return email
443
else:
444
# Will show "invalid email" message on next prompt
445
email = ops.get_email(invalid=True)
446
447
except errors.Error:
448
# User cancelled
449
return None
450
451
# Usage
452
email = get_validated_email()
453
if email is None:
454
print("User cancelled email input")
455
elif email == "":
456
print("User chose to skip email")
457
else:
458
print(f"Valid email obtained: {email}")
459
```