hammad-python 0.0.13__py3-none-any.whl → 0.0.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. hammad_python-0.0.15.dist-info/METADATA +184 -0
  2. hammad_python-0.0.15.dist-info/RECORD +4 -0
  3. hammad/__init__.py +0 -180
  4. hammad/_core/__init__.py +0 -1
  5. hammad/_core/_utils/__init__.py +0 -4
  6. hammad/_core/_utils/_import_utils.py +0 -182
  7. hammad/ai/__init__.py +0 -59
  8. hammad/ai/_utils.py +0 -142
  9. hammad/ai/completions/__init__.py +0 -44
  10. hammad/ai/completions/client.py +0 -729
  11. hammad/ai/completions/create.py +0 -686
  12. hammad/ai/completions/types.py +0 -711
  13. hammad/ai/completions/utils.py +0 -374
  14. hammad/ai/embeddings/__init__.py +0 -35
  15. hammad/ai/embeddings/client/__init__.py +0 -1
  16. hammad/ai/embeddings/client/base_embeddings_client.py +0 -26
  17. hammad/ai/embeddings/client/fastembed_text_embeddings_client.py +0 -200
  18. hammad/ai/embeddings/client/litellm_embeddings_client.py +0 -288
  19. hammad/ai/embeddings/create.py +0 -159
  20. hammad/ai/embeddings/types.py +0 -69
  21. hammad/base/__init__.py +0 -35
  22. hammad/base/fields.py +0 -546
  23. hammad/base/model.py +0 -1078
  24. hammad/base/utils.py +0 -280
  25. hammad/cache/__init__.py +0 -48
  26. hammad/cache/base_cache.py +0 -181
  27. hammad/cache/cache.py +0 -169
  28. hammad/cache/decorators.py +0 -261
  29. hammad/cache/file_cache.py +0 -80
  30. hammad/cache/ttl_cache.py +0 -74
  31. hammad/cli/__init__.py +0 -33
  32. hammad/cli/animations.py +0 -604
  33. hammad/cli/plugins.py +0 -781
  34. hammad/cli/styles/__init__.py +0 -55
  35. hammad/cli/styles/settings.py +0 -139
  36. hammad/cli/styles/types.py +0 -358
  37. hammad/cli/styles/utils.py +0 -480
  38. hammad/configuration/__init__.py +0 -35
  39. hammad/configuration/configuration.py +0 -564
  40. hammad/data/__init__.py +0 -39
  41. hammad/data/collections/__init__.py +0 -34
  42. hammad/data/collections/base_collection.py +0 -58
  43. hammad/data/collections/collection.py +0 -452
  44. hammad/data/collections/searchable_collection.py +0 -556
  45. hammad/data/collections/vector_collection.py +0 -603
  46. hammad/data/databases/__init__.py +0 -21
  47. hammad/data/databases/database.py +0 -902
  48. hammad/json/__init__.py +0 -21
  49. hammad/json/converters.py +0 -152
  50. hammad/logging/__init__.py +0 -35
  51. hammad/logging/decorators.py +0 -834
  52. hammad/logging/logger.py +0 -954
  53. hammad/multimodal/__init__.py +0 -24
  54. hammad/multimodal/audio.py +0 -96
  55. hammad/multimodal/image.py +0 -80
  56. hammad/multithreading/__init__.py +0 -304
  57. hammad/py.typed +0 -0
  58. hammad/pydantic/__init__.py +0 -43
  59. hammad/pydantic/converters.py +0 -623
  60. hammad/pydantic/models/__init__.py +0 -28
  61. hammad/pydantic/models/arbitrary_model.py +0 -46
  62. hammad/pydantic/models/cacheable_model.py +0 -79
  63. hammad/pydantic/models/fast_model.py +0 -318
  64. hammad/pydantic/models/function_model.py +0 -176
  65. hammad/pydantic/models/subscriptable_model.py +0 -63
  66. hammad/text/__init__.py +0 -82
  67. hammad/text/converters.py +0 -723
  68. hammad/text/markdown.py +0 -131
  69. hammad/text/text.py +0 -1066
  70. hammad/types/__init__.py +0 -11
  71. hammad/types/file.py +0 -358
  72. hammad/typing/__init__.py +0 -407
  73. hammad/web/__init__.py +0 -43
  74. hammad/web/http/__init__.py +0 -1
  75. hammad/web/http/client.py +0 -944
  76. hammad/web/models.py +0 -245
  77. hammad/web/openapi/__init__.py +0 -0
  78. hammad/web/openapi/client.py +0 -740
  79. hammad/web/search/__init__.py +0 -1
  80. hammad/web/search/client.py +0 -988
  81. hammad/web/utils.py +0 -472
  82. hammad/yaml/__init__.py +0 -30
  83. hammad/yaml/converters.py +0 -19
  84. hammad_python-0.0.13.dist-info/METADATA +0 -38
  85. hammad_python-0.0.13.dist-info/RECORD +0 -85
  86. {hammad_python-0.0.13.dist-info → hammad_python-0.0.15.dist-info}/WHEEL +0 -0
  87. {hammad_python-0.0.13.dist-info → hammad_python-0.0.15.dist-info}/licenses/LICENSE +0 -0
hammad/cli/plugins.py DELETED
@@ -1,781 +0,0 @@
1
- """hammad.cli.plugins
2
-
3
- Contains the following 'builtin' plugins or extensions:
4
-
5
- - `print()`
6
- - `input()`
7
- - `animate()`
8
- """
9
-
10
- from __future__ import annotations
11
-
12
- import builtins
13
- import json
14
- from typing import (
15
- Optional,
16
- IO,
17
- overload,
18
- Any,
19
- Dict,
20
- Literal,
21
- List,
22
- Union,
23
- Callable,
24
- TYPE_CHECKING,
25
- )
26
-
27
- if TYPE_CHECKING:
28
- from rich import get_console
29
- from rich.console import Console, RenderableType
30
- from rich.prompt import Prompt, Confirm
31
- from prompt_toolkit import prompt as pt_prompt
32
- from prompt_toolkit.completion import WordCompleter
33
- from .animations import (
34
- CLIFlashingAnimation,
35
- CLIPulsingAnimation,
36
- CLIShakingAnimation,
37
- CLITypingAnimation,
38
- CLISpinningAnimation,
39
- CLIRainbowAnimation,
40
- RainbowPreset,
41
- )
42
- from .styles.types import (
43
- CLIStyleType,
44
- CLIStyleBackgroundType,
45
- CLIStyleColorName,
46
- )
47
- from .styles.settings import (
48
- CLIStyleRenderableSettings,
49
- CLIStyleBackgroundSettings,
50
- CLIStyleLiveSettings,
51
- )
52
- from .styles.utils import (
53
- live_render,
54
- style_renderable,
55
- )
56
-
57
- # Lazy import cache
58
- _IMPORT_CACHE = {}
59
-
60
-
61
- def _get_rich_console():
62
- """Lazy import for rich.get_console"""
63
- if "get_console" not in _IMPORT_CACHE:
64
- from rich import get_console
65
-
66
- _IMPORT_CACHE["get_console"] = get_console
67
- return _IMPORT_CACHE["get_console"]
68
-
69
-
70
- def _get_rich_console_classes():
71
- """Lazy import for rich.console classes"""
72
- if "console_classes" not in _IMPORT_CACHE:
73
- from rich.console import Console, RenderableType
74
-
75
- _IMPORT_CACHE["console_classes"] = (Console, RenderableType)
76
- return _IMPORT_CACHE["console_classes"]
77
-
78
-
79
- def _get_rich_prompts():
80
- """Lazy import for rich.prompt classes"""
81
- if "prompts" not in _IMPORT_CACHE:
82
- from rich.prompt import Prompt, Confirm
83
-
84
- _IMPORT_CACHE["prompts"] = (Prompt, Confirm)
85
- return _IMPORT_CACHE["prompts"]
86
-
87
-
88
- def _get_prompt_toolkit():
89
- """Lazy import for prompt_toolkit"""
90
- if "prompt_toolkit" not in _IMPORT_CACHE:
91
- from prompt_toolkit import prompt as pt_prompt
92
- from prompt_toolkit.completion import WordCompleter
93
-
94
- _IMPORT_CACHE["prompt_toolkit"] = (pt_prompt, WordCompleter)
95
- return _IMPORT_CACHE["prompt_toolkit"]
96
-
97
-
98
- def _get_style_utils():
99
- """Lazy import for style utilities"""
100
- if "style_utils" not in _IMPORT_CACHE:
101
- from .styles.utils import live_render, style_renderable
102
-
103
- _IMPORT_CACHE["style_utils"] = (live_render, style_renderable)
104
- return _IMPORT_CACHE["style_utils"]
105
-
106
-
107
- def _get_animation_classes():
108
- """Lazy import for animation classes"""
109
- if "animations" not in _IMPORT_CACHE:
110
- from .animations import (
111
- CLIFlashingAnimation,
112
- CLIPulsingAnimation,
113
- CLIShakingAnimation,
114
- CLITypingAnimation,
115
- CLISpinningAnimation,
116
- CLIRainbowAnimation,
117
- RainbowPreset,
118
- )
119
-
120
- _IMPORT_CACHE["animations"] = {
121
- "CLIFlashingAnimation": CLIFlashingAnimation,
122
- "CLIPulsingAnimation": CLIPulsingAnimation,
123
- "CLIShakingAnimation": CLIShakingAnimation,
124
- "CLITypingAnimation": CLITypingAnimation,
125
- "CLISpinningAnimation": CLISpinningAnimation,
126
- "CLIRainbowAnimation": CLIRainbowAnimation,
127
- "RainbowPreset": RainbowPreset,
128
- }
129
- return _IMPORT_CACHE["animations"]
130
-
131
-
132
- @overload
133
- def print(
134
- *values: object,
135
- sep: str = " ",
136
- end: str = "\n",
137
- file: Optional[IO[str]] = None,
138
- flush: bool = False,
139
- ) -> None: ...
140
-
141
-
142
- @overload
143
- def print(
144
- *values: object,
145
- sep: str = " ",
146
- end: str = "\n",
147
- file: Optional[IO[str]] = None,
148
- flush: bool = False,
149
- style: "CLIStyleType | None" = None,
150
- style_settings: "CLIStyleRenderableSettings | None" = None,
151
- bg: "CLIStyleBackgroundType | None" = None,
152
- bg_settings: "CLIStyleBackgroundSettings | None" = None,
153
- live: "CLIStyleLiveSettings | int | None" = None,
154
- ) -> None: ...
155
-
156
-
157
- def print(
158
- *values: object,
159
- sep: str = " ",
160
- end: str = "\n",
161
- file: Optional[IO[str]] = None,
162
- flush: bool = False,
163
- style: "CLIStyleType | None" = None,
164
- style_settings: "CLIStyleRenderableSettings | None" = None,
165
- bg: "CLIStyleBackgroundType | None" = None,
166
- bg_settings: "CLIStyleBackgroundSettings | None" = None,
167
- live: "CLIStyleLiveSettings | int | None" = None,
168
- ) -> None:
169
- """
170
- Stylized print function built with `rich`. This method maintains
171
- all standard functionality of the print function, with no overhead
172
- unless the styled parameters are provided.
173
-
174
- Args:
175
- *values : The values to print.
176
- sep : The separator between values.
177
- end : The end character.
178
- file : The file to write to.
179
- flush : Whether to flush the file.
180
- style : A color or style name to apply to the content.
181
- style_settings : A dictionary of style settings to apply to the content.
182
- bg : A color or box name to apply to the background.
183
- bg_settings : A dictionary of background settings to apply to the content.
184
- live : A dictionary of live settings or an integer in seconds to run the print in a live renderable.
185
-
186
- NOTE: If `live` is set as an integer, transient is True.
187
-
188
- Returns:
189
- None
190
-
191
- Raises:
192
- PrintError : If the renderable is not a RenderableType.
193
- """
194
-
195
- # If no styling parameters are provided, use built-in print to avoid rich's default styling
196
- if (
197
- style is None
198
- and style_settings is None
199
- and bg is None
200
- and bg_settings is None
201
- and live is None
202
- ):
203
- builtins.print(*values, sep=sep, end=end, file=file, flush=flush)
204
- return
205
-
206
- # Convert values to string for styling
207
- content = sep.join(str(value) for value in values)
208
-
209
- # Apply styling and background
210
- live_render, style_renderable = _get_style_utils()
211
- styled_content = style_renderable(
212
- content,
213
- style=style,
214
- style_settings=style_settings,
215
- bg=bg,
216
- bg_settings=bg_settings,
217
- )
218
-
219
- # Handle live rendering
220
- if live is not None:
221
- if isinstance(live, int):
222
- # If live is an integer, treat it as duration in seconds
223
- from .styles.settings import CLIStyleLiveSettings
224
-
225
- live_settings: CLIStyleLiveSettings = {
226
- "duration": float(live),
227
- "transient": False, # Changed to False for testing
228
- }
229
- else:
230
- live_settings = live
231
-
232
- # For very short durations or testing, just print normally
233
- duration = live if isinstance(live, int) else live_settings.get("duration", 2.0)
234
- if duration <= 1:
235
- get_console = _get_rich_console()
236
- Console, _ = _get_rich_console_classes()
237
- console = get_console() if file is None else Console(file=file)
238
- console.print(styled_content, end=end)
239
- else:
240
- live_render(styled_content, live_settings)
241
- else:
242
- # Regular print with styling
243
- get_console = _get_rich_console()
244
- Console, _ = _get_rich_console_classes()
245
- console = get_console() if file is None else Console(file=file)
246
- console.print(styled_content, end=end)
247
-
248
-
249
- class InputError(Exception):
250
- """Exception raised for errors in the Input module."""
251
-
252
- def __init__(self, message: str) -> None:
253
- self.message = message
254
- super().__init__(self.message)
255
-
256
-
257
- def _validate_against_schema(value: str, schema: Any) -> Any:
258
- """Validate and convert input value against a schema.
259
-
260
- Args:
261
- value: The input value as a string.
262
- schema: The schema to validate against.
263
-
264
- Returns:
265
- The converted/validated value.
266
-
267
- Raises:
268
- InputError: If validation fails.
269
- """
270
- if schema is None:
271
- return value
272
-
273
- try:
274
- # Handle basic types
275
- if schema == str:
276
- return value
277
- elif schema == int:
278
- return int(value)
279
- elif schema == float:
280
- return float(value)
281
- elif schema == bool:
282
- return value.lower() in ("true", "t", "yes", "y", "1", "on")
283
-
284
- # Handle dict - expect JSON input
285
- elif schema == dict or (
286
- hasattr(schema, "__origin__") and schema.__origin__ is dict
287
- ):
288
- try:
289
- return json.loads(value)
290
- except json.JSONDecodeError:
291
- raise InputError(f"Invalid JSON format for dictionary input")
292
-
293
- # Handle list - expect JSON input
294
- elif schema == list or (
295
- hasattr(schema, "__origin__") and schema.__origin__ is list
296
- ):
297
- try:
298
- result = json.loads(value)
299
- if not isinstance(result, list):
300
- raise InputError("Expected a list")
301
- return result
302
- except json.JSONDecodeError:
303
- raise InputError(f"Invalid JSON format for list input")
304
-
305
- # Handle Union types (including Optional)
306
- elif hasattr(schema, "__origin__") and schema.__origin__ is Union:
307
- args = schema.__args__
308
- if len(args) == 2 and type(None) in args:
309
- # This is Optional[T]
310
- if not value or value.lower() == "none":
311
- return None
312
- non_none_type = args[0] if args[1] is type(None) else args[1]
313
- return _validate_against_schema(value, non_none_type)
314
-
315
- # Handle Pydantic models
316
- elif hasattr(schema, "model_validate_json"):
317
- try:
318
- return schema.model_validate_json(value)
319
- except Exception as e:
320
- raise InputError(f"Invalid input for {schema.__name__}: {e}")
321
-
322
- # Handle BasedModels
323
- elif hasattr(schema, "model_validate_json") or (
324
- hasattr(schema, "__bases__")
325
- and any("BasedModel" in str(base) for base in schema.__bases__)
326
- ):
327
- try:
328
- return schema.model_validate_json(value)
329
- except Exception as e:
330
- raise InputError(f"Invalid input for {schema.__name__}: {e}")
331
-
332
- # Handle dataclasses
333
- elif hasattr(schema, "__dataclass_fields__"):
334
- try:
335
- data = json.loads(value)
336
- return schema(**data)
337
- except Exception as e:
338
- raise InputError(f"Invalid input for {schema.__name__}: {e}")
339
-
340
- # Handle TypedDict
341
- elif hasattr(schema, "__annotations__") and hasattr(schema, "__total__"):
342
- try:
343
- return json.loads(value)
344
- except json.JSONDecodeError:
345
- raise InputError(f"Invalid JSON format for {schema.__name__}")
346
-
347
- # Fallback - try to parse as JSON
348
- else:
349
- try:
350
- return json.loads(value)
351
- except json.JSONDecodeError:
352
- return value
353
-
354
- except InputError:
355
- raise
356
- except Exception as e:
357
- raise InputError(f"Validation error: {e}")
358
-
359
-
360
- def _collect_fields_sequentially(schema: Any, console) -> Dict[str, Any]:
361
- """Collect field values sequentially for structured schemas.
362
-
363
- Args:
364
- schema: The schema to collect fields for.
365
- console: The console to use for output.
366
-
367
- Returns:
368
- Dictionary of field names to values.
369
- """
370
- result = {}
371
-
372
- try:
373
- # Handle Pydantic models
374
- if hasattr(schema, "model_fields"):
375
- fields_info = schema.model_fields
376
- console.print(
377
- f"\n[bold blue]Entering data for {schema.__name__}:[/bold blue]"
378
- )
379
-
380
- for field_name, field_info in fields_info.items():
381
- field_type = (
382
- field_info.annotation if hasattr(field_info, "annotation") else str
383
- )
384
- default = getattr(field_info, "default", None)
385
-
386
- prompt_text = f" {field_name}"
387
- if default is not None and default != "...":
388
- prompt_text += f" (default: {default})"
389
- prompt_text += ": "
390
-
391
- Prompt, _ = _get_rich_prompts()
392
- value = Prompt.ask(prompt_text)
393
- if not value and default is not None and default != "...":
394
- result[field_name] = default
395
- else:
396
- try:
397
- result[field_name] = _validate_against_schema(value, field_type)
398
- except InputError as e:
399
- console.print(f"[red]Error: {e}[/red]")
400
- result[field_name] = value
401
-
402
- # Handle BasedModels
403
- elif hasattr(schema, "_get_fields_info"):
404
- fields_info = schema._get_fields_info()
405
- console.print(
406
- f"\n[bold blue]Entering data for {schema.__name__}:[/bold blue]"
407
- )
408
-
409
- for field_name, field_info in fields_info.items():
410
- field_type = field_info.get("type", str)
411
- default = field_info.get("default")
412
- required = field_info.get("required", True)
413
-
414
- prompt_text = f" {field_name}"
415
- if not required and default is not None:
416
- prompt_text += f" (default: {default})"
417
- elif not required:
418
- prompt_text += " (optional)"
419
- prompt_text += ": "
420
-
421
- Prompt, _ = _get_rich_prompts()
422
- value = Prompt.ask(prompt_text)
423
- if not value and not required and default is not None:
424
- result[field_name] = default
425
- elif not value and not required:
426
- continue
427
- else:
428
- try:
429
- result[field_name] = _validate_against_schema(value, field_type)
430
- except InputError as e:
431
- console.print(f"[red]Error: {e}[/red]")
432
- result[field_name] = value
433
-
434
- # Handle dataclasses
435
- elif hasattr(schema, "__dataclass_fields__"):
436
- from ..typing import get_type_description
437
- import dataclasses
438
-
439
- fields_info = schema.__dataclass_fields__
440
- console.print(
441
- f"\n[bold blue]Entering data for {schema.__name__}:[/bold blue]"
442
- )
443
-
444
- for field_name, field_info in fields_info.items():
445
- field_type = field_info.type
446
- default = getattr(field_info, "default", None)
447
-
448
- prompt_text = f" {field_name}"
449
- if default is not None and default is not dataclasses.MISSING:
450
- prompt_text += f" (default: {default})"
451
- elif hasattr(field_type, "__name__"):
452
- prompt_text += f" ({field_type.__name__})"
453
- else:
454
- prompt_text += f" ({get_type_description(field_type)})"
455
- prompt_text += ""
456
-
457
- Prompt, _ = _get_rich_prompts()
458
- value = Prompt.ask(prompt_text)
459
- if (
460
- not value
461
- and default is not None
462
- and default is not dataclasses.MISSING
463
- ):
464
- result[field_name] = default
465
- else:
466
- try:
467
- result[field_name] = _validate_against_schema(value, field_type)
468
- except InputError as e:
469
- console.print(f"[red]Error: {e}[/red]")
470
- result[field_name] = value
471
-
472
- # Handle TypedDict
473
- elif hasattr(schema, "__annotations__"):
474
- annotations = getattr(schema, "__annotations__", {})
475
- console.print(
476
- f"\n[bold blue]Entering data for {schema.__name__}:[/bold blue]"
477
- )
478
-
479
- for field_name, field_type in annotations.items():
480
- prompt_text = f" {field_name}: "
481
- Prompt, _ = _get_rich_prompts()
482
- value = Prompt.ask(prompt_text)
483
-
484
- if value:
485
- try:
486
- result[field_name] = _validate_against_schema(value, field_type)
487
- except InputError as e:
488
- console.print(f"[red]Error: {e}[/red]")
489
- result[field_name] = value
490
-
491
- except Exception as e:
492
- console.print(f"[red]Error collecting fields: {e}[/red]")
493
-
494
- return result
495
-
496
-
497
- @overload
498
- def input(prompt: str = "") -> str: ...
499
-
500
-
501
- @overload
502
- def input(
503
- prompt: str = "",
504
- schema: Any = None,
505
- sequential: bool = True,
506
- style: "CLIStyleType | None" = None,
507
- style_settings: "CLIStyleRenderableSettings | None" = None,
508
- bg: "CLIStyleBackgroundType | None" = None,
509
- bg_settings: "CLIStyleBackgroundSettings | None" = None,
510
- multiline: bool = False,
511
- password: bool = False,
512
- complete: Optional[List[str]] = None,
513
- validate: Optional[callable] = None,
514
- ) -> Any: ...
515
-
516
-
517
- def input(
518
- prompt: str = "",
519
- schema: Any = None,
520
- sequential: bool = True,
521
- style: "CLIStyleType | None" = None,
522
- style_settings: "CLIStyleRenderableSettings | None" = None,
523
- bg: "CLIStyleBackgroundType | None" = None,
524
- bg_settings: "CLIStyleBackgroundSettings | None" = None,
525
- multiline: bool = False,
526
- password: bool = False,
527
- complete: Optional[List[str]] = None,
528
- validate: Optional[callable] = None,
529
- ) -> Any:
530
- """
531
- Stylized input function built with `rich` and `prompt_toolkit`. This method maintains
532
- compatibility with the standard input function while adding advanced features like
533
- schema validation, styling, and structured data input.
534
-
535
- Args:
536
- prompt: The prompt message to display.
537
- schema: A type, model class, or schema to validate against. Supports:
538
- - Basic types (str, int, float, bool)
539
- - Collections (dict, list)
540
- - Pydantic models
541
- - BasedModels
542
- - Dataclasses
543
- - TypedDict
544
- sequential: For schemas with multiple fields, request one field at a time.
545
- style: A color or dictionary of style settings to apply to the prompt.
546
- bg: A color or dictionary of background settings to apply to the prompt.
547
- multiline: Whether to allow multiline input.
548
- password: Whether to hide the input (password mode).
549
- complete: List of completion options.
550
- validate: Custom validation function.
551
-
552
- Returns:
553
- The validated input value, converted to the appropriate type based on schema.
554
-
555
- Raises:
556
- InputError: If validation fails or input is invalid.
557
- """
558
- get_console = _get_rich_console()
559
- console = get_console()
560
-
561
- try:
562
- # If no special features are requested, use built-in input for compatibility
563
- if (
564
- schema is None
565
- and style is None
566
- and style_settings is None
567
- and bg is None
568
- and bg_settings is None
569
- and not multiline
570
- and not password
571
- and complete is None
572
- and validate is None
573
- ):
574
- return builtins.input(prompt)
575
-
576
- # Apply styling to prompt if provided
577
- _, style_renderable = _get_style_utils()
578
- styled_prompt = style_renderable(
579
- prompt,
580
- style=style,
581
- style_settings=style_settings,
582
- bg=bg,
583
- bg_settings=bg_settings,
584
- )
585
-
586
- # Handle schema-based input
587
- if schema is not None:
588
- # Handle bool schema with Confirm.ask
589
- if schema == bool:
590
- Prompt, Confirm = _get_rich_prompts()
591
- return Confirm.ask(styled_prompt)
592
-
593
- # Handle structured schemas with multiple fields
594
- if sequential and (
595
- hasattr(schema, "__annotations__")
596
- or hasattr(schema, "model_fields")
597
- or hasattr(schema, "_get_fields_info")
598
- or hasattr(schema, "__dataclass_fields__")
599
- ):
600
- field_data = _collect_fields_sequentially(schema, console)
601
-
602
- try:
603
- # Create instance from collected data
604
- if hasattr(schema, "model_validate"):
605
- # Pydantic model
606
- return schema.model_validate(field_data)
607
- elif hasattr(schema, "__call__"):
608
- # BasedModel, dataclass, or other callable
609
- return schema(**field_data)
610
- else:
611
- # TypedDict or similar - return the dict
612
- return field_data
613
- except Exception as e:
614
- console.print(f"[red]Error creating {schema.__name__}: {e}[/red]")
615
- return field_data
616
-
617
- # Handle single value input
618
- Prompt, Confirm = _get_rich_prompts()
619
- if password:
620
- value = Prompt.ask(styled_prompt, password=True)
621
- elif complete:
622
- # Use prompt_toolkit for completion
623
- pt_prompt, WordCompleter = _get_prompt_toolkit()
624
- completer = WordCompleter(complete)
625
- value = pt_prompt(str(styled_prompt), completer=completer)
626
- elif multiline:
627
- console.print(styled_prompt, end="")
628
- lines = []
629
- console.print("[dim](Enter empty line to finish)[/dim]")
630
- pt_prompt, _ = _get_prompt_toolkit()
631
- while True:
632
- line = pt_prompt("... ")
633
- if not line:
634
- break
635
- lines.append(line)
636
- value = "\n".join(lines)
637
- else:
638
- # Regular input with Rich prompt
639
- value = Prompt.ask(styled_prompt)
640
-
641
- # Apply custom validation
642
- if validate:
643
- try:
644
- if not validate(value):
645
- raise InputError("Custom validation failed")
646
- except Exception as e:
647
- raise InputError(f"Validation error: {e}")
648
-
649
- # Apply schema validation
650
- if schema is not None:
651
- return _validate_against_schema(value, schema)
652
-
653
- return value
654
-
655
- except KeyboardInterrupt:
656
- console.print("\n[yellow]Input cancelled by user[/yellow]")
657
- raise
658
- except InputError:
659
- raise
660
- except Exception as e:
661
- raise InputError(f"Input error: {e}")
662
-
663
-
664
- def animate(
665
- renderable: "RenderableType | str",
666
- type: Literal["flashing", "pulsing", "shaking", "typing", "spinning", "rainbow"],
667
- duration: Optional[float] = None,
668
- # Flashing animation parameters
669
- speed: float = 0.5,
670
- colors: "Optional[List[CLIStyleColorName]]" = None,
671
- on_color: "CLIStyleColorName" = "white",
672
- off_color: "CLIStyleColorName" = "dim white",
673
- # Pulsing animation parameters
674
- min_opacity: float = 0.3,
675
- max_opacity: float = 1.0,
676
- color: "CLIStyleColorName" = "white",
677
- # Shaking animation parameters
678
- intensity: int = 1,
679
- # Typing animation parameters
680
- typing_speed: Optional[float] = None,
681
- cursor: str = "█",
682
- show_cursor: bool = True,
683
- # Spinning animation parameters
684
- frames: Optional[List[str]] = None,
685
- prefix: bool = True,
686
- # Rich.Live parameters
687
- refresh_rate: int = 20,
688
- transient: bool = True,
689
- auto_refresh: bool = True,
690
- console: Optional["Console"] = None,
691
- screen: bool = False,
692
- vertical_overflow: str = "ellipsis",
693
- ) -> None:
694
- """Create and run an animation based on the specified type.
695
-
696
- Args:
697
- renderable: The object to animate (text, panel, etc.)
698
- type: The type of animation to create
699
- duration: Duration of the animation in seconds (defaults to 2.0)
700
- speed: Animation speed (used by flashing, pulsing, shaking, spinning, rainbow)
701
- colors: Color list (used by flashing, rainbow)
702
- on_color: Color when flashing "on" (used by flashing)
703
- off_color: Color when flashing "off" (used by flashing)
704
- min_opacity: Minimum opacity for pulsing animation
705
- max_opacity: Maximum opacity for pulsing animation
706
- color: Color for pulsing animation
707
- intensity: Shaking intensity for shaking animation
708
- typing_speed: Speed for typing animation (used by typing)
709
- cursor: Cursor character for typing animation (used by typing)
710
- show_cursor: Whether to show cursor for typing animation (used by typing)
711
- frames: Custom frames for spinning animation
712
- prefix: Whether to show spinner as prefix for spinning animation
713
- refresh_rate: Refresh rate per second for Live rendering
714
- transient: Whether to clear animation after completion
715
- auto_refresh: Whether to auto-refresh the display
716
- console: Console to use for rendering
717
- screen: Whether to use alternate screen buffer
718
- vertical_overflow: How to handle vertical overflow
719
-
720
- Examples:
721
- >>> animate("Hello!", type="flashing", duration=3.0, speed=0.3)
722
- >>> animate(Panel("Loading"), type="pulsing", min_opacity=0.1)
723
- >>> animate("Hello World!", type="typing", typing_speed=0.1)
724
- >>> animate("Colorful!", type="rainbow", colors=["red", "blue"])
725
- """
726
- animations = _get_animation_classes()
727
-
728
- if type == "flashing":
729
- animation = animations["CLIFlashingAnimation"](
730
- renderable,
731
- speed=speed,
732
- colors=colors,
733
- on_color=on_color,
734
- off_color=off_color,
735
- duration=duration,
736
- )
737
- elif type == "pulsing":
738
- animation = animations["CLIPulsingAnimation"](
739
- renderable,
740
- speed=speed,
741
- min_opacity=min_opacity,
742
- max_opacity=max_opacity,
743
- color=color,
744
- duration=duration,
745
- )
746
- elif type == "shaking":
747
- animation = animations["CLIShakingAnimation"](
748
- renderable, intensity=intensity, speed=speed, duration=duration
749
- )
750
- elif type == "typing":
751
- animation = animations["CLITypingAnimation"](
752
- renderable,
753
- speed=speed,
754
- typing_speed=typing_speed,
755
- cursor=cursor,
756
- show_cursor=show_cursor,
757
- duration=duration,
758
- )
759
- elif type == "spinning":
760
- animation = animations["CLISpinningAnimation"](
761
- renderable, frames=frames, speed=speed, prefix=prefix, duration=duration
762
- )
763
- elif type == "rainbow":
764
- animation = animations["CLIRainbowAnimation"](
765
- renderable, speed=speed, colors=colors, duration=duration
766
- )
767
- else:
768
- raise ValueError(f"Unknown animation type: {type}")
769
-
770
- animation.animate(
771
- duration=duration,
772
- refresh_rate=refresh_rate,
773
- transient=transient,
774
- auto_refresh=auto_refresh,
775
- console=console,
776
- screen=screen,
777
- vertical_overflow=vertical_overflow,
778
- )
779
-
780
-
781
- __all__ = ("print", "input", "animate")