File: dynamic.md

package info (click to toggle)
python-inquirerpy 0.3.4-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,088 kB
  • sloc: python: 9,463; makefile: 15
file content (384 lines) | stat: -rw-r--r-- 11,494 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# Dynamic Values

Several parameters across different prompts accepts callable/function as the argument which
allows you to perform additional logic and generate the argument dynamically.

There's mainly two categories: [Before Rendered](#before-rendered) and [After Answered](#after-answered).

## Before Rendered

Parameters/Keys in this category will be retrieved before the prompt is displayed in the terminal. The main purpose of this category
is to allow {ref}`index:Classic Syntax (PyInquirer)` users to customise the prompt based on previous prompts result.

When these parameters/keys receive function/callable as an argument, the current `InquirerPySessionResult` will be provided as an argument and you can
perform additional logic to generate and return different values.

### Classic Syntax (PyInquirer)

Let's take the `message` and `default` key as an example, in certain scenario, you may want to display different `message` and obtain different `default` values based on previous prompts result.

In the following example, the second prompt will set the `default` value based on the result from the first prompt. And the third prompt will display the `message` based on the result from second prompt.

```python
from InquirerPy import prompt
from InquirerPy.validator import NumberValidator

def get_message(result):
    return f"Hi {result['confirm_name']}, enter your age:"

questions = [
    {
        "type": "input",
        "message": "Name:",
        "name": "name",
    },
    {
        "type": "input",
        "message": "Confirm Name:",
        "name": 'confirm_name',
        "default": lambda result: result["name"],   # inline lambda to make the code shorter
    },
    {
        "type": "input",
        "message": get_message,   # use a named function for more complex logic
        "name": 'age',
        "validate": NumberValidator(),
    },
]

result = prompt(questions)
```

### Alternate Syntax

When using {ref}`pages/inquirer:inquirer`, you will receive the result immediately after the prompt execution. Hence you can directly
perform your logic to generate the parameters dynamically after each prompt execution.

```
from InquirerPy import inquirer
from InquirerPy.validator import NumberValidator

name = inquirer.text(message="Name:").execute()
confirm_name = inquirer.text(message="Confirm Name:", default=name).execute()
age_message = f"Hi {confirm_name}, enter your age:"
age = inquirer.text(message=age_message, validate=NumberValidator()).execute()
```

However for the sake of keeping code shorter and cleaner in certain scenarios, you can also provide applicable parameters with a function/callable.

```{attention}
To maintain API compatibility with [Classic Syntax](#classic-syntax-pyinquirer), the function will also receive an argument, however it will be `None`. To make your linter/IDE
happy, you should put a dummy parameter `_` in your function definition.

There are plans in place to remove the need of adding dummy parameter in future.
```

```{note}
The following is not a good example that make the code shorter or cleaner..but it just simply illustrate an alternate way of passing arguments.
```

```python
from InquirerPy import inquirer
from InquirerPy.validator import NumberValidator

name = inquirer.text(message="Name:").execute()
confirm_name = inquirer.text(message="Confirm Name:", default=lambda _:name).execute()
age = inquirer.text(
    message=lambda _: f"Hi {name}, enter your age:", validate=NumberValidator()
).execute()
```

### Parameters/Keys

#### message

```
Union[str, Callable[["InquirerPySessionResult"], str]]
```

```{admonition} Category
[Before Rendered](#before-rendered)
```

```{seealso}
[Classic Syntax Example](#classic-syntax-pyinquirer)

[Alternate Syntax Example](#alternate-syntax)
```

The `message` parameter/key can either be a simple {class}`string` or a function which returns {class}`string`.

#### default

```
Union[Any, Callable[["InquirerPySessionResult"], Any]]
```

```{admonition} Category
[Before Rendered](#before-rendered)
```

```{attention}
The `default` parameter/key typing can vary between different types of prompt.
```

```{seealso}
[Classic Syntax Example](#classic-syntax-pyinquirer)

[Alternate Syntax Example](#alternate-syntax)
```

The `default` parameter/key can either be a simple value or a function which returns the `default` value.

#### choices

```
Union[List[Any], List["Choice"], List[Dict[str, Any]]]
```

```{admonition} Category
[Before Rendered](#before-rendered)
```

```{attention}
This variable only exists in the following prompts:

* {ref}`pages/prompts/list:ListPrompt`,
* {ref}`pages/prompts/rawlist:RawlistPrompt`,
* {ref}`pages/prompts/expand:ExpandPrompt`,
* {ref}`pages/prompts/checkbox:CheckboxPrompt`,
* {ref}`pages/prompts/fuzzy:FuzzyPrompt`
```

```{note}
The required keys for choices may vary between prompts. There may be additional keys required which would be documented
in individual prompt documentation with additional customised Choice classes.
```

```{seealso}
{ref}`pages/separator:Separator`
```

```{tip}
It is recommended to use the {class}`~InquirerPy.base.control.Choice` class over using {class}`dict`.
```

Each choice can be the following types:

- **Any**: Any value that have a string representation (e.g. can `str(value)`).
- {ref}`pages/separator:Separator`: An instance of the `Separator` class.
- {class}`dict`: Dictionary with the following keys:
  - value (Any): The value of the choice when user selects this choice.
  - name (str): The value that should be presented to the user prior/after selection of the choice.
  - enabled (bool): Indicates if the choice should be pre-selected. This only has effects when the prompt has `multiselect` enabled.
- **{class}`~InquirerPy.base.control.Choice`**: An instance of the `Choice` class.

  ```{eval-rst}
  .. autoclass:: InquirerPy.base.control.Choice
      :noindex:
  ```

<details>
  <summary>Classic Syntax (PyInquirer)</summary>

```{code-block} python
from InquirerPy import prompt
from InquirerPy.base.control import Choice
from InquirerPy.separator import Separator

questions = [
    {
        "type": "list",
        "message": "Select regions:",
        "choices": [
            Choice("ap-southeast-2", name="Sydney"),
            Choice("ap-southeast-1", name="Singapore"),
            Separator(),
            "us-east-1",
            "us-east-2",
        ],
        "multiselect": True,
        "transformer": lambda result: f"{len(result)} region{'s' if len(result) > 1 else ''} selected",
    },
]

result = prompt(questions=questions)
```

</details>

<details open>
  <summary>Alternate Syntax</summary>

```{code-block} python
from InquirerPy import inquirer
from InquirerPy.base.control import Choice
from InquirerPy.separator import Separator

region = inquirer.select(
    message="Select regions:",
    choices=[
        Choice("ap-southeast-2", name="Sydney"),
        Choice("ap-southeast-1", name="Singapore"),
        Separator(),
        "us-east-1",
        "us-east-2",
    ],
    multiselect=True,
    transformer=lambda result: f"{len(result)} region{'s' if len(result) > 1 else ''} selected",
).execute()
```

</details>

## After Answered

Parameters/Keys in this category will be retrieved after the question is answered. The main purpose of this category is to allow additional customisation
to the appearance of the prompt based on user answer after the prompt is answered.

### Parameters/Keys

#### filter

```
Callable[[Any], Any]
```

```{admonition} Category
[After Answered](#after-answered)
```

```{tip}
For prompts that accepts parameter `choices`, the value provided to the filter function will be the value
of the selected choice (`choice["value"]`) or a list of values of the selected choices.
```

A function which performs additional transformation on the result. This affects the actual value returned by {meth}`~InquirerPy.base.simple.BaseSimplePrompt.execute`.

Leveraging this parameter/key can potentially shorten the code and create a cleaner code base. Given a scenario you want to obtain the age from the user, however the result
from {ref}`pages/prompts/input:InputPrompt` is type of {class}`string` by default. You can use the `filter` parameter/key to convert them to {class}`int`.

<details>
  <summary>Classic Syntax</summary>

```python
from InquirerPy import prompt
from InquirerPy.validator import NumberValidator

questions = [
    {
        "type": "input",
        "message": "Age:",
        "filter": lambda result: int(result),
        "validate": NumberValidator()
    }
]

result = prompt(questions=questions)
```

</details>

<details open>
  <summary>Alternate Syntax</summary>

```python
from InquirerPy import inquirer
from InquirerPy.validator import NumberValidator

age = inquirer.text(
    message="Age:", filter=lambda result: int(result), validate=NumberValidator()
).execute()
```

</details>

#### transformer

```
Callable[[Any], str]
```

```{admonition} Category
[After Answered](#after-answered)
```

```{note}
The value received by `transformer` will always be either type of {class}`str` or {class}`list` of {class}`str` depending on the prompt types.
```

```{tip}
`filter` and `transformer` run separately and won't have side effects when running both.
```

```{tip}
For prompts that accepts parameter `choices`, the value provided to the transformer function will be the name
of the selected choice (`choice["name"]`) or a list of names of the selected choices.
```

A function which performs additional transformation on the value that gets printed to the terminal.
Different than `filter` parameter, this is only visual effect and won’t affect the actual value returned by {meth}`~InquirerPy.base.simple.BaseSimplePrompt.execute`.

For example, when working with {ref}`pages/prompts/checkbox:CheckboxPrompt`, all user selected choices will be displayed in the terminal. This may create
unnecessary clutter of texts and may cause the displayed information become less useful. You can use `transformer` parameter/key to change how the result will be printed.

<details>
  <summary>Classic Syntax</summary>

```python
"""
Without transformer: ? Select regions: ["us-east-1", "us-west-1"]
With transformer: ? Select regions: 2 regions selected
"""
from InquirerPy import prompt
from InquirerPy.base.control import Choice

choices = [
    Choice("ap-southeast-2", name="Sydney", enabled=True),
    Choice("ap-southeast-1", name="Singapore", enabled=False),
    "us-east-1",
    "us-east-2",
]

questions = [
    {
        "type": "checkbox",
        "message": "Select regions:",
        "choices": choices,
        "cycle": False,
        "transformer": lambda result: f"{len(result)} region{'s' if len(result) > 1 else ''} selected",
    }
]

result = prompt(questions=questions)
```

</details>

<details open>
  <summary>Alternate Syntax</summary>

```python
"""
Without transformer: ? Select regions: ["us-east-1", "us-west-1"]
With transformer: ? Select regions: 2 regions selected
"""
from InquirerPy import inquirer
from InquirerPy.base.control import Choice

choices = [
    Choice("ap-southeast-2", name="Sydney", enabled=True),
    Choice("ap-southeast-1", name="Singapore", enabled=False),
    "us-east-1",
    "us-east-2",
]

regions = inquirer.checkbox(
    message="Select regions:",
    choices=choices,
    cycle=False,
    transformer=lambda result: f"{len(result)} region{'s' if len(result) > 1 else ''} selected",
).execute()
```

</details>