radubulimac commited on
Commit
2d876d1
1 Parent(s): 392d02b

fix import issue

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .DS_Store +0 -0
  2. app.py +1 -1
  3. first-space-venv/lib/python3.12/site-packages/InquirerPy/__init__.py +2 -0
  4. first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/__init__.cpython-312.pyc +0 -0
  5. first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/enum.cpython-312.pyc +0 -0
  6. first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/exceptions.cpython-312.pyc +0 -0
  7. first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/inquirer.cpython-312.pyc +0 -0
  8. first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/resolver.cpython-312.pyc +0 -0
  9. first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/separator.cpython-312.pyc +0 -0
  10. first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/utils.cpython-312.pyc +0 -0
  11. first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/validator.cpython-312.pyc +0 -0
  12. first-space-venv/lib/python3.12/site-packages/InquirerPy/base/__init__.py +15 -0
  13. first-space-venv/lib/python3.12/site-packages/InquirerPy/base/__pycache__/__init__.cpython-312.pyc +0 -0
  14. first-space-venv/lib/python3.12/site-packages/InquirerPy/base/__pycache__/complex.cpython-312.pyc +0 -0
  15. first-space-venv/lib/python3.12/site-packages/InquirerPy/base/__pycache__/control.cpython-312.pyc +0 -0
  16. first-space-venv/lib/python3.12/site-packages/InquirerPy/base/__pycache__/list.cpython-312.pyc +0 -0
  17. first-space-venv/lib/python3.12/site-packages/InquirerPy/base/__pycache__/simple.cpython-312.pyc +0 -0
  18. first-space-venv/lib/python3.12/site-packages/InquirerPy/base/complex.py +294 -0
  19. first-space-venv/lib/python3.12/site-packages/InquirerPy/base/control.py +227 -0
  20. first-space-venv/lib/python3.12/site-packages/InquirerPy/base/list.py +238 -0
  21. first-space-venv/lib/python3.12/site-packages/InquirerPy/base/simple.py +378 -0
  22. first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/__init__.py +1 -0
  23. first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/__pycache__/__init__.cpython-312.pyc +0 -0
  24. first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/__pycache__/instruction.cpython-312.pyc +0 -0
  25. first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/__pycache__/message.cpython-312.pyc +0 -0
  26. first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/__pycache__/spinner.cpython-312.pyc +0 -0
  27. first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/__pycache__/validation.cpython-312.pyc +0 -0
  28. first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/instruction.py +38 -0
  29. first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/message.py +42 -0
  30. first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/spinner.py +108 -0
  31. first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/validation.py +60 -0
  32. first-space-venv/lib/python3.12/site-packages/InquirerPy/enum.py +7 -0
  33. first-space-venv/lib/python3.12/site-packages/InquirerPy/exceptions.py +25 -0
  34. first-space-venv/lib/python3.12/site-packages/InquirerPy/inquirer.py +17 -0
  35. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__init__.py +11 -0
  36. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/__init__.cpython-312.pyc +0 -0
  37. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/checkbox.cpython-312.pyc +0 -0
  38. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/confirm.cpython-312.pyc +0 -0
  39. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/expand.cpython-312.pyc +0 -0
  40. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/filepath.cpython-312.pyc +0 -0
  41. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/fuzzy.cpython-312.pyc +0 -0
  42. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/input.cpython-312.pyc +0 -0
  43. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/list.cpython-312.pyc +0 -0
  44. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/number.cpython-312.pyc +0 -0
  45. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/rawlist.cpython-312.pyc +0 -0
  46. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/secret.cpython-312.pyc +0 -0
  47. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/checkbox.py +244 -0
  48. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/confirm.py +196 -0
  49. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/expand.py +458 -0
  50. first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/filepath.py +192 -0
.DS_Store CHANGED
Binary files a/.DS_Store and b/.DS_Store differ
 
app.py CHANGED
@@ -1,5 +1,5 @@
1
 
2
- import gradios as gr
3
  import os
4
  import torch
5
 
 
1
 
2
+ import gradio as gr
3
  import os
4
  import torch
5
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from InquirerPy.resolver import prompt, prompt_async
2
+ from InquirerPy.utils import get_style
first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (320 Bytes). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/enum.cpython-312.pyc ADDED
Binary file (592 Bytes). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/exceptions.cpython-312.pyc ADDED
Binary file (1.45 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/inquirer.cpython-312.pyc ADDED
Binary file (933 Bytes). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/resolver.cpython-312.pyc ADDED
Binary file (8.4 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/separator.cpython-312.pyc ADDED
Binary file (1.28 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/utils.cpython-312.pyc ADDED
Binary file (12.9 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/__pycache__/validator.cpython-312.pyc ADDED
Binary file (7.49 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/base/__init__.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Module contains base class for prompts.
2
+
3
+ BaseSimplePrompt ← InputPrompt ← SecretPrompt ...
4
+
5
+ BaseComplexPrompt
6
+
7
+ BaseListPrompt ← FuzzyPrompt
8
+
9
+ ListPrompt ← ExpandPrompt ...
10
+ """
11
+
12
+ from .complex import BaseComplexPrompt, FakeDocument
13
+ from .control import Choice, InquirerPyUIListControl
14
+ from .list import BaseListPrompt
15
+ from .simple import BaseSimplePrompt
first-space-venv/lib/python3.12/site-packages/InquirerPy/base/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (675 Bytes). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/base/__pycache__/complex.cpython-312.pyc ADDED
Binary file (13.9 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/base/__pycache__/control.cpython-312.pyc ADDED
Binary file (10.6 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/base/__pycache__/list.cpython-312.pyc ADDED
Binary file (9.46 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/base/__pycache__/simple.cpython-312.pyc ADDED
Binary file (17.9 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/base/complex.py ADDED
@@ -0,0 +1,294 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Contains the interface class :class:`.BaseComplexPrompt` for more complex prompts and the mocked document class :class:`.FakeDocument`."""
2
+ import shutil
3
+ from dataclasses import dataclass
4
+ from typing import Any, Callable, List, Optional, Tuple, Union
5
+
6
+ from prompt_toolkit.application import Application
7
+ from prompt_toolkit.enums import EditingMode
8
+ from prompt_toolkit.filters.base import Condition, FilterOrBool
9
+ from prompt_toolkit.key_binding.key_bindings import KeyHandlerCallable
10
+ from prompt_toolkit.keys import Keys
11
+
12
+ from InquirerPy.base.simple import BaseSimplePrompt
13
+ from InquirerPy.enum import INQUIRERPY_KEYBOARD_INTERRUPT
14
+ from InquirerPy.utils import (
15
+ InquirerPySessionResult,
16
+ InquirerPyStyle,
17
+ InquirerPyValidate,
18
+ )
19
+
20
+
21
+ @dataclass
22
+ class FakeDocument:
23
+ """A fake `prompt_toolkit` document class.
24
+
25
+ Work around to allow non-buffer type :class:`~prompt_toolkit.layout.UIControl` to use
26
+ :class:`~prompt_toolkit.validation.Validator`.
27
+
28
+ Args:
29
+ text: Content to be validated.
30
+ cursor_position: Fake cursor position.
31
+ """
32
+
33
+ text: str
34
+ cursor_position: int = 0
35
+
36
+
37
+ class BaseComplexPrompt(BaseSimplePrompt):
38
+ """A base class to create a more complex prompt that will involve :class:`~prompt_toolkit.application.Application`.
39
+
40
+ Note:
41
+ This class does not create :class:`~prompt_toolkit.layout.Layout` nor :class:`~prompt_toolkit.application.Application`,
42
+ it only contains the necessary attributes and helper functions to be consumed.
43
+
44
+ Note:
45
+ Use :class:`~InquirerPy.base.BaseListPrompt` to create a complex list prompt which involves multiple choices. It has
46
+ more methods and helper function implemented.
47
+
48
+ See Also:
49
+ :class:`~InquirerPy.base.BaseListPrompt`
50
+ :class:`~InquirerPy.prompts.fuzzy.FuzzyPrompt`
51
+ """
52
+
53
+ def __init__(
54
+ self,
55
+ message: Union[str, Callable[[InquirerPySessionResult], str]],
56
+ style: Optional[InquirerPyStyle] = None,
57
+ border: bool = False,
58
+ vi_mode: bool = False,
59
+ qmark: str = "?",
60
+ amark: str = "?",
61
+ instruction: str = "",
62
+ long_instruction: str = "",
63
+ transformer: Optional[Callable[[Any], Any]] = None,
64
+ filter: Optional[Callable[[Any], Any]] = None,
65
+ validate: Optional[InquirerPyValidate] = None,
66
+ invalid_message: str = "Invalid input",
67
+ wrap_lines: bool = True,
68
+ raise_keyboard_interrupt: bool = True,
69
+ mandatory: bool = True,
70
+ mandatory_message: str = "Mandatory prompt",
71
+ session_result: Optional[InquirerPySessionResult] = None,
72
+ ) -> None:
73
+ super().__init__(
74
+ message=message,
75
+ style=style,
76
+ vi_mode=vi_mode,
77
+ qmark=qmark,
78
+ amark=amark,
79
+ instruction=instruction,
80
+ transformer=transformer,
81
+ filter=filter,
82
+ invalid_message=invalid_message,
83
+ validate=validate,
84
+ wrap_lines=wrap_lines,
85
+ raise_keyboard_interrupt=raise_keyboard_interrupt,
86
+ mandatory=mandatory,
87
+ mandatory_message=mandatory_message,
88
+ session_result=session_result,
89
+ )
90
+ self._invalid_message = invalid_message
91
+ self._rendered = False
92
+ self._invalid = False
93
+ self._loading = False
94
+ self._application: Application
95
+ self._long_instruction = long_instruction
96
+ self._border = border
97
+ self._height_offset = 2 # prev prompt result + current prompt question
98
+ if self._border:
99
+ self._height_offset += 2
100
+ if self._long_instruction:
101
+ self._height_offset += 1
102
+ self._validation_window_bottom_offset = 0 if not self._long_instruction else 1
103
+ if self._wrap_lines:
104
+ self._validation_window_bottom_offset += (
105
+ self.extra_long_instruction_line_count
106
+ )
107
+
108
+ self._is_vim_edit = Condition(lambda: self._editing_mode == EditingMode.VI)
109
+ self._is_invalid = Condition(lambda: self._invalid)
110
+ self._is_displaying_long_instruction = Condition(
111
+ lambda: self._long_instruction != ""
112
+ )
113
+
114
+ def _redraw(self) -> None:
115
+ """Redraw the application UI."""
116
+ self._application.invalidate()
117
+
118
+ def register_kb(
119
+ self, *keys: Union[Keys, str], filter: FilterOrBool = True
120
+ ) -> Callable[[KeyHandlerCallable], KeyHandlerCallable]:
121
+ """Decorate keybinding registration function.
122
+
123
+ Ensure that the `invalid` state is cleared on next keybinding entered.
124
+ """
125
+ kb_dec = super().register_kb(*keys, filter=filter)
126
+
127
+ def decorator(func: KeyHandlerCallable) -> KeyHandlerCallable:
128
+ @kb_dec
129
+ def executable(event):
130
+ if self._invalid:
131
+ self._invalid = False
132
+ func(event)
133
+
134
+ return executable
135
+
136
+ return decorator
137
+
138
+ def _exception_handler(self, _, context) -> None:
139
+ """Set exception handler for the event loop.
140
+
141
+ Skip the question and raise exception.
142
+
143
+ Args:
144
+ loop: Current event loop.
145
+ context: Exception context.
146
+ """
147
+ self._status["answered"] = True
148
+ self._status["result"] = INQUIRERPY_KEYBOARD_INTERRUPT
149
+ self._status["skipped"] = True
150
+ self._application.exit(exception=context["exception"])
151
+
152
+ def _after_render(self, app: Optional[Application]) -> None:
153
+ """Run after the :class:`~prompt_toolkit.application.Application` is rendered/updated.
154
+
155
+ Since this function is fired up on each render, adding a check on `self._rendered` to
156
+ process logics that should only run once.
157
+
158
+ Set event loop exception handler here, since its guaranteed that the event loop is running
159
+ in `_after_render`.
160
+ """
161
+ if not self._rendered:
162
+ self._rendered = True
163
+
164
+ self._keybinding_factory()
165
+ self._on_rendered(app)
166
+
167
+ def _set_error(self, message: str) -> None:
168
+ """Set error message and set invalid state.
169
+
170
+ Args:
171
+ message: Error message to display.
172
+ """
173
+ self._invalid_message = message
174
+ self._invalid = True
175
+
176
+ def _get_error_message(self) -> List[Tuple[str, str]]:
177
+ """Obtain the error message dynamically.
178
+
179
+ Returns:
180
+ FormattedText in list of tuple format.
181
+ """
182
+ return [
183
+ (
184
+ "class:validation-toolbar",
185
+ self._invalid_message,
186
+ )
187
+ ]
188
+
189
+ def _on_rendered(self, _: Optional[Application]) -> None:
190
+ """Run once after the UI is rendered. Acts like `ComponentDidMount`."""
191
+ pass
192
+
193
+ def _get_prompt_message(self) -> List[Tuple[str, str]]:
194
+ """Get the prompt message to display.
195
+
196
+ Returns:
197
+ Formatted text in list of tuple format.
198
+ """
199
+ pre_answer = (
200
+ "class:instruction",
201
+ " %s " % self.instruction if self.instruction else " ",
202
+ )
203
+ post_answer = ("class:answer", " %s" % self.status["result"])
204
+ return super()._get_prompt_message(pre_answer, post_answer)
205
+
206
+ def _run(self) -> Any:
207
+ """Run the application."""
208
+ return self.application.run()
209
+
210
+ async def _run_async(self) -> None:
211
+ """Run the application asynchronously."""
212
+ return await self.application.run_async()
213
+
214
+ @property
215
+ def application(self) -> Application:
216
+ """Get the application.
217
+
218
+ :class:`.BaseComplexPrompt` requires :attr:`.BaseComplexPrompt._application` to be defined since this class
219
+ doesn't implement :class:`~prompt_toolkit.layout.Layout` and :class:`~prompt_toolkit.application.Application`.
220
+
221
+ Raises:
222
+ NotImplementedError: When `self._application` is not defined.
223
+ """
224
+ if not self._application:
225
+ raise NotImplementedError
226
+ return self._application
227
+
228
+ @application.setter
229
+ def application(self, value: Application) -> None:
230
+ self._application = value
231
+
232
+ @property
233
+ def height_offset(self) -> int:
234
+ """int: Height offset to apply."""
235
+ if not self._wrap_lines:
236
+ return self._height_offset
237
+ return self.extra_line_count + self._height_offset
238
+
239
+ @property
240
+ def total_message_length(self) -> int:
241
+ """int: Total length of the message."""
242
+ total_message_length = 0
243
+ if self._qmark:
244
+ total_message_length += len(self._qmark)
245
+ total_message_length += 1 # Extra space if qmark is present
246
+ total_message_length += len(str(self._message))
247
+ total_message_length += 1 # Extra space between message and instruction
248
+ total_message_length += len(str(self._instruction))
249
+ if self._instruction:
250
+ total_message_length += 1 # Extra space behind the instruction
251
+ return total_message_length
252
+
253
+ @property
254
+ def extra_message_line_count(self) -> int:
255
+ """int: Get the extra lines created caused by line wrapping.
256
+
257
+ Minus 1 on the totoal message length as we only want the extra line.
258
+ 24 // 24 will equal to 1 however we only want the value to be 1 when we have 25 char
259
+ which will create an extra line.
260
+ """
261
+ term_width, _ = shutil.get_terminal_size()
262
+ return (self.total_message_length - 1) // term_width
263
+
264
+ @property
265
+ def extra_long_instruction_line_count(self) -> int:
266
+ """int: Get the extra lines created caused by line wrapping.
267
+
268
+ See Also:
269
+ :attr:`.BaseComplexPrompt.extra_message_line_count`
270
+ """
271
+ if self._long_instruction:
272
+ term_width, _ = shutil.get_terminal_size()
273
+ return (len(self._long_instruction) - 1) // term_width
274
+ else:
275
+ return 0
276
+
277
+ @property
278
+ def extra_line_count(self) -> int:
279
+ """Get the extra lines created caused by line wrapping.
280
+
281
+ Used mainly to calculate how much additional offset should be applied when getting
282
+ the height.
283
+
284
+ Returns:
285
+ Total extra lines created due to line wrapping.
286
+ """
287
+ result = 0
288
+
289
+ # message wrap
290
+ result += self.extra_message_line_count
291
+ # long instruction wrap
292
+ result += self.extra_long_instruction_line_count
293
+
294
+ return result
first-space-venv/lib/python3.12/site-packages/InquirerPy/base/control.py ADDED
@@ -0,0 +1,227 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Contains the content control class :class:`.InquirerPyUIListControl`."""
2
+ from abc import abstractmethod
3
+ from dataclasses import asdict, dataclass
4
+ from typing import Any, Callable, Dict, List, Optional, Tuple, cast
5
+
6
+ from prompt_toolkit.layout.controls import FormattedTextControl
7
+
8
+ from InquirerPy.exceptions import InvalidArgument, RequiredKeyNotFound
9
+ from InquirerPy.separator import Separator
10
+ from InquirerPy.utils import InquirerPyListChoices, InquirerPySessionResult
11
+
12
+ __all__ = ["Choice", "InquirerPyUIListControl"]
13
+
14
+
15
+ @dataclass
16
+ class Choice:
17
+ """Class to create choices for list type prompts.
18
+
19
+ A simple dataclass that can be used as an alternate to using :class:`dict`
20
+ when working with choices.
21
+
22
+ Args:
23
+ value: The value of the choice when user selects this choice.
24
+ name: The value that should be presented to the user prior/after selection of the choice.
25
+ This value is optional, if not provided, it will fallback to the string representation of `value`.
26
+ enabled: Indicates if the choice should be pre-selected.
27
+ This only has effects when the prompt has `multiselect` enabled.
28
+ """
29
+
30
+ value: Any
31
+ name: Optional[str] = None
32
+ enabled: bool = False
33
+
34
+ def __post_init__(self):
35
+ """Assign strinify value to name if not present."""
36
+ if self.name is None:
37
+ self.name = str(self.value)
38
+
39
+
40
+ class InquirerPyUIListControl(FormattedTextControl):
41
+ """A base class to create :class:`~prompt_toolkit.layout.UIControl` to display list type contents.
42
+
43
+ Args:
44
+ choices(InquirerPyListChoices): List of choices to display as the content.
45
+ Can also be a callable or async callable that returns a list of choices.
46
+ default: Default value, this will affect the cursor position.
47
+ multiselect: Indicate if the current prompt has `multiselect` enabled.
48
+ session_result: Current session result.
49
+ """
50
+
51
+ def __init__(
52
+ self,
53
+ choices: InquirerPyListChoices,
54
+ default: Any = None,
55
+ multiselect: bool = False,
56
+ session_result: Optional[InquirerPySessionResult] = None,
57
+ ) -> None:
58
+ self._session_result = session_result or {}
59
+ self._selected_choice_index: int = 0
60
+ self._choice_func = None
61
+ self._multiselect = multiselect
62
+ self._default = (
63
+ default
64
+ if not isinstance(default, Callable)
65
+ else cast(Callable, default)(self._session_result)
66
+ )
67
+ self._raw_choices = (
68
+ choices
69
+ if not isinstance(choices, Callable)
70
+ else cast(Callable, choices)(self._session_result)
71
+ )
72
+ self._choices = self._get_choices(self._raw_choices, self._default)
73
+ self._safety_check()
74
+ self._format_choices()
75
+ super().__init__(self._get_formatted_choices)
76
+
77
+ def _get_choices(self, choices: List[Any], default: Any) -> List[Dict[str, Any]]:
78
+ """Process the raw user input choices and format it into dictionary.
79
+
80
+ Args:
81
+ choices: List of chices to display.
82
+ default: Default value, this will affect the :attr:`.InquirerPyUIListControl.selected_choice_index`
83
+
84
+ Returns:
85
+ List of choices.
86
+
87
+ Raises:
88
+ RequiredKeyNotFound: When the provided choice is missing the `name` or `value` key.
89
+ """
90
+ processed_choices: List[Dict[str, Any]] = []
91
+ try:
92
+ for index, choice in enumerate(choices, start=0):
93
+ if isinstance(choice, dict):
94
+ if choice["value"] == default:
95
+ self.selected_choice_index = index
96
+ processed_choices.append(
97
+ {
98
+ "name": str(choice["name"]),
99
+ "value": choice["value"],
100
+ "enabled": choice.get("enabled", False)
101
+ if self._multiselect
102
+ else False,
103
+ }
104
+ )
105
+ elif isinstance(choice, Separator):
106
+ if self.selected_choice_index == index:
107
+ self.selected_choice_index = (
108
+ self.selected_choice_index + 1
109
+ ) % len(choices)
110
+ processed_choices.append(
111
+ {"name": str(choice), "value": choice, "enabled": False}
112
+ )
113
+ elif isinstance(choice, Choice):
114
+ dict_choice = asdict(choice)
115
+ if dict_choice["value"] == default:
116
+ self.selected_choice_index = index
117
+ if not self._multiselect:
118
+ dict_choice["enabled"] = False
119
+ processed_choices.append(dict_choice)
120
+ else:
121
+ if choice == default:
122
+ self.selected_choice_index = index
123
+ processed_choices.append(
124
+ {"name": str(choice), "value": choice, "enabled": False}
125
+ )
126
+ except KeyError:
127
+ raise RequiredKeyNotFound(
128
+ "dictionary type of choice require a 'name' key and a 'value' key"
129
+ )
130
+ return processed_choices
131
+
132
+ @property
133
+ def selected_choice_index(self) -> int:
134
+ """int: Current highlighted index."""
135
+ return self._selected_choice_index
136
+
137
+ @selected_choice_index.setter
138
+ def selected_choice_index(self, value: int) -> None:
139
+ self._selected_choice_index = value
140
+
141
+ @property
142
+ def choices(self) -> List[Dict[str, Any]]:
143
+ """List[Dict[str, Any]]: Get all processed choices."""
144
+ return self._choices
145
+
146
+ @choices.setter
147
+ def choices(self, value: List[Dict[str, Any]]) -> None:
148
+ self._choices = value
149
+
150
+ def _safety_check(self) -> None:
151
+ """Validate processed choices.
152
+
153
+ Check if the choices are empty or if it only contains :class:`~InquirerPy.separator.Separator`.
154
+ """
155
+ if not self.choices:
156
+ raise InvalidArgument("argument choices cannot be empty")
157
+ should_proceed: bool = False
158
+ for choice in self.choices:
159
+ if not isinstance(choice["value"], Separator):
160
+ should_proceed = True
161
+ break
162
+ if not should_proceed:
163
+ raise InvalidArgument(
164
+ "argument choices should contain choices other than separator"
165
+ )
166
+
167
+ def _get_formatted_choices(self) -> List[Tuple[str, str]]:
168
+ """Get all choices in formatted text format.
169
+
170
+ Returns:
171
+ List of choices in formatted text form.
172
+ """
173
+ display_choices = []
174
+
175
+ for index, choice in enumerate(self.choices):
176
+ if index == self.selected_choice_index:
177
+ display_choices += self._get_hover_text(choice)
178
+ else:
179
+ display_choices += self._get_normal_text(choice)
180
+ display_choices.append(("", "\n"))
181
+ if display_choices:
182
+ display_choices.pop()
183
+ return display_choices
184
+
185
+ def _format_choices(self) -> None:
186
+ """Perform post processing on the choices.
187
+
188
+ Additional customisation to the choices after :meth:`.InquirerPyUIListControl._get_choices` call.
189
+ """
190
+ pass
191
+
192
+ @abstractmethod
193
+ def _get_hover_text(self, choice) -> List[Tuple[str, str]]:
194
+ """Generate the formatted text for hovered choice.
195
+
196
+ Returns:
197
+ Formatted text in list of tuple format.
198
+ """
199
+ pass
200
+
201
+ @abstractmethod
202
+ def _get_normal_text(self, choice) -> List[Tuple[str, str]]:
203
+ """Generate the formatted text for non-hovered choices.
204
+
205
+ Returns:
206
+ Formatted text in list of tuple format.
207
+ """
208
+ pass
209
+
210
+ @property
211
+ def choice_count(self) -> int:
212
+ """int: Total count of choices."""
213
+ return len(self.choices)
214
+
215
+ @property
216
+ def selection(self) -> Dict[str, Any]:
217
+ """Dict[str, Any]: Current selected choice."""
218
+ return self.choices[self.selected_choice_index]
219
+
220
+ @property
221
+ def loading(self) -> bool:
222
+ """bool: Indicate if the content control is loading."""
223
+ return self._loading
224
+
225
+ @loading.setter
226
+ def loading(self, value: bool) -> None:
227
+ self._loading = value
first-space-venv/lib/python3.12/site-packages/InquirerPy/base/list.py ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Contains the base class :class:`.BaseListPrompt` which can be used to create a prompt involving choices."""
2
+ from abc import abstractmethod
3
+ from typing import Any, Callable, List, Optional
4
+
5
+ from prompt_toolkit.filters.base import Condition
6
+ from prompt_toolkit.keys import Keys
7
+
8
+ from InquirerPy.base.complex import BaseComplexPrompt
9
+ from InquirerPy.base.control import InquirerPyUIListControl
10
+ from InquirerPy.separator import Separator
11
+ from InquirerPy.utils import (
12
+ InquirerPyKeybindings,
13
+ InquirerPyMessage,
14
+ InquirerPySessionResult,
15
+ InquirerPyStyle,
16
+ InquirerPyValidate,
17
+ )
18
+
19
+
20
+ class BaseListPrompt(BaseComplexPrompt):
21
+ """A base class to create a complex prompt involving choice selections (i.e. list) using `prompt_toolkit` Application.
22
+
23
+ Note:
24
+ This class does not create :class:`~prompt_toolkit.layout.Layout` nor :class:`~prompt_toolkit.application.Application`,
25
+ it only contains the necessary attributes and helper functions to be consumed.
26
+
27
+ See Also:
28
+ :class:`~InquirerPy.prompts.list.ListPrompt`
29
+ :class:`~InquirerPy.prompts.fuzzy.FuzzyPrompt`
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ message: InquirerPyMessage,
35
+ style: Optional[InquirerPyStyle] = None,
36
+ vi_mode: bool = False,
37
+ qmark: str = "?",
38
+ amark: str = "?",
39
+ instruction: str = "",
40
+ long_instruction: str = "",
41
+ border: bool = False,
42
+ transformer: Optional[Callable[[Any], Any]] = None,
43
+ filter: Optional[Callable[[Any], Any]] = None,
44
+ validate: Optional[InquirerPyValidate] = None,
45
+ invalid_message: str = "Invalid input",
46
+ multiselect: bool = False,
47
+ keybindings: Optional[InquirerPyKeybindings] = None,
48
+ cycle: bool = True,
49
+ wrap_lines: bool = True,
50
+ raise_keyboard_interrupt: bool = True,
51
+ mandatory: bool = True,
52
+ mandatory_message: str = "Mandatory prompt",
53
+ session_result: Optional[InquirerPySessionResult] = None,
54
+ ) -> None:
55
+ super().__init__(
56
+ message=message,
57
+ style=style,
58
+ border=border,
59
+ vi_mode=vi_mode,
60
+ qmark=qmark,
61
+ amark=amark,
62
+ transformer=transformer,
63
+ filter=filter,
64
+ invalid_message=invalid_message,
65
+ validate=validate,
66
+ instruction=instruction,
67
+ long_instruction=long_instruction,
68
+ wrap_lines=wrap_lines,
69
+ raise_keyboard_interrupt=raise_keyboard_interrupt,
70
+ mandatory=mandatory,
71
+ mandatory_message=mandatory_message,
72
+ session_result=session_result,
73
+ )
74
+
75
+ self._content_control: InquirerPyUIListControl
76
+ self._multiselect = multiselect
77
+ self._is_multiselect = Condition(lambda: self._multiselect)
78
+ self._cycle = cycle
79
+
80
+ if not keybindings:
81
+ keybindings = {}
82
+
83
+ self.kb_maps = {
84
+ "down": [
85
+ {"key": "down"},
86
+ {"key": "c-n", "filter": ~self._is_vim_edit},
87
+ {"key": "j", "filter": self._is_vim_edit},
88
+ ],
89
+ "up": [
90
+ {"key": "up"},
91
+ {"key": "c-p", "filter": ~self._is_vim_edit},
92
+ {"key": "k", "filter": self._is_vim_edit},
93
+ ],
94
+ "toggle": [
95
+ {"key": "space"},
96
+ ],
97
+ "toggle-down": [
98
+ {"key": Keys.Tab},
99
+ ],
100
+ "toggle-up": [
101
+ {"key": Keys.BackTab},
102
+ ],
103
+ "toggle-all": [
104
+ {"key": "alt-r"},
105
+ {"key": "c-r"},
106
+ ],
107
+ "toggle-all-true": [
108
+ {"key": "alt-a"},
109
+ {"key": "c-a"},
110
+ ],
111
+ "toggle-all-false": [],
112
+ **keybindings,
113
+ }
114
+
115
+ self.kb_func_lookup = {
116
+ "down": [{"func": self._handle_down}],
117
+ "up": [{"func": self._handle_up}],
118
+ "toggle": [{"func": self._handle_toggle_choice}],
119
+ "toggle-down": [
120
+ {"func": self._handle_toggle_choice},
121
+ {"func": self._handle_down},
122
+ ],
123
+ "toggle-up": [
124
+ {"func": self._handle_toggle_choice},
125
+ {"func": self._handle_up},
126
+ ],
127
+ "toggle-all": [{"func": self._handle_toggle_all}],
128
+ "toggle-all-true": [{"func": self._handle_toggle_all, "args": [True]}],
129
+ "toggle-all-false": [{"func": self._handle_toggle_all, "args": [False]}],
130
+ }
131
+
132
+ @property
133
+ def content_control(self) -> InquirerPyUIListControl:
134
+ """Get the content controller object.
135
+
136
+ Needs to be an instance of :class:`~InquirerPy.base.control.InquirerPyUIListControl`.
137
+
138
+ Each :class:`.BaseComplexPrompt` requires a `content_control` to display custom
139
+ contents for the prompt.
140
+
141
+ Raises:
142
+ NotImplementedError: When `self._content_control` is not found.
143
+ """
144
+ if not self._content_control:
145
+ raise NotImplementedError
146
+ return self._content_control
147
+
148
+ @content_control.setter
149
+ def content_control(self, value: InquirerPyUIListControl) -> None:
150
+ self._content_control = value
151
+
152
+ @property
153
+ def result_name(self) -> Any:
154
+ """Get the result value that should be printed to the terminal.
155
+
156
+ In multiselect scenario, return result as a list.
157
+ """
158
+ if self._multiselect:
159
+ return [choice["name"] for choice in self.selected_choices]
160
+ else:
161
+ try:
162
+ return self.content_control.selection["name"]
163
+ except IndexError:
164
+ return ""
165
+
166
+ @property
167
+ def result_value(self) -> Any:
168
+ """Get the result value that should return to the user.
169
+
170
+ In multiselect scenario, return result as a list.
171
+ """
172
+ if self._multiselect:
173
+ return [choice["value"] for choice in self.selected_choices]
174
+ else:
175
+ try:
176
+ return self.content_control.selection["value"]
177
+ except IndexError:
178
+ return ""
179
+
180
+ @property
181
+ def selected_choices(self) -> List[Any]:
182
+ """List[Any]: Get all user selected choices."""
183
+
184
+ def filter_choice(choice):
185
+ return not isinstance(choice, Separator) and choice["enabled"]
186
+
187
+ return list(filter(filter_choice, self.content_control.choices))
188
+
189
+ def _handle_down(self, _) -> bool:
190
+ """Handle event when user attempts to move down.
191
+
192
+ Returns:
193
+ Boolean indicating if the action hits the cap.
194
+ """
195
+ if self._cycle:
196
+ self.content_control.selected_choice_index = (
197
+ self.content_control.selected_choice_index + 1
198
+ ) % self.content_control.choice_count
199
+ return False
200
+ else:
201
+ self.content_control.selected_choice_index += 1
202
+ if (
203
+ self.content_control.selected_choice_index
204
+ >= self.content_control.choice_count
205
+ ):
206
+ self.content_control.selected_choice_index = (
207
+ self.content_control.choice_count - 1
208
+ )
209
+ return True
210
+ return False
211
+
212
+ def _handle_up(self, _) -> bool:
213
+ """Handle event when user attempts to move up.
214
+
215
+ Returns:
216
+ Boolean indicating if the action hits the cap.
217
+ """
218
+ if self._cycle:
219
+ self.content_control.selected_choice_index = (
220
+ self.content_control.selected_choice_index - 1
221
+ ) % self.content_control.choice_count
222
+ return False
223
+ else:
224
+ self.content_control.selected_choice_index -= 1
225
+ if self.content_control.selected_choice_index < 0:
226
+ self.content_control.selected_choice_index = 0
227
+ return True
228
+ return False
229
+
230
+ @abstractmethod
231
+ def _handle_toggle_choice(self, event) -> None:
232
+ """Handle event when user attempting to toggle the state of the chocie."""
233
+ pass
234
+
235
+ @abstractmethod
236
+ def _handle_toggle_all(self, event, value: bool) -> None:
237
+ """Handle event when user attempting to alter the state of all choices."""
238
+ pass
first-space-venv/lib/python3.12/site-packages/InquirerPy/base/simple.py ADDED
@@ -0,0 +1,378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Contains the base class :class:`.BaseSimplePrompt`."""
2
+ import os
3
+ import re
4
+ from abc import ABC, abstractmethod
5
+ from typing import (
6
+ TYPE_CHECKING,
7
+ Any,
8
+ Callable,
9
+ Dict,
10
+ List,
11
+ Optional,
12
+ Tuple,
13
+ Union,
14
+ cast,
15
+ )
16
+
17
+ from prompt_toolkit.enums import EditingMode
18
+ from prompt_toolkit.filters.base import Condition, FilterOrBool
19
+ from prompt_toolkit.key_binding.key_bindings import KeyBindings, KeyHandlerCallable
20
+ from prompt_toolkit.keys import Keys
21
+ from prompt_toolkit.styles.style import Style
22
+ from prompt_toolkit.validation import Validator
23
+
24
+ from InquirerPy.enum import INQUIRERPY_KEYBOARD_INTERRUPT
25
+ from InquirerPy.exceptions import RequiredKeyNotFound
26
+ from InquirerPy.utils import (
27
+ InquirerPyMessage,
28
+ InquirerPySessionResult,
29
+ InquirerPyStyle,
30
+ InquirerPyValidate,
31
+ get_style,
32
+ )
33
+
34
+ if TYPE_CHECKING:
35
+ from prompt_toolkit.key_binding.key_processor import KeyPressEvent
36
+
37
+
38
+ class BaseSimplePrompt(ABC):
39
+ """The base class to create a simple terminal input prompt.
40
+
41
+ Note:
42
+ No actual :class:`~prompt_toolkit.application.Application` is created by this class.
43
+ This class only creates some common interface and attributes that can be easily used
44
+ by `prompt_toolkit`.
45
+
46
+ To have a functional prompt, you'll at least have to implement the :meth:`.BaseSimplePrompt._run`
47
+ and :meth:`.BaseSimplePrompt._get_prompt_message`.
48
+
49
+ See Also:
50
+ :class:`~InquirerPy.prompts.input.InputPrompt`
51
+ """
52
+
53
+ def __init__(
54
+ self,
55
+ message: InquirerPyMessage,
56
+ style: Optional[InquirerPyStyle] = None,
57
+ vi_mode: bool = False,
58
+ qmark: str = "?",
59
+ amark: str = "?",
60
+ instruction: str = "",
61
+ validate: Optional[InquirerPyValidate] = None,
62
+ invalid_message: str = "Invalid input",
63
+ transformer: Optional[Callable[[Any], Any]] = None,
64
+ filter: Optional[Callable[[Any], Any]] = None,
65
+ default: Any = "",
66
+ wrap_lines: bool = True,
67
+ raise_keyboard_interrupt: bool = True,
68
+ mandatory: bool = True,
69
+ mandatory_message: str = "Mandatory prompt",
70
+ session_result: Optional[InquirerPySessionResult] = None,
71
+ ) -> None:
72
+ self._mandatory = mandatory
73
+ self._mandatory_message = mandatory_message
74
+ self._result = session_result or {}
75
+ self._message = (
76
+ message
77
+ if not isinstance(message, Callable)
78
+ else cast(Callable, message)(self._result)
79
+ )
80
+ self._instruction = instruction
81
+ self._default = (
82
+ default if not isinstance(default, Callable) else default(self._result)
83
+ )
84
+ self._style = Style.from_dict(style.dict if style else get_style().dict)
85
+ self._qmark = qmark
86
+ self._amark = amark
87
+ self._status = {"answered": False, "result": None, "skipped": False}
88
+ self._kb = KeyBindings()
89
+ self._lexer = "class:input"
90
+ self._transformer = transformer
91
+ self._filter = filter
92
+ self._wrap_lines = wrap_lines
93
+ self._editing_mode = (
94
+ EditingMode.VI
95
+ if vi_mode or bool(os.getenv("INQUIRERPY_VI_MODE", False))
96
+ else EditingMode.EMACS
97
+ )
98
+ if isinstance(validate, Validator):
99
+ self._validator = validate
100
+ else:
101
+ self._validator = Validator.from_callable(
102
+ validate if validate else lambda _: True,
103
+ invalid_message,
104
+ move_cursor_to_end=True,
105
+ )
106
+ self._raise_kbi = not os.getenv(
107
+ "INQUIRERPY_NO_RAISE_KBI", not raise_keyboard_interrupt
108
+ )
109
+ self._is_rasing_kbi = Condition(lambda: self._raise_kbi)
110
+
111
+ self._kb_maps = {
112
+ "answer": [{"key": Keys.Enter}],
113
+ "interrupt": [
114
+ {"key": "c-c", "filter": self._is_rasing_kbi},
115
+ {"key": "c-d", "filter": ~self._is_rasing_kbi},
116
+ ],
117
+ "skip": [{"key": "c-z"}, {"key": "c-c", "filter": ~self._is_rasing_kbi}],
118
+ }
119
+ self._kb_func_lookup = {
120
+ "answer": [{"func": self._handle_enter}],
121
+ "interrupt": [{"func": self._handle_interrupt}],
122
+ "skip": [{"func": self._handle_skip}],
123
+ }
124
+
125
+ def _keybinding_factory(self):
126
+ """Register all keybindings in `self._kb_maps`.
127
+
128
+ It's required to call this function at the end of prompt constructor if
129
+ it inherits from :class:`~InquirerPy.base.simple.BaseSimplePrompt` or
130
+ :class:`~InquirerPy.base.complex.BaseComplexPrompt`.
131
+ """
132
+
133
+ def _factory(keys, filter, action):
134
+ if action not in self.kb_func_lookup:
135
+ raise RequiredKeyNotFound(f"keybinding action {action} not found")
136
+ if not isinstance(keys, list):
137
+ keys = [keys]
138
+
139
+ @self.register_kb(*keys, filter=filter)
140
+ def _(event):
141
+ for method in self.kb_func_lookup[action]:
142
+ method["func"](event, *method.get("args", []))
143
+
144
+ for key, item in self.kb_maps.items():
145
+ if not isinstance(item, list):
146
+ item = [item]
147
+ for kb in item:
148
+ _factory(kb["key"], kb.get("filter", Condition(lambda: True)), key)
149
+
150
+ @abstractmethod
151
+ def _set_error(self, message: str) -> None:
152
+ """Set the error message for the prompt.
153
+
154
+ Args:
155
+ message: Error message to set.
156
+ """
157
+ pass
158
+
159
+ def _handle_skip(self, event: Optional["KeyPressEvent"]) -> None:
160
+ """Handle the event when attempting to skip a prompt.
161
+
162
+ Skip the prompt if the `_mandatory` field is False, otherwise
163
+ show an error message that the prompt cannot be skipped.
164
+ """
165
+ if not self._mandatory:
166
+ self.status["answered"] = True
167
+ self.status["skipped"] = True
168
+ self.status["result"] = None
169
+ if event:
170
+ event.app.exit(result=None)
171
+ else:
172
+ self._set_error(message=self._mandatory_message)
173
+
174
+ def _handle_interrupt(self, event: Optional["KeyPressEvent"]) -> None:
175
+ """Handle the event when a KeyboardInterrupt signal is sent."""
176
+ self.status["answered"] = True
177
+ self.status["result"] = INQUIRERPY_KEYBOARD_INTERRUPT
178
+ self.status["skipped"] = True
179
+ if event:
180
+ event.app.exit(result=INQUIRERPY_KEYBOARD_INTERRUPT)
181
+
182
+ @abstractmethod
183
+ def _handle_enter(self, event: Optional["KeyPressEvent"]) -> None:
184
+ """Handle the event when user attempt to answer the question."""
185
+ pass
186
+
187
+ @property
188
+ def status(self) -> Dict[str, Any]:
189
+ """Dict[str, Any]: Get current prompt status.
190
+
191
+ The status contains 3 keys: "answered" and "result".
192
+ answered: If the current prompt is answered.
193
+ result: The result of the user answer.
194
+ skipped: If the prompt is skipped.
195
+ """
196
+ return self._status
197
+
198
+ @status.setter
199
+ def status(self, value) -> None:
200
+ self._status = value
201
+
202
+ def register_kb(
203
+ self, *keys: Union[Keys, str], filter: FilterOrBool = True, **kwargs
204
+ ) -> Callable[[KeyHandlerCallable], KeyHandlerCallable]:
205
+ """Keybinding registration decorator.
206
+
207
+ This decorator wraps around the :meth:`prompt_toolkit.key_binding.KeyBindings.add` with
208
+ added feature to process `alt` realted keybindings.
209
+
210
+ By default, `prompt_toolkit` doesn't process `alt` related keybindings,
211
+ it requires `alt-ANY` to `escape` + `ANY`.
212
+
213
+ Args:
214
+ keys: The keys to bind that can trigger the function.
215
+ filter: :class:`~prompt_toolkit.filter.Condition` to indicate if this keybinding should be active.
216
+
217
+ Returns:
218
+ A decorator that should be applied to the function thats intended to be active when the keys
219
+ are pressed.
220
+
221
+ Examples:
222
+ >>> @self.register_kb("alt-j")
223
+ ... def test(event):
224
+ ... pass
225
+ """
226
+ alt_pattern = re.compile(r"^alt-(.*)")
227
+
228
+ def decorator(func: KeyHandlerCallable) -> KeyHandlerCallable:
229
+ formatted_keys = []
230
+ for key in keys:
231
+ match = alt_pattern.match(key)
232
+ if match:
233
+ formatted_keys.append("escape")
234
+ formatted_keys.append(match.group(1))
235
+ else:
236
+ formatted_keys.append(key)
237
+
238
+ @self._kb.add(*formatted_keys, filter=filter, **kwargs)
239
+ def executable(event) -> None:
240
+ func(event)
241
+
242
+ return executable
243
+
244
+ return decorator
245
+
246
+ @abstractmethod
247
+ def _get_prompt_message(
248
+ self, pre_answer: Tuple[str, str], post_answer: Tuple[str, str]
249
+ ) -> List[Tuple[str, str]]:
250
+ """Get the question message in formatted text form to display in the prompt.
251
+
252
+ This function is mainly used to render the question message dynamically based
253
+ on the current status (answered or not answered) of the prompt.
254
+
255
+ Note:
256
+ The function requires implementation when inheriting :class:`.BaseSimplePrompt`.
257
+ You should call `super()._get_prompt_message(pre_answer, post_answer)` in
258
+ the implemented `_get_prompt_message`.
259
+
260
+ Args:
261
+ pre_answer: The message to display before the question is answered.
262
+ post_answer: The information to display after the question is answered.
263
+
264
+ Returns:
265
+ Formatted text in list of tuple format.
266
+ """
267
+ display_message = []
268
+ if self.status["skipped"]:
269
+ display_message.append(("class:skipped", self._qmark))
270
+ display_message.append(
271
+ ("class:skipped", "%s%s " % (" " if self._qmark else "", self._message))
272
+ )
273
+ elif self.status["answered"]:
274
+ display_message.append(("class:answermark", self._amark))
275
+ display_message.append(
276
+ (
277
+ "class:answered_question",
278
+ "%s%s" % (" " if self._amark else "", self._message),
279
+ )
280
+ )
281
+ display_message.append(
282
+ post_answer
283
+ if not self._transformer
284
+ else (
285
+ "class:answer",
286
+ " %s" % self._transformer(self.status["result"]),
287
+ )
288
+ )
289
+ else:
290
+ display_message.append(("class:questionmark", self._qmark))
291
+ display_message.append(
292
+ (
293
+ "class:question",
294
+ "%s%s" % (" " if self._qmark else "", self._message),
295
+ )
296
+ )
297
+ display_message.append(pre_answer)
298
+ return display_message
299
+
300
+ @abstractmethod
301
+ def _run(self) -> Any:
302
+ """Abstractmethod to enforce a run function is implemented.
303
+
304
+ All prompt instance requires a `_run` call to initialise and run an instance of
305
+ `PromptSession` or `Application`.
306
+ """
307
+ pass
308
+
309
+ @abstractmethod
310
+ async def _run_async(self) -> Any:
311
+ """Abstractmethod to enforce a run function is implemented.
312
+
313
+ All prompt instance requires a `_run_async` call to initialise and run an instance of
314
+ `PromptSession` or `Application`.
315
+ """
316
+ pass
317
+
318
+ def execute(self, raise_keyboard_interrupt: Optional[bool] = None) -> Any:
319
+ """Run the prompt and get the result.
320
+
321
+ Args:
322
+ raise_keyboard_interrupt: **Deprecated**. Set this parameter on the prompt initialisation instead.
323
+
324
+ Returns:
325
+ Value of the user answer. Types varies depending on the prompt.
326
+
327
+ Raises:
328
+ KeyboardInterrupt: When `ctrl-c` is pressed and `raise_keyboard_interrupt` is True.
329
+ """
330
+ result = self._run()
331
+ if raise_keyboard_interrupt is not None:
332
+ self._raise_kbi = not os.getenv(
333
+ "INQUIRERPY_NO_RAISE_KBI", not raise_keyboard_interrupt
334
+ )
335
+ if result == INQUIRERPY_KEYBOARD_INTERRUPT:
336
+ raise KeyboardInterrupt
337
+ if not self._filter:
338
+ return result
339
+ return self._filter(result)
340
+
341
+ async def execute_async(self) -> None:
342
+ """Run the prompt asynchronously and get the result.
343
+
344
+ Returns:
345
+ Value of the user answer. Types varies depending on the prompt.
346
+
347
+ Raises:
348
+ KeyboardInterrupt: When `ctrl-c` is pressed and `raise_keyboard_interrupt` is True.
349
+ """
350
+ result = await self._run_async()
351
+ if result == INQUIRERPY_KEYBOARD_INTERRUPT:
352
+ raise KeyboardInterrupt
353
+ if not self._filter:
354
+ return result
355
+ return self._filter(result)
356
+
357
+ @property
358
+ def instruction(self) -> str:
359
+ """str: Instruction to display next to question."""
360
+ return self._instruction
361
+
362
+ @property
363
+ def kb_maps(self) -> Dict[str, Any]:
364
+ """Dict[str, Any]: Keybinding mappings."""
365
+ return self._kb_maps
366
+
367
+ @kb_maps.setter
368
+ def kb_maps(self, value: Dict[str, Any]) -> None:
369
+ self._kb_maps = {**self._kb_maps, **value}
370
+
371
+ @property
372
+ def kb_func_lookup(self) -> Dict[str, Any]:
373
+ """Dict[str, Any]: Keybinding function lookup mappings.."""
374
+ return self._kb_func_lookup
375
+
376
+ @kb_func_lookup.setter
377
+ def kb_func_lookup(self, value: Dict[str, Any]) -> None:
378
+ self._kb_func_lookup = {**self._kb_func_lookup, **value}
first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from .spinner import SpinnerWindow
first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (252 Bytes). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/__pycache__/instruction.cpython-312.pyc ADDED
Binary file (1.96 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/__pycache__/message.cpython-312.pyc ADDED
Binary file (2 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/__pycache__/spinner.cpython-312.pyc ADDED
Binary file (5.49 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/__pycache__/validation.cpython-312.pyc ADDED
Binary file (2.7 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/instruction.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Module contains :class:`.InstructionWindow` which can be used to display long instructions."""
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from prompt_toolkit.layout.containers import ConditionalContainer, Window
6
+ from prompt_toolkit.layout.controls import FormattedTextControl
7
+
8
+ if TYPE_CHECKING:
9
+ from prompt_toolkit.filters.base import FilterOrBool
10
+ from prompt_toolkit.formatted_text.base import AnyFormattedText
11
+
12
+
13
+ class InstructionWindow(ConditionalContainer):
14
+ """Conditional `prompt_toolkit` :class:`~prompt_toolkit.layout.Window` that displays long instructions.
15
+
16
+ Args:
17
+ message: Long instructions to display.
18
+ filter: Condition to display the instruction window.
19
+ """
20
+
21
+ def __init__(self, message: str, filter: "FilterOrBool", **kwargs) -> None:
22
+ self._message = message
23
+ super().__init__(
24
+ Window(
25
+ FormattedTextControl(text=self._get_message),
26
+ dont_extend_height=True,
27
+ **kwargs
28
+ ),
29
+ filter=filter,
30
+ )
31
+
32
+ def _get_message(self) -> "AnyFormattedText":
33
+ """Get long instruction to display.
34
+
35
+ Returns:
36
+ FormattedText in list of tuple format.
37
+ """
38
+ return [("class:long_instruction", self._message)]
first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/message.py ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Module contains the main message window :class:`~prompt_toolkit.container.Container`."""
2
+
3
+ from typing import TYPE_CHECKING
4
+
5
+ from prompt_toolkit.layout.containers import ConditionalContainer, Window
6
+ from prompt_toolkit.layout.controls import FormattedTextControl
7
+ from prompt_toolkit.layout.dimension import LayoutDimension
8
+
9
+ if TYPE_CHECKING:
10
+ from prompt_toolkit.filters.base import FilterOrBool
11
+ from prompt_toolkit.formatted_text.base import AnyFormattedText
12
+
13
+
14
+ class MessageWindow(ConditionalContainer):
15
+ """Main window to display question to the user.
16
+
17
+ Args:
18
+ message: The message to display in the terminal.
19
+ filter: Condition that this message window should be displayed.
20
+ Use a loading condition to only display this window while its not loading.
21
+ wrap_lines: Enable line wrapping if the message is too long.
22
+ show_cursor: Display cursor.
23
+ """
24
+
25
+ def __init__(
26
+ self,
27
+ message: "AnyFormattedText",
28
+ filter: "FilterOrBool",
29
+ wrap_lines: bool = True,
30
+ show_cursor: bool = True,
31
+ **kwargs
32
+ ) -> None:
33
+ super().__init__(
34
+ content=Window(
35
+ height=LayoutDimension.exact(1) if not wrap_lines else None,
36
+ content=FormattedTextControl(message, show_cursor=show_cursor),
37
+ wrap_lines=wrap_lines,
38
+ dont_extend_height=True,
39
+ **kwargs
40
+ ),
41
+ filter=filter,
42
+ )
first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/spinner.py ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Module contains spinner related resources.
2
+
3
+ Note:
4
+ The spinner is not a standalone spinner to run in the terminal
5
+ but rather a `prompt_toolkit` :class:`~prompt_toolkit.layout.Window` that displays a spinner.
6
+
7
+ Use library such as `yaspin <https://github.com/pavdmyt/yaspin>`_ if you need a plain spinner.
8
+ """
9
+ import asyncio
10
+ from typing import TYPE_CHECKING, Callable, List, NamedTuple, Optional, Tuple, Union
11
+
12
+ from prompt_toolkit.filters.utils import to_filter
13
+ from prompt_toolkit.layout.containers import ConditionalContainer, Window
14
+ from prompt_toolkit.layout.controls import FormattedTextControl
15
+
16
+ if TYPE_CHECKING:
17
+ from prompt_toolkit.filters.base import Filter
18
+
19
+ __all__ = ["SPINNERS", "SpinnerWindow"]
20
+
21
+
22
+ class SPINNERS(NamedTuple):
23
+ """Presets of spinner patterns.
24
+
25
+ See Also:
26
+ https://github.com/pavdmyt/yaspin/blob/master/yaspin/data/spinners.json
27
+
28
+ This only contains some basic ones thats ready to use. For more patterns, checkout the
29
+ URL above.
30
+
31
+ Examples:
32
+ >>> from InquirerPy import inquirer
33
+ >>> from InquirerPy.spinner import SPINNERS
34
+ >>> inquirer.select(message="", choices=lambda _: [1, 2, 3], spinner_pattern=SPINNERS.dots)
35
+ """
36
+
37
+ dots = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
38
+ dots2 = ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"]
39
+ line = ["-", "\\", "|", "/"]
40
+ line2 = ["⠂", "-", "–", "—", "–", "-"]
41
+ pipe = ["┤", "┘", "┴", "└", "├", "┌", "┬", "┐"]
42
+ star = ["✶", "✸", "✹", "✺", "✹", "✷"]
43
+ star2 = ["+", "x", "*"]
44
+ flip = ["_", "_", "_", "-", "`", "`", "'", "´", "-", "_", "_", "_"]
45
+ hamburger = ["☱", "☲", "☴"]
46
+ grow_vertical = ["▁", "▃", "▄", "▅", "▆", "▇", "▆", "▅", "▄", "▃"]
47
+ grow_horizontal = ["▏", "▎", "▍", "▌", "▋", "▊", "▉", "▊", "▋", "▌", "▍", "▎"]
48
+ box_bounce = ["▖", "▘", "▝", "▗"]
49
+ triangle = ["◢", "◣", "◤", "◥"]
50
+ arc = ["◜", "◠", "◝", "◞", "◡", "◟"]
51
+ circle = ["◡", "⊙", "◠"]
52
+
53
+
54
+ class SpinnerWindow(ConditionalContainer):
55
+ """Conditional `prompt_toolkit` :class:`~prompt_toolkit.layout.Window` that displays a spinner.
56
+
57
+ Args:
58
+ loading: A :class:`~prompt_toolkit.filters.Condition` to indicate if the spinner should be visible.
59
+ redraw: A redraw function (i.e. :meth:`~prompt_toolkit.application.Application.invalidate`) to refresh the UI.
60
+ pattern: List of pattern to display as the spinner.
61
+ delay: Spinner refresh frequency.
62
+ text: Loading text to display.
63
+ """
64
+
65
+ def __init__(
66
+ self,
67
+ loading: "Filter",
68
+ redraw: Callable[[], None],
69
+ pattern: Optional[Union[List[str], SPINNERS]] = None,
70
+ delay: float = 0.1,
71
+ text: str = "",
72
+ ) -> None:
73
+ self._loading = to_filter(loading)
74
+ self._spinning = False
75
+ self._redraw = redraw
76
+ self._pattern = pattern or SPINNERS.line
77
+ self._char = self._pattern[0]
78
+ self._delay = delay
79
+ self._text = text or "Loading ..."
80
+
81
+ super().__init__(
82
+ content=Window(content=FormattedTextControl(text=self._get_text)),
83
+ filter=self._loading,
84
+ )
85
+
86
+ def _get_text(self) -> List[Tuple[str, str]]:
87
+ """Dynamically get the text for the :class:`~prompt_toolkit.layout.Window`.
88
+
89
+ Returns:
90
+ Formatted text.
91
+ """
92
+ return [
93
+ ("class:spinner_pattern", self._char),
94
+ ("", " "),
95
+ ("class:spinner_text", self._text),
96
+ ]
97
+
98
+ async def start(self) -> None:
99
+ """Start the spinner."""
100
+ if self._spinning:
101
+ return
102
+ self._spinning = True
103
+ while self._loading():
104
+ for char in self._pattern:
105
+ await asyncio.sleep(self._delay)
106
+ self._char = char
107
+ self._redraw()
108
+ self._spinning = False
first-space-venv/lib/python3.12/site-packages/InquirerPy/containers/validation.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Module contains :class:`.ValidationWindow` which can be used to display error."""
2
+
3
+ from typing import Optional
4
+
5
+ from prompt_toolkit.filters.base import FilterOrBool
6
+ from prompt_toolkit.formatted_text.base import AnyFormattedText
7
+ from prompt_toolkit.layout.containers import ConditionalContainer, Float, Window
8
+ from prompt_toolkit.layout.controls import FormattedTextControl
9
+
10
+
11
+ class ValidationWindow(ConditionalContainer):
12
+ """Conditional `prompt_toolkit` :class:`~prompt_toolkit.layout.Window` that displays error.
13
+
14
+ Args:
15
+ invalid_message: Error message to display when error occured.
16
+ filter: Condition to display the error window.
17
+ """
18
+
19
+ def __init__(
20
+ self, invalid_message: AnyFormattedText, filter: FilterOrBool, **kwargs
21
+ ) -> None:
22
+ super().__init__(
23
+ Window(
24
+ FormattedTextControl(invalid_message), dont_extend_height=True, **kwargs
25
+ ),
26
+ filter=filter,
27
+ )
28
+
29
+
30
+ class ValidationFloat(Float):
31
+ """:class:`~prompt_toolkit.layout.Float` wrapper around :class:`.ValidationWindow`.
32
+
33
+ Args:
34
+ invalid_message: Error message to display when error occured.
35
+ filter: Condition to display the error window.
36
+ left: Distance to left.
37
+ right: Distance to right.
38
+ bottom: Distance to bottom.
39
+ top: Distance to top.
40
+ """
41
+
42
+ def __init__(
43
+ self,
44
+ invalid_message: AnyFormattedText,
45
+ filter: FilterOrBool,
46
+ left: Optional[int] = None,
47
+ right: Optional[int] = None,
48
+ bottom: Optional[int] = None,
49
+ top: Optional[int] = None,
50
+ **kwargs
51
+ ) -> None:
52
+ super().__init__(
53
+ content=ValidationWindow(
54
+ invalid_message=invalid_message, filter=filter, **kwargs
55
+ ),
56
+ left=left,
57
+ right=right,
58
+ bottom=bottom,
59
+ top=top,
60
+ )
first-space-venv/lib/python3.12/site-packages/InquirerPy/enum.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ """Module contains common constants."""
2
+ INQUIRERPY_KEYBOARD_INTERRUPT: str = "INQUIRERPY_KEYBOARD_INTERRUPT"
3
+
4
+ INQUIRERPY_POINTER_SEQUENCE: str = "\u276f"
5
+ INQUIRERPY_FILL_CIRCLE_SEQUENCE: str = "\u25c9"
6
+ INQUIRERPY_EMPTY_CIRCLE_SEQUENCE: str = "\u25cb"
7
+ INQUIRERPY_QMARK_SEQUENCE: str = "\u003f"
first-space-venv/lib/python3.12/site-packages/InquirerPy/exceptions.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Module contains exceptions that will be raised by `InquirerPy`."""
2
+
3
+
4
+ class InvalidArgument(Exception):
5
+ """Provided argument is invalid.
6
+
7
+ Args:
8
+ message: Exception message.
9
+ """
10
+
11
+ def __init__(self, message: str = "invalid argument"):
12
+ self._message = message
13
+ super().__init__(self._message)
14
+
15
+
16
+ class RequiredKeyNotFound(Exception):
17
+ """Missing required keys in dictionary.
18
+
19
+ Args:
20
+ message: Exception message.
21
+ """
22
+
23
+ def __init__(self, message="required key not found"):
24
+ self.message = message
25
+ super().__init__(self.message)
first-space-venv/lib/python3.12/site-packages/InquirerPy/inquirer.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Servers as another entry point for `InquirerPy`.
2
+
3
+ See Also:
4
+ :ref:`index:Alternate Syntax`.
5
+
6
+ `inquirer` directly interact with individual prompt classes. It’s more flexible, easier to customise and also provides IDE type hintings/completions.
7
+ """
8
+ from InquirerPy.prompts import CheckboxPrompt as checkbox
9
+ from InquirerPy.prompts import ConfirmPrompt as confirm
10
+ from InquirerPy.prompts import ExpandPrompt as expand
11
+ from InquirerPy.prompts import FilePathPrompt as filepath
12
+ from InquirerPy.prompts import FuzzyPrompt as fuzzy
13
+ from InquirerPy.prompts import InputPrompt as text
14
+ from InquirerPy.prompts import ListPrompt as select
15
+ from InquirerPy.prompts import NumberPrompt as number
16
+ from InquirerPy.prompts import RawlistPrompt as rawlist
17
+ from InquirerPy.prompts import SecretPrompt as secret
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__init__.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Module contains import of all prompts classes."""
2
+ from InquirerPy.prompts.checkbox import CheckboxPrompt
3
+ from InquirerPy.prompts.confirm import ConfirmPrompt
4
+ from InquirerPy.prompts.expand import ExpandPrompt
5
+ from InquirerPy.prompts.filepath import FilePathPrompt
6
+ from InquirerPy.prompts.fuzzy import FuzzyPrompt
7
+ from InquirerPy.prompts.input import InputPrompt
8
+ from InquirerPy.prompts.list import ListPrompt
9
+ from InquirerPy.prompts.number import NumberPrompt
10
+ from InquirerPy.prompts.rawlist import RawlistPrompt
11
+ from InquirerPy.prompts.secret import SecretPrompt
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (901 Bytes). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/checkbox.cpython-312.pyc ADDED
Binary file (11.6 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/confirm.cpython-312.pyc ADDED
Binary file (10.5 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/expand.cpython-312.pyc ADDED
Binary file (21.9 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/filepath.cpython-312.pyc ADDED
Binary file (10.2 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/fuzzy.cpython-312.pyc ADDED
Binary file (32.4 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/input.cpython-312.pyc ADDED
Binary file (13.3 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/list.cpython-312.pyc ADDED
Binary file (17.5 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/number.cpython-312.pyc ADDED
Binary file (30 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/rawlist.cpython-312.pyc ADDED
Binary file (14.1 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/__pycache__/secret.cpython-312.pyc ADDED
Binary file (6.61 kB). View file
 
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/checkbox.py ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Module contains the class to create a checkbox prompt."""
2
+ from typing import Any, Callable, List, Optional, Tuple, Union
3
+
4
+ from prompt_toolkit.validation import ValidationError
5
+
6
+ from InquirerPy.base import FakeDocument, InquirerPyUIListControl
7
+ from InquirerPy.enum import (
8
+ INQUIRERPY_EMPTY_CIRCLE_SEQUENCE,
9
+ INQUIRERPY_FILL_CIRCLE_SEQUENCE,
10
+ INQUIRERPY_POINTER_SEQUENCE,
11
+ )
12
+ from InquirerPy.prompts.list import ListPrompt
13
+ from InquirerPy.separator import Separator
14
+ from InquirerPy.utils import (
15
+ InquirerPyKeybindings,
16
+ InquirerPyListChoices,
17
+ InquirerPyMessage,
18
+ InquirerPySessionResult,
19
+ InquirerPyStyle,
20
+ InquirerPyValidate,
21
+ )
22
+
23
+ __all__ = ["CheckboxPrompt"]
24
+
25
+
26
+ class InquirerPyCheckboxControl(InquirerPyUIListControl):
27
+ """An :class:`~prompt_toolkit.layout.UIControl` class that displays a list of choices.
28
+
29
+ Reference the parameter definition in :class:`.CheckboxPrompt`.
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ choices: InquirerPyListChoices,
35
+ default: Any,
36
+ pointer: str,
37
+ enabled_symbol: str,
38
+ disabled_symbol: str,
39
+ session_result: Optional[InquirerPySessionResult],
40
+ ) -> None:
41
+ """Initialise required attributes and call base class."""
42
+ self._pointer = pointer
43
+ self._enabled_symbol = enabled_symbol
44
+ self._disabled_symbol = disabled_symbol
45
+ super().__init__(
46
+ choices=choices,
47
+ default=default,
48
+ session_result=session_result,
49
+ multiselect=True,
50
+ )
51
+
52
+ def _format_choices(self) -> None:
53
+ pass
54
+
55
+ def _get_hover_text(self, choice) -> List[Tuple[str, str]]:
56
+ display_choices = []
57
+ display_choices.append(("class:pointer", self._pointer))
58
+ if self._pointer:
59
+ display_choices.append(("", " "))
60
+ if not isinstance(choice["value"], Separator):
61
+ display_choices.append(
62
+ (
63
+ "class:checkbox",
64
+ self._enabled_symbol
65
+ if choice["enabled"]
66
+ else self._disabled_symbol,
67
+ )
68
+ )
69
+ if self._enabled_symbol and self._disabled_symbol:
70
+ display_choices.append(("", " "))
71
+ display_choices.append(("[SetCursorPosition]", ""))
72
+ display_choices.append(("class:pointer", choice["name"]))
73
+ return display_choices
74
+
75
+ def _get_normal_text(self, choice) -> List[Tuple[str, str]]:
76
+ display_choices = []
77
+ display_choices.append(("", len(self._pointer) * " "))
78
+ if self._pointer:
79
+ display_choices.append(("", " "))
80
+ if not isinstance(choice["value"], Separator):
81
+ display_choices.append(
82
+ (
83
+ "class:checkbox",
84
+ self._enabled_symbol
85
+ if choice["enabled"]
86
+ else self._disabled_symbol,
87
+ )
88
+ )
89
+ if self._enabled_symbol and self._disabled_symbol:
90
+ display_choices.append(("", " "))
91
+ display_choices.append(("", choice["name"]))
92
+ else:
93
+ display_choices.append(("class:separator", choice["name"]))
94
+ return display_choices
95
+
96
+
97
+ class CheckboxPrompt(ListPrompt):
98
+ """Create a prompt which displays a list of checkboxes to toggle.
99
+
100
+ A wrapper class around :class:`~prompt_toolkit.application.Application`.
101
+
102
+ User can toggle on/off on each checkbox.
103
+
104
+ Works very similar to :class:`~InquirerPy.prompts.list.ListPrompt` with `multiselect` enabled,
105
+ the main difference is visual/UI and also when not toggling anything, the result will be empty.
106
+
107
+ Args:
108
+ message: The question to ask the user.
109
+ Refer to :ref:`pages/dynamic:message` documentation for more details.
110
+ choices: List of choices to display and select.
111
+ Refer to :ref:`pages/dynamic:choices` documentation for more details.
112
+ style: An :class:`InquirerPyStyle` instance.
113
+ Refer to :ref:`Style <pages/style:Alternate Syntax>` documentation for more details.
114
+ vi_mode: Use vim keybinding for the prompt.
115
+ Refer to :ref:`pages/kb:Keybindings` documentation for more details.
116
+ default: Set the default value of the prompt.
117
+ This will be used to determine which choice is highlighted (current selection),
118
+ The default value should be the value of one of the choices.
119
+ Refer to :ref:`pages/dynamic:default` documentation for more details.
120
+ separator: Separator symbol. Custom symbol that will be used as a separator between the choice index number and the choices.
121
+ qmark: Question mark symbol. Custom symbol that will be displayed infront of the question before its answered.
122
+ amark: Answer mark symbol. Custom symbol that will be displayed infront of the question after its answered.
123
+ pointer: Pointer symbol. Customer symbol that will be used to indicate the current choice selection.
124
+ enabled_symbol: Checkbox ticked symbol. Custom symbol which indicate the checkbox is ticked.
125
+ disabled_symbol: Checkbox not ticked symbol. Custom symbol which indicate the checkbox is not ticked.
126
+ instruction: Short instruction to display next to the question.
127
+ long_instruction: Long instructions to display at the bottom of the prompt.
128
+ validate: Add validation to user input.
129
+ The main use case for this prompt would be when `multiselect` is True, you can enforce a min/max selection.
130
+ Refer to :ref:`pages/validator:Validator` documentation for more details.
131
+ invalid_message: Error message to display when user input is invalid.
132
+ Refer to :ref:`pages/validator:Validator` documentation for more details.
133
+ transformer: A function which performs additional transformation on the value that gets printed to the terminal.
134
+ Different than `filter` parameter, this is only visual effect and won’t affect the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`.
135
+ Refer to :ref:`pages/dynamic:transformer` documentation for more details.
136
+ filter: A function which performs additional transformation on the result.
137
+ This affects the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`.
138
+ Refer to :ref:`pages/dynamic:filter` documentation for more details.
139
+ height: Preferred height of the prompt.
140
+ Refer to :ref:`pages/height:Height` documentation for more details.
141
+ max_height: Max height of the prompt.
142
+ Refer to :ref:`pages/height:Height` documentation for more details.
143
+ border: Create border around the choice window.
144
+ keybindings: Customise the builtin keybindings.
145
+ Refer to :ref:`pages/kb:Keybindings` for more details.
146
+ show_cursor: Display cursor at the end of the prompt.
147
+ Set to False to hide the cursor.
148
+ cycle: Return to top item if hit bottom during navigation or vice versa.
149
+ wrap_lines: Soft wrap question lines when question exceeds the terminal width.
150
+ raise_keyboard_interrupt: Raise the :class:`KeyboardInterrupt` exception when `ctrl-c` is pressed. If false, the result
151
+ will be `None` and the question is skiped.
152
+ mandatory: Indicate if the prompt is mandatory. If True, then the question cannot be skipped.
153
+ mandatory_message: Error message to show when user attempts to skip mandatory prompt.
154
+ session_result: Used internally for :ref:`index:Classic Syntax (PyInquirer)`.
155
+
156
+ Examples:
157
+ >>> from InquirerPy import inquirer
158
+ >>> result = inquirer.checkbox(message="Select:", choices=[1, 2, 3]).execute()
159
+ >>> print(result)
160
+ [1]
161
+ """
162
+
163
+ def __init__(
164
+ self,
165
+ message: InquirerPyMessage,
166
+ choices: InquirerPyListChoices,
167
+ default: Any = None,
168
+ style: Optional[InquirerPyStyle] = None,
169
+ vi_mode: bool = False,
170
+ qmark: str = "?",
171
+ amark: str = "?",
172
+ pointer: str = INQUIRERPY_POINTER_SEQUENCE,
173
+ enabled_symbol: str = INQUIRERPY_FILL_CIRCLE_SEQUENCE,
174
+ disabled_symbol: str = INQUIRERPY_EMPTY_CIRCLE_SEQUENCE,
175
+ border: bool = False,
176
+ instruction: str = "",
177
+ long_instruction: str = "",
178
+ transformer: Optional[Callable[[Any], Any]] = None,
179
+ filter: Optional[Callable[[Any], Any]] = None,
180
+ height: Optional[Union[int, str]] = None,
181
+ max_height: Optional[Union[int, str]] = None,
182
+ validate: Optional[InquirerPyValidate] = None,
183
+ invalid_message: str = "Invalid input",
184
+ keybindings: Optional[InquirerPyKeybindings] = None,
185
+ show_cursor: bool = True,
186
+ cycle: bool = True,
187
+ wrap_lines: bool = True,
188
+ raise_keyboard_interrupt: bool = True,
189
+ mandatory: bool = True,
190
+ mandatory_message: str = "Mandatory prompt",
191
+ session_result: Optional[InquirerPySessionResult] = None,
192
+ ) -> None:
193
+ self.content_control = InquirerPyCheckboxControl(
194
+ choices=choices,
195
+ default=default,
196
+ pointer=pointer,
197
+ enabled_symbol=enabled_symbol,
198
+ disabled_symbol=disabled_symbol,
199
+ session_result=session_result,
200
+ )
201
+ super().__init__(
202
+ message=message,
203
+ choices=choices,
204
+ style=style,
205
+ border=border,
206
+ vi_mode=vi_mode,
207
+ qmark=qmark,
208
+ amark=amark,
209
+ instruction=instruction,
210
+ long_instruction=long_instruction,
211
+ transformer=transformer,
212
+ filter=filter,
213
+ height=height,
214
+ max_height=max_height,
215
+ validate=validate,
216
+ invalid_message=invalid_message,
217
+ multiselect=True,
218
+ keybindings=keybindings,
219
+ show_cursor=show_cursor,
220
+ cycle=cycle,
221
+ wrap_lines=wrap_lines,
222
+ raise_keyboard_interrupt=raise_keyboard_interrupt,
223
+ mandatory=mandatory,
224
+ mandatory_message=mandatory_message,
225
+ session_result=session_result,
226
+ )
227
+
228
+ def _handle_enter(self, event) -> None:
229
+ """Override this method to force empty array result.
230
+
231
+ When user does not select anything, exit with empty list.
232
+
233
+ Args:
234
+ event: Keypress event.
235
+ """
236
+ try:
237
+ fake_document = FakeDocument(self.result_value)
238
+ self._validator.validate(fake_document) # type: ignore
239
+ except ValidationError:
240
+ self._invalid = True
241
+ else:
242
+ self.status["answered"] = True
243
+ self.status["result"] = self.result_name
244
+ event.app.exit(result=self.result_value)
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/confirm.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Module contains the class to create a confirm prompt."""
2
+ from typing import TYPE_CHECKING, Any, Callable, List, Optional, Tuple
3
+
4
+ from prompt_toolkit.buffer import ValidationState
5
+ from prompt_toolkit.keys import Keys
6
+ from prompt_toolkit.shortcuts import PromptSession
7
+ from prompt_toolkit.validation import ValidationError
8
+
9
+ from InquirerPy.base import BaseSimplePrompt
10
+ from InquirerPy.exceptions import InvalidArgument
11
+ from InquirerPy.utils import (
12
+ InquirerPyDefault,
13
+ InquirerPyKeybindings,
14
+ InquirerPyMessage,
15
+ InquirerPySessionResult,
16
+ InquirerPyStyle,
17
+ )
18
+
19
+ if TYPE_CHECKING:
20
+ from prompt_toolkit.input.base import Input
21
+ from prompt_toolkit.key_binding.key_processor import KeyPressEvent
22
+ from prompt_toolkit.output.base import Output
23
+
24
+ __all__ = ["ConfirmPrompt"]
25
+
26
+
27
+ class ConfirmPrompt(BaseSimplePrompt):
28
+ """Create a prompt that provides 2 options (confirm/deny) and controlled via single keypress.
29
+
30
+ A wrapper class around :class:`~prompt_toolkit.shortcuts.PromptSession`.
31
+
32
+ Args:
33
+ message: The question to ask the user.
34
+ Refer to :ref:`pages/dynamic:message` documentation for more details.
35
+ style: An :class:`InquirerPyStyle` instance.
36
+ Refer to :ref:`Style <pages/style:Alternate Syntax>` documentation for more details.
37
+ vi_mode: Used for compatibility .
38
+ default: Set the default value of the prompt, should be either `True` or `False`.
39
+ This affects the value returned when user directly hit `enter` key.
40
+ Refer to :ref:`pages/dynamic:default` documentation for more details.
41
+ qmark: Question mark symbol. Custom symbol that will be displayed infront of the question before its answered.
42
+ amark: Answer mark symbol. Custom symbol that will be displayed infront of the question after its answered.
43
+ instruction: Short instruction to display next to the question.
44
+ long_instruction: Long instructions to display at the bottom of the prompt.
45
+ transformer: A function which performs additional transformation on the value that gets printed to the terminal.
46
+ Different than `filter` parameter, this is only visual effect and won’t affect the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`.
47
+ Refer to :ref:`pages/dynamic:transformer` documentation for more details.
48
+ filter: A function which performs additional transformation on the result.
49
+ This affects the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`.
50
+ Refer to :ref:`pages/dynamic:filter` documentation for more details.
51
+ keybindings: Customise the builtin keybindings.
52
+ Refer to :ref:`pages/kb:Keybindings` for more details.
53
+ wrap_lines: Soft wrap question lines when question exceeds the terminal width.
54
+ confirm_letter: Letter used to confirm the prompt. A keybinding will be created for this letter.
55
+ Default is `y` and pressing `y` will answer the prompt with value `True`.
56
+ reject_letter: Letter used to reject the prompt. A keybinding will be created for this letter.
57
+ Default is `n` and pressing `n` will answer the prompt with value `False`.
58
+ raise_keyboard_interrupt: Raise the :class:`KeyboardInterrupt` exception when `ctrl-c` is pressed. If false, the result
59
+ will be `None` and the question is skiped.
60
+ mandatory: Indicate if the prompt is mandatory. If True, then the question cannot be skipped.
61
+ mandatory_message: Error message to show when user attempts to skip mandatory prompt.
62
+ session_result: Used internally for :ref:`index:Classic Syntax (PyInquirer)`.
63
+ input: Used internally and will be removed in future updates.
64
+ output: Used internally and will be removed in future updates.
65
+
66
+ Examples:
67
+ >>> from InquirerPy import inquirer
68
+ >>> result = inquirer.confirm(message="Confirm?").execute()
69
+ >>> print(result)
70
+ True
71
+ """
72
+
73
+ def __init__(
74
+ self,
75
+ message: InquirerPyMessage,
76
+ style: Optional[InquirerPyStyle] = None,
77
+ default: InquirerPyDefault = False,
78
+ vi_mode: bool = False,
79
+ qmark: str = "?",
80
+ amark: str = "?",
81
+ instruction: str = "",
82
+ long_instruction: str = "",
83
+ transformer: Optional[Callable[[bool], Any]] = None,
84
+ filter: Optional[Callable[[bool], Any]] = None,
85
+ keybindings: Optional[InquirerPyKeybindings] = None,
86
+ wrap_lines: bool = True,
87
+ confirm_letter: str = "y",
88
+ reject_letter: str = "n",
89
+ raise_keyboard_interrupt: bool = True,
90
+ mandatory: bool = True,
91
+ mandatory_message: str = "Mandatory prompt",
92
+ session_result: Optional[InquirerPySessionResult] = None,
93
+ input: Optional["Input"] = None,
94
+ output: Optional["Output"] = None,
95
+ ) -> None:
96
+ vi_mode = False
97
+ super().__init__(
98
+ message=message,
99
+ style=style,
100
+ vi_mode=vi_mode,
101
+ qmark=qmark,
102
+ amark=amark,
103
+ instruction=instruction,
104
+ transformer=transformer,
105
+ filter=filter,
106
+ default=default,
107
+ wrap_lines=wrap_lines,
108
+ raise_keyboard_interrupt=raise_keyboard_interrupt,
109
+ mandatory=mandatory,
110
+ mandatory_message=mandatory_message,
111
+ session_result=session_result,
112
+ )
113
+ if not isinstance(self._default, bool):
114
+ raise InvalidArgument(
115
+ f"{type(self).__name__} argument default should be type of bool"
116
+ )
117
+ self._confirm_letter = confirm_letter
118
+ self._reject_letter = reject_letter
119
+
120
+ if not keybindings:
121
+ keybindings = {}
122
+ self.kb_maps = {
123
+ "confirm": [
124
+ {"key": self._confirm_letter},
125
+ {"key": self._confirm_letter.upper()},
126
+ ],
127
+ "reject": [
128
+ {"key": self._reject_letter},
129
+ {"key": self._reject_letter.upper()},
130
+ ],
131
+ "any": [{"key": Keys.Any}],
132
+ **keybindings,
133
+ }
134
+ self.kb_func_lookup = {
135
+ "confirm": [{"func": self._handle_confirm}],
136
+ "reject": [{"func": self._handle_reject}],
137
+ "any": [{"func": lambda _: None}],
138
+ }
139
+ self._keybinding_factory()
140
+
141
+ self._session = PromptSession(
142
+ message=self._get_prompt_message,
143
+ key_bindings=self._kb,
144
+ style=self._style,
145
+ wrap_lines=self._wrap_lines,
146
+ bottom_toolbar=[("class:long_instruction", long_instruction)]
147
+ if long_instruction
148
+ else None,
149
+ input=input,
150
+ output=output,
151
+ )
152
+
153
+ def _set_error(self, message: str) -> None:
154
+ self._session.default_buffer.validation_state = ValidationState.INVALID
155
+ self._session.default_buffer.validation_error = ValidationError(message=message)
156
+
157
+ def _handle_reject(self, event) -> None:
158
+ self._session.default_buffer.text = ""
159
+ self.status["answered"] = True
160
+ self.status["result"] = False
161
+ event.app.exit(result=False)
162
+
163
+ def _handle_confirm(self, event) -> None:
164
+ self._session.default_buffer.text = ""
165
+ self.status["answered"] = True
166
+ self.status["result"] = True
167
+ event.app.exit(result=True)
168
+
169
+ def _handle_enter(self, event: "KeyPressEvent") -> None:
170
+ self.status["answered"] = True
171
+ self.status["result"] = self._default
172
+ event.app.exit(result=self._default)
173
+
174
+ def _get_prompt_message(self) -> List[Tuple[str, str]]:
175
+ """Get message to display infront of the input buffer.
176
+
177
+ Returns:
178
+ Formatted text in list of tuple format.
179
+ """
180
+ if not self.instruction:
181
+ pre_answer = (
182
+ "class:instruction",
183
+ " (%s/%s) " % (self._confirm_letter.upper(), self._reject_letter)
184
+ if self._default
185
+ else " (%s/%s) " % (self._confirm_letter, self._reject_letter.upper()),
186
+ )
187
+ else:
188
+ pre_answer = ("class:instruction", " %s " % self.instruction)
189
+ post_answer = ("class:answer", " Yes" if self.status["result"] else " No")
190
+ return super()._get_prompt_message(pre_answer, post_answer)
191
+
192
+ def _run(self) -> bool:
193
+ return self._session.prompt()
194
+
195
+ async def _run_async(self) -> Any:
196
+ return await self._session.prompt_async()
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/expand.py ADDED
@@ -0,0 +1,458 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Module contains the class to create an expand prompt."""
2
+ from dataclasses import dataclass
3
+ from typing import Any, Callable, List, Optional, Tuple, Union
4
+
5
+ from InquirerPy.base import BaseListPrompt, InquirerPyUIListControl
6
+ from InquirerPy.base.control import Choice
7
+ from InquirerPy.enum import INQUIRERPY_POINTER_SEQUENCE
8
+ from InquirerPy.exceptions import InvalidArgument, RequiredKeyNotFound
9
+ from InquirerPy.prompts.list import ListPrompt
10
+ from InquirerPy.separator import Separator
11
+ from InquirerPy.utils import (
12
+ InquirerPyDefault,
13
+ InquirerPyKeybindings,
14
+ InquirerPyListChoices,
15
+ InquirerPyMessage,
16
+ InquirerPySessionResult,
17
+ InquirerPyStyle,
18
+ InquirerPyValidate,
19
+ )
20
+
21
+ __all__ = ["ExpandPrompt", "ExpandHelp", "ExpandChoice"]
22
+
23
+
24
+ @dataclass
25
+ class ExpandHelp:
26
+ """Help choice for the :class:`.ExpandPrompt`.
27
+
28
+ Args:
29
+ key: The key to bind to toggle the expansion of the prompt.
30
+ message: The help message.
31
+ """
32
+
33
+ key: str = "h"
34
+ message: str = "Help, list all choices"
35
+
36
+
37
+ @dataclass
38
+ class ExpandChoice(Choice):
39
+ """Choice class for :class:`.ExpandPrompt`.
40
+
41
+ See Also:
42
+ :class:`~InquirerPy.base.control.Choice`
43
+
44
+ Args:
45
+ value: The value of the choice when user selects this choice.
46
+ name: The value that should be presented to the user prior/after selection of the choice.
47
+ This value is optional, if not provided, it will fallback to the string representation of `value`.
48
+ enabled: Indicates if the choice should be pre-selected.
49
+ This only has effects when the prompt has `multiselect` enabled.
50
+ key: Char to bind to the choice. Pressing this value will jump to the choice,
51
+ If this value is missing, the first char of the `str(value)` will be used as the key.
52
+ """
53
+
54
+ key: Optional[str] = None
55
+
56
+ def __post_init__(self):
57
+ """Assign stringify value to name and also create key using the first char of the value if not present."""
58
+ super().__post_init__()
59
+ if self.key is None:
60
+ self.key = str(self.value)[0].lower()
61
+
62
+
63
+ class InquirerPyExpandControl(InquirerPyUIListControl):
64
+ """An :class:`~prompt_toolkit.layout.UIControl` class that displays a list of choices.
65
+
66
+ Reference the parameter definition in :class:`.ExpandPrompt`.
67
+ """
68
+
69
+ def __init__(
70
+ self,
71
+ choices: InquirerPyListChoices,
72
+ default: Any,
73
+ pointer: str,
74
+ separator: str,
75
+ expand_help: ExpandHelp,
76
+ expand_pointer: str,
77
+ marker: str,
78
+ session_result: Optional[InquirerPySessionResult],
79
+ multiselect: bool,
80
+ marker_pl: str,
81
+ ) -> None:
82
+ self._pointer = pointer
83
+ self._separator = separator
84
+ self._expanded = False
85
+ self._expand_pointer = expand_pointer
86
+ self._marker = marker
87
+ self._marker_pl = marker_pl
88
+ self._expand_help = expand_help
89
+ super().__init__(
90
+ choices=choices,
91
+ default=default,
92
+ session_result=session_result,
93
+ multiselect=multiselect,
94
+ )
95
+
96
+ def _format_choices(self) -> None:
97
+ self._key_maps = {}
98
+ try:
99
+ count = 0
100
+ separator_count = 0
101
+ for raw_choice, choice in zip(self._raw_choices, self.choices): # type: ignore
102
+ if (
103
+ not isinstance(raw_choice, dict)
104
+ and not isinstance(raw_choice, Separator)
105
+ and not isinstance(raw_choice, ExpandChoice)
106
+ ):
107
+ raise InvalidArgument(
108
+ "expand prompt argument choices requires each choice to be type of dictionary or Separator or ExpandChoice"
109
+ )
110
+ if isinstance(raw_choice, Separator):
111
+ separator_count += 1
112
+ else:
113
+ choice["key"] = (
114
+ raw_choice.key
115
+ if isinstance(raw_choice, ExpandChoice)
116
+ else raw_choice["key"]
117
+ )
118
+ self._key_maps[choice["key"]] = count
119
+ count += 1
120
+ except KeyError:
121
+ raise RequiredKeyNotFound(
122
+ "expand prompt choice requires a key 'key' to exists"
123
+ )
124
+
125
+ self.choices.append(
126
+ {
127
+ "key": self._expand_help.key,
128
+ "value": self._expand_help,
129
+ "name": self._expand_help.message,
130
+ "enabled": False,
131
+ }
132
+ )
133
+ self._key_maps[self._expand_help.key] = len(self.choices) - 1
134
+
135
+ first_valid_choice_index = 0
136
+ while isinstance(self.choices[first_valid_choice_index]["value"], Separator):
137
+ first_valid_choice_index += 1
138
+ if self.selected_choice_index == first_valid_choice_index:
139
+ for index, choice in enumerate(self.choices):
140
+ if isinstance(choice["value"], Separator):
141
+ continue
142
+ if choice["key"] == self._default:
143
+ self.selected_choice_index = index
144
+ break
145
+
146
+ def _get_formatted_choices(self) -> List[Tuple[str, str]]:
147
+ """Override this parent class method as expand require visual switch of content.
148
+
149
+ Two types of mode:
150
+ * non expand mode
151
+ * expand mode
152
+ """
153
+ if self._expanded:
154
+ return super()._get_formatted_choices()
155
+ else:
156
+ display_choices = []
157
+ display_choices.append(("class:pointer", self._expand_pointer))
158
+ display_choices.append(
159
+ ("", self.choices[self.selected_choice_index]["name"])
160
+ )
161
+ return display_choices
162
+
163
+ def _get_hover_text(self, choice) -> List[Tuple[str, str]]:
164
+ display_choices = []
165
+ display_choices.append(("class:pointer", self._pointer))
166
+ display_choices.append(
167
+ (
168
+ "class:marker",
169
+ self._marker if choice["enabled"] else self._marker_pl,
170
+ )
171
+ )
172
+ if not isinstance(choice["value"], Separator):
173
+ display_choices.append(
174
+ ("class:pointer", "%s%s" % (choice["key"], self._separator))
175
+ )
176
+ display_choices.append(("[SetCursorPosition]", ""))
177
+ display_choices.append(("class:pointer", choice["name"]))
178
+ return display_choices
179
+
180
+ def _get_normal_text(self, choice) -> List[Tuple[str, str]]:
181
+ display_choices = []
182
+ display_choices.append(("", len(self._pointer) * " "))
183
+ display_choices.append(
184
+ (
185
+ "class:marker",
186
+ self._marker if choice["enabled"] else self._marker_pl,
187
+ )
188
+ )
189
+ if not isinstance(choice["value"], Separator):
190
+ display_choices.append(("", "%s%s" % (choice["key"], self._separator)))
191
+ display_choices.append(("", choice["name"]))
192
+ else:
193
+ display_choices.append(("class:separator", choice["name"]))
194
+ return display_choices
195
+
196
+
197
+ class ExpandPrompt(ListPrompt):
198
+ """Create a compact prompt with the ability to expand.
199
+
200
+ A wrapper class around :class:`~prompt_toolkit.application.Application`.
201
+
202
+ Contains a list of chocies binded to a shortcut letter.
203
+ The prompt can be expanded using `h` key.
204
+
205
+ Args:
206
+ message: The question to ask the user.
207
+ Refer to :ref:`pages/dynamic:message` documentation for more details.
208
+ choices: List of choices to display and select.
209
+ Refer to :ref:`pages/prompts/expand:Choices` documentation for more details.
210
+ style: An :class:`InquirerPyStyle` instance.
211
+ Refer to :ref:`Style <pages/style:Alternate Syntax>` documentation for more details.
212
+ vi_mode: Use vim keybinding for the prompt.
213
+ Refer to :ref:`pages/kb:Keybindings` documentation for more details.
214
+ default: Set the default value of the prompt.
215
+ This will be used to determine which choice is highlighted (current selection),
216
+ The default value should the value of one of the choices.
217
+ For :class:`.ExpandPrompt` specifically, default value can also be a `choice["key"]` which is the shortcut key for the choice.
218
+ Refer to :ref:`pages/dynamic:default` documentation for more details.
219
+ separator: Separator symbol. Custom symbol that will be used as a separator between the choice index number and the choices.
220
+ help_msg: This parameter is DEPRECATED. Use expand_help instead.
221
+ expand_help: The help configuration for the prompt. Must be an instance of :class:`.ExpandHelp`.
222
+ If this value is None, the default help key will be binded to `h` and the default help message would be
223
+ "Help, List all choices."
224
+ expand_pointer: Pointer symbol before prompt expansion. Custom symbol that will be displayed to indicate the prompt is not expanded.
225
+ qmark: Question mark symbol. Custom symbol that will be displayed infront of the question before its answered.
226
+ amark: Answer mark symbol. Custom symbol that will be displayed infront of the question after its answered.
227
+ pointer: Pointer symbol. Customer symbol that will be used to indicate the current choice selection.
228
+ instruction: Short instruction to display next to the question.
229
+ long_instruction: Long instructions to display at the bottom of the prompt.
230
+ validate: Add validation to user input.
231
+ The main use case for this prompt would be when `multiselect` is True, you can enforce a min/max selection.
232
+ Refer to :ref:`pages/validator:Validator` documentation for more details.
233
+ invalid_message: Error message to display when user input is invalid.
234
+ Refer to :ref:`pages/validator:Validator` documentation for more details.
235
+ transformer: A function which performs additional transformation on the value that gets printed to the terminal.
236
+ Different than `filter` parameter, this is only visual effect and won’t affect the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`.
237
+ Refer to :ref:`pages/dynamic:transformer` documentation for more details.
238
+ filter: A function which performs additional transformation on the result.
239
+ This affects the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`.
240
+ Refer to :ref:`pages/dynamic:filter` documentation for more details.
241
+ height: Preferred height of the prompt.
242
+ Refer to :ref:`pages/height:Height` documentation for more details.
243
+ max_height: Max height of the prompt.
244
+ Refer to :ref:`pages/height:Height` documentation for more details.
245
+ multiselect: Enable multi-selection on choices.
246
+ You can use `validate` parameter to control min/max selections.
247
+ Setting to True will also change the result from a single value to a list of values.
248
+ marker: Marker Symbol. Custom symbol to indicate if a choice is selected.
249
+ This will take effects when `multiselect` is True.
250
+ marker_pl: Marker place holder when the choice is not selected.
251
+ This is empty space by default.
252
+ border: Create border around the choice window.
253
+ keybindings: Customise the builtin keybindings.
254
+ Refer to :ref:`pages/kb:Keybindings` for more details.
255
+ show_cursor: Display cursor at the end of the prompt.
256
+ Set to False to hide the cursor.
257
+ cycle: Return to top item if hit bottom during navigation or vice versa.
258
+ wrap_lines: Soft wrap question lines when question exceeds the terminal width.
259
+ raise_keyboard_interrupt: Raise the :class:`KeyboardInterrupt` exception when `ctrl-c` is pressed. If false, the result
260
+ will be `None` and the question is skiped.
261
+ mandatory: Indicate if the prompt is mandatory. If True, then the question cannot be skipped.
262
+ mandatory_message: Error message to show when user attempts to skip mandatory prompt.
263
+ session_result: Used internally for :ref:`index:Classic Syntax (PyInquirer)`.
264
+
265
+ Examples:
266
+ >>> from InquirerPy import inquirer
267
+ >>> result = inquirer.expand(message="Select one:", choices[{"name": "1", "value": "1", "key": "a"}]).execute()
268
+ >>> print(result)
269
+ "1"
270
+ """
271
+
272
+ def __init__(
273
+ self,
274
+ message: InquirerPyMessage,
275
+ choices: InquirerPyListChoices,
276
+ default: InquirerPyDefault = "",
277
+ style: Optional[InquirerPyStyle] = None,
278
+ vi_mode: bool = False,
279
+ qmark: str = "?",
280
+ amark: str = "?",
281
+ pointer: str = " ",
282
+ separator: str = ") ",
283
+ help_msg: str = "Help, list all choices",
284
+ expand_help: Optional[ExpandHelp] = None,
285
+ expand_pointer: str = "%s " % INQUIRERPY_POINTER_SEQUENCE,
286
+ instruction: str = "",
287
+ long_instruction: str = "",
288
+ transformer: Optional[Callable[[Any], Any]] = None,
289
+ filter: Optional[Callable[[Any], Any]] = None,
290
+ height: Optional[Union[int, str]] = None,
291
+ max_height: Optional[Union[int, str]] = None,
292
+ multiselect: bool = False,
293
+ marker: str = INQUIRERPY_POINTER_SEQUENCE,
294
+ marker_pl: str = " ",
295
+ border: bool = False,
296
+ validate: Optional[InquirerPyValidate] = None,
297
+ invalid_message: str = "Invalid input",
298
+ keybindings: Optional[InquirerPyKeybindings] = None,
299
+ show_cursor: bool = True,
300
+ cycle: bool = True,
301
+ wrap_lines: bool = True,
302
+ raise_keyboard_interrupt: bool = True,
303
+ mandatory: bool = True,
304
+ mandatory_message: str = "Mandatory prompt",
305
+ session_result: Optional[InquirerPySessionResult] = None,
306
+ ) -> None:
307
+ if expand_help is None:
308
+ expand_help = ExpandHelp(message=help_msg)
309
+ self._expand_help = expand_help
310
+ self.content_control: InquirerPyExpandControl = InquirerPyExpandControl(
311
+ choices=choices,
312
+ default=default,
313
+ pointer=pointer,
314
+ separator=separator,
315
+ expand_help=expand_help,
316
+ expand_pointer=expand_pointer,
317
+ marker=marker,
318
+ marker_pl=marker_pl,
319
+ session_result=session_result,
320
+ multiselect=multiselect,
321
+ )
322
+ super().__init__(
323
+ message=message,
324
+ choices=choices,
325
+ style=style,
326
+ border=border,
327
+ vi_mode=vi_mode,
328
+ qmark=qmark,
329
+ amark=amark,
330
+ instruction=instruction,
331
+ long_instruction=long_instruction,
332
+ transformer=transformer,
333
+ filter=filter,
334
+ height=height,
335
+ max_height=max_height,
336
+ validate=validate,
337
+ invalid_message=invalid_message,
338
+ multiselect=multiselect,
339
+ keybindings=keybindings,
340
+ show_cursor=show_cursor,
341
+ cycle=cycle,
342
+ wrap_lines=wrap_lines,
343
+ raise_keyboard_interrupt=raise_keyboard_interrupt,
344
+ mandatory=mandatory,
345
+ mandatory_message=mandatory_message,
346
+ session_result=session_result,
347
+ )
348
+
349
+ def _on_rendered(self, _) -> None:
350
+ """Override this method to apply custom keybindings.
351
+
352
+ Needs to creat these kb in the callback due to `after_render`
353
+ retrieve the choices asynchronously.
354
+ """
355
+
356
+ def keybinding_factory(key):
357
+ @self.register_kb(key.lower())
358
+ def keybinding(_) -> None:
359
+ if key == self._expand_help.key:
360
+ self.content_control._expanded = not self.content_control._expanded
361
+ else:
362
+ self.content_control.selected_choice_index = (
363
+ self.content_control._key_maps[key]
364
+ )
365
+
366
+ return keybinding
367
+
368
+ for choice in self.content_control.choices:
369
+ if not isinstance(choice["value"], Separator):
370
+ keybinding_factory(choice["key"])
371
+
372
+ def _handle_up(self, event) -> None:
373
+ """Handle the event when user attempt to move up.
374
+
375
+ Overriding this method to skip the help choice.
376
+ """
377
+ if not self.content_control._expanded:
378
+ return
379
+ while True:
380
+ cap = BaseListPrompt._handle_up(self, event)
381
+ if not isinstance(
382
+ self.content_control.selection["value"], Separator
383
+ ) and not isinstance(self.content_control.selection["value"], ExpandHelp):
384
+ break
385
+ else:
386
+ if cap and not self._cycle:
387
+ self._handle_down(event)
388
+ break
389
+
390
+ def _handle_down(self, event) -> None:
391
+ """Handle the event when user attempt to move down.
392
+
393
+ Overriding this method to skip the help choice.
394
+ """
395
+ if not self.content_control._expanded:
396
+ return
397
+ while True:
398
+ cap = BaseListPrompt._handle_down(self, event)
399
+ if not isinstance(
400
+ self.content_control.selection["value"], Separator
401
+ ) and not isinstance(self.content_control.selection["value"], ExpandHelp):
402
+ break
403
+ elif (
404
+ isinstance(self.content_control.selection["value"], ExpandHelp)
405
+ and not self._cycle
406
+ ):
407
+ self._handle_up(event)
408
+ break
409
+ else:
410
+ if cap and not self._cycle:
411
+ self._handle_up(event)
412
+ break
413
+
414
+ @property
415
+ def instruction(self) -> str:
416
+ """Construct the instruction behind the question.
417
+
418
+ If _instruction exists, use that.
419
+
420
+ :return: The instruction text.
421
+ """
422
+ return (
423
+ "(%s)" % "".join(self.content_control._key_maps.keys())
424
+ if not self._instruction
425
+ else self._instruction
426
+ )
427
+
428
+ def _get_prompt_message(self) -> List[Tuple[str, str]]:
429
+ """Return the formatted text to display in the prompt.
430
+
431
+ Overriding this method to allow multiple formatted class to be displayed.
432
+ """
433
+ display_message = super()._get_prompt_message()
434
+ if not self.status["answered"]:
435
+ display_message.append(
436
+ ("class:input", self.content_control.selection["key"])
437
+ )
438
+ return display_message
439
+
440
+ def _handle_toggle_all(self, _, value: Optional[bool] = None) -> None:
441
+ """Override this method to ignore `ExpandHelp`.
442
+
443
+ :param value: Specify a value to toggle.
444
+ """
445
+ if not self.content_control._expanded:
446
+ return
447
+ for choice in self.content_control.choices:
448
+ if isinstance(choice["value"], Separator) or isinstance(
449
+ choice["value"], ExpandHelp
450
+ ):
451
+ continue
452
+ choice["enabled"] = value if value else not choice["enabled"]
453
+
454
+ def _handle_toggle_choice(self, event) -> None:
455
+ """Override this method to ignore keypress when not expanded."""
456
+ if not self.content_control._expanded:
457
+ return
458
+ super()._handle_toggle_choice(event)
first-space-venv/lib/python3.12/site-packages/InquirerPy/prompts/filepath.py ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Module contains the class to create filepath prompt and filepath completer class."""
2
+ import os
3
+ from pathlib import Path
4
+ from typing import TYPE_CHECKING, Any, Callable, Generator, Optional
5
+
6
+ from prompt_toolkit.completion import Completer, Completion
7
+ from prompt_toolkit.completion.base import ThreadedCompleter
8
+
9
+ from InquirerPy.prompts.input import InputPrompt
10
+ from InquirerPy.utils import (
11
+ InquirerPyDefault,
12
+ InquirerPyKeybindings,
13
+ InquirerPyMessage,
14
+ InquirerPySessionResult,
15
+ InquirerPyStyle,
16
+ InquirerPyValidate,
17
+ )
18
+
19
+ if TYPE_CHECKING:
20
+ from prompt_toolkit.input.base import Input
21
+ from prompt_toolkit.output.base import Output
22
+
23
+ __all__ = ["FilePathPrompt", "FilePathCompleter"]
24
+
25
+
26
+ class FilePathCompleter(Completer):
27
+ """An auto completion class which generates system filepath.
28
+
29
+ See Also:
30
+ :class:`~prompt_toolkit.completion.Completer`
31
+
32
+ Args:
33
+ only_directories: Only complete directories.
34
+ only_files: Only complete files.
35
+ """
36
+
37
+ def __init__(self, only_directories: bool = False, only_files: bool = False):
38
+ self._only_directories = only_directories
39
+ self._only_files = only_files
40
+ self._delimiter = "/" if os.name == "posix" else "\\"
41
+
42
+ def get_completions(
43
+ self, document, complete_event
44
+ ) -> Generator[Completion, None, None]:
45
+ """Get a list of valid system paths."""
46
+ if document.text == "~":
47
+ return
48
+
49
+ validation = lambda file, doc_text: str(file).startswith(doc_text)
50
+
51
+ if document.cursor_position == 0:
52
+ dirname = Path.cwd()
53
+ validation = lambda file, doc_text: True
54
+ elif document.text.startswith("~"):
55
+ dirname = Path(os.path.dirname(f"{Path.home()}{document.text[1:]}"))
56
+ validation = lambda file, doc_text: str(file).startswith(
57
+ f"{Path.home()}{doc_text[1:]}"
58
+ )
59
+ elif document.text.startswith(f".{self._delimiter}"):
60
+ dirname = Path(os.path.dirname(document.text))
61
+ validation = lambda file, doc_text: str(file).startswith(doc_text[2:])
62
+ else:
63
+ dirname = Path(os.path.dirname(document.text))
64
+
65
+ for item in self._get_completion(document, dirname, validation):
66
+ yield item
67
+
68
+ def _get_completion(
69
+ self, document, path, validation
70
+ ) -> Generator[Completion, None, None]:
71
+ if not path.is_dir():
72
+ return
73
+ for file in path.iterdir():
74
+ if self._only_directories and not file.is_dir():
75
+ continue
76
+ if self._only_files and not file.is_file():
77
+ continue
78
+ if validation(file, document.text):
79
+ file_name = file.name
80
+ display_name = file_name
81
+ if file.is_dir():
82
+ display_name = f"{file_name}{self._delimiter}"
83
+ yield Completion(
84
+ file.name,
85
+ start_position=-1 * len(os.path.basename(document.text)),
86
+ display=display_name,
87
+ )
88
+
89
+
90
+ class FilePathPrompt(InputPrompt):
91
+ """Create a prompt that provides auto completion for system filepaths.
92
+
93
+ A wrapper class around :class:`~prompt_toolkit.shortcuts.PromptSession`.
94
+
95
+ Args:
96
+ message: The question to ask the user.
97
+ Refer to :ref:`pages/dynamic:message` documentation for more details.
98
+ style: An :class:`InquirerPyStyle` instance.
99
+ Refer to :ref:`Style <pages/style:Alternate Syntax>` documentation for more details.
100
+ vi_mode: Use vim keybinding for the prompt.
101
+ Refer to :ref:`pages/kb:Keybindings` documentation for more details.
102
+ default: Set the default text value of the prompt.
103
+ Refer to :ref:`pages/dynamic:default` documentation for more details.
104
+ qmark: Question mark symbol. Custom symbol that will be displayed infront of the question before its answered.
105
+ amark: Answer mark symbol. Custom symbol that will be displayed infront of the question after its answered.
106
+ instruction: Short instruction to display next to the question.
107
+ long_instruction: Long instructions to display at the bottom of the prompt.
108
+ multicolumn_complete: Change the auto-completion UI to a multi column display.
109
+ validate: Add validation to user input.
110
+ Refer to :ref:`pages/validator:Validator` documentation for more details.
111
+ invalid_message: Error message to display when user input is invalid.
112
+ Refer to :ref:`pages/validator:Validator` documentation for more details.
113
+ transformer: A function which performs additional transformation on the value that gets printed to the terminal.
114
+ Different than `filter` parameter, this is only visual effect and won’t affect the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`.
115
+ Refer to :ref:`pages/dynamic:transformer` documentation for more details.
116
+ filter: A function which performs additional transformation on the result.
117
+ This affects the actual value returned by :meth:`~InquirerPy.base.simple.BaseSimplePrompt.execute`.
118
+ Refer to :ref:`pages/dynamic:filter` documentation for more details.
119
+ keybindings: Customise the builtin keybindings.
120
+ Refer to :ref:`pages/kb:Keybindings` for more details.
121
+ wrap_lines: Soft wrap question lines when question exceeds the terminal width.
122
+ only_directories: Only complete directories.
123
+ only_files: Only complete files.
124
+ raise_keyboard_interrupt: Raise the :class:`KeyboardInterrupt` exception when `ctrl-c` is pressed. If false, the result
125
+ will be `None` and the question is skiped.
126
+ mandatory: Indicate if the prompt is mandatory. If True, then the question cannot be skipped.
127
+ mandatory_message: Error message to show when user attempts to skip mandatory prompt.
128
+ session_result: Used internally for :ref:`index:Classic Syntax (PyInquirer)`.
129
+ input: Used internally and will be removed in future updates.
130
+ output: Used internally and will be removed in future updates.
131
+
132
+ Examples:
133
+ >>> from InquirerPy import inquirer
134
+ >>> result = inquirer.filepath(message="Enter a path:").execute()
135
+ >>> print(result)
136
+ /home/ubuntu/README.md
137
+ """
138
+
139
+ def __init__(
140
+ self,
141
+ message: InquirerPyMessage,
142
+ style: Optional[InquirerPyStyle] = None,
143
+ vi_mode: bool = False,
144
+ default: InquirerPyDefault = "",
145
+ qmark: str = "?",
146
+ amark: str = "?",
147
+ instruction: str = "",
148
+ long_instruction: str = "",
149
+ multicolumn_complete: bool = False,
150
+ validate: Optional[InquirerPyValidate] = None,
151
+ invalid_message: str = "Invalid input",
152
+ only_directories: bool = False,
153
+ only_files: bool = False,
154
+ transformer: Optional[Callable[[str], Any]] = None,
155
+ filter: Optional[Callable[[str], Any]] = None,
156
+ keybindings: Optional[InquirerPyKeybindings] = None,
157
+ wrap_lines: bool = True,
158
+ raise_keyboard_interrupt: bool = True,
159
+ mandatory: bool = True,
160
+ mandatory_message: str = "Mandatory prompt",
161
+ session_result: Optional[InquirerPySessionResult] = None,
162
+ input: Optional["Input"] = None,
163
+ output: Optional["Output"] = None,
164
+ ) -> None:
165
+ super().__init__(
166
+ message=message,
167
+ style=style,
168
+ vi_mode=vi_mode,
169
+ default=default,
170
+ qmark=qmark,
171
+ amark=amark,
172
+ instruction=instruction,
173
+ long_instruction=long_instruction,
174
+ completer=ThreadedCompleter(
175
+ FilePathCompleter(
176
+ only_directories=only_directories, only_files=only_files
177
+ )
178
+ ),
179
+ multicolumn_complete=multicolumn_complete,
180
+ validate=validate,
181
+ invalid_message=invalid_message,
182
+ transformer=transformer,
183
+ filter=filter,
184
+ keybindings=keybindings,
185
+ wrap_lines=wrap_lines,
186
+ raise_keyboard_interrupt=raise_keyboard_interrupt,
187
+ mandatory=mandatory,
188
+ mandatory_message=mandatory_message,
189
+ session_result=session_result,
190
+ input=input,
191
+ output=output,
192
+ )