hammad-python 0.0.29__py3-none-any.whl → 0.0.31__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 (137) hide show
  1. ham/__init__.py +10 -0
  2. {hammad_python-0.0.29.dist-info → hammad_python-0.0.31.dist-info}/METADATA +6 -32
  3. hammad_python-0.0.31.dist-info/RECORD +6 -0
  4. hammad/__init__.py +0 -84
  5. hammad/_internal.py +0 -256
  6. hammad/_main.py +0 -226
  7. hammad/cache/__init__.py +0 -40
  8. hammad/cache/base_cache.py +0 -181
  9. hammad/cache/cache.py +0 -169
  10. hammad/cache/decorators.py +0 -261
  11. hammad/cache/file_cache.py +0 -80
  12. hammad/cache/ttl_cache.py +0 -74
  13. hammad/cli/__init__.py +0 -33
  14. hammad/cli/animations.py +0 -573
  15. hammad/cli/plugins.py +0 -867
  16. hammad/cli/styles/__init__.py +0 -55
  17. hammad/cli/styles/settings.py +0 -139
  18. hammad/cli/styles/types.py +0 -358
  19. hammad/cli/styles/utils.py +0 -634
  20. hammad/data/__init__.py +0 -90
  21. hammad/data/collections/__init__.py +0 -49
  22. hammad/data/collections/collection.py +0 -326
  23. hammad/data/collections/indexes/__init__.py +0 -37
  24. hammad/data/collections/indexes/qdrant/__init__.py +0 -1
  25. hammad/data/collections/indexes/qdrant/index.py +0 -723
  26. hammad/data/collections/indexes/qdrant/settings.py +0 -94
  27. hammad/data/collections/indexes/qdrant/utils.py +0 -210
  28. hammad/data/collections/indexes/tantivy/__init__.py +0 -1
  29. hammad/data/collections/indexes/tantivy/index.py +0 -426
  30. hammad/data/collections/indexes/tantivy/settings.py +0 -40
  31. hammad/data/collections/indexes/tantivy/utils.py +0 -176
  32. hammad/data/configurations/__init__.py +0 -35
  33. hammad/data/configurations/configuration.py +0 -564
  34. hammad/data/models/__init__.py +0 -50
  35. hammad/data/models/extensions/__init__.py +0 -4
  36. hammad/data/models/extensions/pydantic/__init__.py +0 -42
  37. hammad/data/models/extensions/pydantic/converters.py +0 -759
  38. hammad/data/models/fields.py +0 -546
  39. hammad/data/models/model.py +0 -1078
  40. hammad/data/models/utils.py +0 -280
  41. hammad/data/sql/__init__.py +0 -24
  42. hammad/data/sql/database.py +0 -576
  43. hammad/data/sql/types.py +0 -127
  44. hammad/data/types/__init__.py +0 -75
  45. hammad/data/types/file.py +0 -431
  46. hammad/data/types/multimodal/__init__.py +0 -36
  47. hammad/data/types/multimodal/audio.py +0 -200
  48. hammad/data/types/multimodal/image.py +0 -182
  49. hammad/data/types/text.py +0 -1308
  50. hammad/formatting/__init__.py +0 -33
  51. hammad/formatting/json/__init__.py +0 -27
  52. hammad/formatting/json/converters.py +0 -158
  53. hammad/formatting/text/__init__.py +0 -63
  54. hammad/formatting/text/converters.py +0 -723
  55. hammad/formatting/text/markdown.py +0 -131
  56. hammad/formatting/yaml/__init__.py +0 -26
  57. hammad/formatting/yaml/converters.py +0 -5
  58. hammad/genai/__init__.py +0 -217
  59. hammad/genai/a2a/__init__.py +0 -32
  60. hammad/genai/a2a/workers.py +0 -552
  61. hammad/genai/agents/__init__.py +0 -59
  62. hammad/genai/agents/agent.py +0 -1973
  63. hammad/genai/agents/run.py +0 -1024
  64. hammad/genai/agents/types/__init__.py +0 -42
  65. hammad/genai/agents/types/agent_context.py +0 -13
  66. hammad/genai/agents/types/agent_event.py +0 -128
  67. hammad/genai/agents/types/agent_hooks.py +0 -220
  68. hammad/genai/agents/types/agent_messages.py +0 -31
  69. hammad/genai/agents/types/agent_response.py +0 -125
  70. hammad/genai/agents/types/agent_stream.py +0 -327
  71. hammad/genai/graphs/__init__.py +0 -125
  72. hammad/genai/graphs/_utils.py +0 -190
  73. hammad/genai/graphs/base.py +0 -1828
  74. hammad/genai/graphs/plugins.py +0 -316
  75. hammad/genai/graphs/types.py +0 -638
  76. hammad/genai/models/__init__.py +0 -1
  77. hammad/genai/models/embeddings/__init__.py +0 -43
  78. hammad/genai/models/embeddings/model.py +0 -226
  79. hammad/genai/models/embeddings/run.py +0 -163
  80. hammad/genai/models/embeddings/types/__init__.py +0 -37
  81. hammad/genai/models/embeddings/types/embedding_model_name.py +0 -75
  82. hammad/genai/models/embeddings/types/embedding_model_response.py +0 -76
  83. hammad/genai/models/embeddings/types/embedding_model_run_params.py +0 -66
  84. hammad/genai/models/embeddings/types/embedding_model_settings.py +0 -47
  85. hammad/genai/models/language/__init__.py +0 -57
  86. hammad/genai/models/language/model.py +0 -1098
  87. hammad/genai/models/language/run.py +0 -878
  88. hammad/genai/models/language/types/__init__.py +0 -40
  89. hammad/genai/models/language/types/language_model_instructor_mode.py +0 -47
  90. hammad/genai/models/language/types/language_model_messages.py +0 -28
  91. hammad/genai/models/language/types/language_model_name.py +0 -239
  92. hammad/genai/models/language/types/language_model_request.py +0 -127
  93. hammad/genai/models/language/types/language_model_response.py +0 -217
  94. hammad/genai/models/language/types/language_model_response_chunk.py +0 -56
  95. hammad/genai/models/language/types/language_model_settings.py +0 -89
  96. hammad/genai/models/language/types/language_model_stream.py +0 -600
  97. hammad/genai/models/language/utils/__init__.py +0 -28
  98. hammad/genai/models/language/utils/requests.py +0 -421
  99. hammad/genai/models/language/utils/structured_outputs.py +0 -135
  100. hammad/genai/models/model_provider.py +0 -4
  101. hammad/genai/models/multimodal.py +0 -47
  102. hammad/genai/models/reranking.py +0 -26
  103. hammad/genai/types/__init__.py +0 -1
  104. hammad/genai/types/base.py +0 -215
  105. hammad/genai/types/history.py +0 -290
  106. hammad/genai/types/tools.py +0 -507
  107. hammad/logging/__init__.py +0 -35
  108. hammad/logging/decorators.py +0 -834
  109. hammad/logging/logger.py +0 -1018
  110. hammad/mcp/__init__.py +0 -53
  111. hammad/mcp/client/__init__.py +0 -35
  112. hammad/mcp/client/client.py +0 -624
  113. hammad/mcp/client/client_service.py +0 -400
  114. hammad/mcp/client/settings.py +0 -178
  115. hammad/mcp/servers/__init__.py +0 -26
  116. hammad/mcp/servers/launcher.py +0 -1161
  117. hammad/runtime/__init__.py +0 -32
  118. hammad/runtime/decorators.py +0 -142
  119. hammad/runtime/run.py +0 -299
  120. hammad/service/__init__.py +0 -49
  121. hammad/service/create.py +0 -527
  122. hammad/service/decorators.py +0 -283
  123. hammad/types.py +0 -288
  124. hammad/typing/__init__.py +0 -435
  125. hammad/web/__init__.py +0 -43
  126. hammad/web/http/__init__.py +0 -1
  127. hammad/web/http/client.py +0 -944
  128. hammad/web/models.py +0 -275
  129. hammad/web/openapi/__init__.py +0 -1
  130. hammad/web/openapi/client.py +0 -740
  131. hammad/web/search/__init__.py +0 -1
  132. hammad/web/search/client.py +0 -1023
  133. hammad/web/utils.py +0 -472
  134. hammad_python-0.0.29.dist-info/RECORD +0 -135
  135. {hammad → ham}/py.typed +0 -0
  136. {hammad_python-0.0.29.dist-info → hammad_python-0.0.31.dist-info}/WHEEL +0 -0
  137. {hammad_python-0.0.29.dist-info → hammad_python-0.0.31.dist-info}/licenses/LICENSE +0 -0
hammad/cache/ttl_cache.py DELETED
@@ -1,74 +0,0 @@
1
- """hammad.cache.ttl_cache"""
2
-
3
- from dataclasses import dataclass
4
- from typing import Any, Literal, OrderedDict, Tuple
5
- import time
6
-
7
- from .base_cache import BaseCache
8
-
9
- __all__ = ("TTLCache",)
10
-
11
-
12
- @dataclass
13
- class TTLCache(BaseCache):
14
- """
15
- Thread-safe TTL cache implementation with LRU eviction.
16
-
17
- Uses OrderedDict for efficient LRU tracking and automatic cleanup
18
- of expired entries on access.
19
- """
20
-
21
- maxsize: int = 1000
22
- ttl: int = 3600
23
- type: Literal["ttl"] = "ttl"
24
-
25
- def __post_init__(self):
26
- """Initialize TTL cache after dataclass initialization."""
27
- super().__post_init__()
28
- self._cache: OrderedDict[str, Tuple[Any, float]] = OrderedDict()
29
-
30
- def __contains__(self, key: str) -> bool:
31
- """Check if key exists and is not expired."""
32
- if key in self._cache:
33
- _value, timestamp = self._cache[key]
34
- if time.time() - timestamp <= self.ttl:
35
- self._cache.move_to_end(key)
36
- return True
37
- else:
38
- # Expired, remove it
39
- del self._cache[key]
40
- return False
41
-
42
- def __getitem__(self, key: str) -> Any:
43
- """Get value for key if not expired."""
44
- if key in self:
45
- return self._cache[key][0]
46
- raise KeyError(key)
47
-
48
- def __setitem__(self, key: str, value: Any) -> None:
49
- """Set value with current timestamp."""
50
- if len(self._cache) >= self.maxsize and key not in self._cache:
51
- self._cleanup_expired()
52
-
53
- if len(self._cache) >= self.maxsize:
54
- self._cache.popitem(last=False)
55
-
56
- self._cache[key] = (value, time.time())
57
- self._cache.move_to_end(key)
58
-
59
- def _cleanup_expired(self) -> None:
60
- """Remove all expired entries."""
61
- current_time = time.time()
62
-
63
- expired_keys = [
64
- k
65
- for k, (_, ts) in list(self._cache.items())
66
- if current_time - ts > self.ttl
67
- ]
68
- for k in expired_keys:
69
- if k in self._cache:
70
- del self._cache[k]
71
-
72
- def clear(self) -> None:
73
- """Clear all cached items."""
74
- self._cache.clear()
hammad/cli/__init__.py DELETED
@@ -1,33 +0,0 @@
1
- """hammad.cli
2
-
3
- Contains resources for styling rendered CLI content as well
4
- as extensions / utilities for creating CLI interfaces."""
5
-
6
- from typing import TYPE_CHECKING
7
- from .._internal import create_getattr_importer
8
-
9
- if TYPE_CHECKING:
10
- from .plugins import print, input, animate
11
- from .styles.settings import (
12
- CLIStyleRenderableSettings,
13
- CLIStyleBackgroundSettings,
14
- CLIStyleLiveSettings,
15
- )
16
-
17
-
18
- __all__ = (
19
- "print",
20
- "input",
21
- "animate",
22
- "CLIStyleRenderableSettings",
23
- "CLIStyleBackgroundSettings",
24
- "CLIStyleLiveSettings",
25
- )
26
-
27
-
28
- __getattr__ = create_getattr_importer(__all__)
29
-
30
-
31
- def __dir__() -> list[str]:
32
- """Get the attributes of the plugins module."""
33
- return list(__all__)
hammad/cli/animations.py DELETED
@@ -1,573 +0,0 @@
1
- """hammad.cli.animations"""
2
-
3
- import time
4
- import math
5
- import random
6
- import threading
7
- from dataclasses import dataclass, field
8
- from typing import Literal, Optional, List, overload, TYPE_CHECKING
9
-
10
- from rich import get_console
11
- from rich.console import Console, ConsoleOptions, RenderResult, RenderableType
12
- from rich.live import Live
13
- from rich.text import Text
14
- from rich.panel import Panel
15
-
16
- from .styles.types import (
17
- CLIStyleColorName,
18
- )
19
-
20
-
21
- __all__ = (
22
- "CLIAnimation",
23
- "CLIAnimationState",
24
- "CLIFlashingAnimation",
25
- "CLIPulsingAnimation",
26
- "CLIShakingAnimation",
27
- "CLITypingAnimation",
28
- "CLISpinningAnimation",
29
- "CLIRainbowAnimation",
30
- "animate_flashing",
31
- "animate_pulsing",
32
- "animate_shaking",
33
- "animate_spinning",
34
- "animate_rainbow",
35
- "animate_typing",
36
- )
37
-
38
-
39
- @dataclass
40
- class CLIAnimationState:
41
- """Internal class used to track the current state of an
42
- animation."""
43
-
44
- start_time: float = field(default_factory=time.time)
45
- frame: int = 0
46
- last_update: float | None = field(default_factory=time.time)
47
-
48
-
49
- @dataclass
50
- class CLIAnimation:
51
- """Base class for all animations within the `hammad` package,
52
- this is used to integrate with rich's `__rich_console__` protocol."""
53
-
54
- def __init__(
55
- self,
56
- # The object that this animation is being applied to.
57
- renderable,
58
- duration: Optional[float] = None,
59
- ) -> None:
60
- self.renderable = renderable
61
- """The object that this animation is being applied to."""
62
- self.duration = duration or 2.0
63
- """The duration of the animation in seconds (defaults to 2.0 seconds)."""
64
- # Set last_update to None to ensure the animation is classified as
65
- # the first update on init.
66
- self.state = CLIAnimationState(last_update=None)
67
- """The current state of the animation."""
68
-
69
- self.rich_console = get_console()
70
- """The rich console responsible for rendering the animation."""
71
- self._animation_thread: threading.Thread | None = None
72
- """The thread responsible for running the animation."""
73
- self._stop_animation = False
74
- """Flag used to stop the animation."""
75
-
76
- def __rich_console__(
77
- self,
78
- console,
79
- options,
80
- ):
81
- """Rich will call this automatically when rendering."""
82
- if not self.is_complete:
83
- console.force_terminal = True
84
- if console.is_terminal:
85
- # force referesh
86
- console._is_alt_screen = False
87
-
88
- current_time = time.time()
89
- self.state.frame += 1
90
- self.state.last_update = current_time
91
-
92
- yield from self.apply(console, options)
93
-
94
- def apply(self, console, options):
95
- """Used by subclasses to apply the animation."""
96
- yield self.renderable
97
-
98
- @property
99
- def time_elapsed(self) -> float:
100
- """Time elapsed since the animation started."""
101
- return time.time() - self.state.start_time
102
-
103
- @property
104
- def is_complete(self) -> bool:
105
- """Check if the animation is complete."""
106
- if self.duration is None:
107
- return False
108
- return self.time_elapsed >= self.duration
109
-
110
- def animate(
111
- self,
112
- duration: Optional[float] = None,
113
- refresh_rate: int = 20,
114
- transient: bool = True,
115
- auto_refresh: bool = True,
116
- console: Optional["Console"] = None,
117
- screen: bool = False,
118
- vertical_overflow: str = "ellipsis",
119
- ) -> None:
120
- """Animate this effect for the specified duration using Live."""
121
- animate_duration = duration or self.duration or 3.0
122
-
123
- # Use provided console or create new one
124
- live_console = console or get_console()
125
-
126
- with Live(
127
- self,
128
- console=live_console,
129
- refresh_per_second=refresh_rate,
130
- transient=transient,
131
- auto_refresh=auto_refresh,
132
- screen=screen,
133
- vertical_overflow=vertical_overflow,
134
- ) as live:
135
- start = time.time()
136
- while time.time() - start < animate_duration:
137
- time.sleep(0.05)
138
-
139
-
140
- class CLIFlashingAnimation(CLIAnimation):
141
- """Makes any renderable flash/blink."""
142
-
143
- def __init__(
144
- self,
145
- renderable,
146
- speed: float = 0.5,
147
- colors: Optional[List[CLIStyleColorName]] = None,
148
- on_color: CLIStyleColorName = "white",
149
- off_color: CLIStyleColorName = "dim white",
150
- duration: Optional[float] = None,
151
- ):
152
- super().__init__(renderable, duration)
153
- self.speed = speed
154
- # If colors is provided, use it; otherwise use on_color/off_color
155
- if colors is not None:
156
- self.colors = colors
157
- else:
158
- self.colors = [on_color, off_color]
159
-
160
- def apply(self, console, options):
161
- # Calculate which color to use based on time
162
- color_index = int(self.time_elapsed / self.speed) % len(self.colors)
163
- color = self.colors[color_index]
164
-
165
- # Apply color to the renderable
166
- if isinstance(self.renderable, str):
167
- yield Text(self.renderable, style=color)
168
- else:
169
- # Wrap any renderable in the flash color
170
- yield Text.from_markup(f"[{color}]{self.renderable}[/{color}]")
171
-
172
-
173
- class CLIPulsingAnimation(CLIAnimation):
174
- """Makes any renderable pulse/breathe."""
175
-
176
- def __init__(
177
- self,
178
- renderable: "RenderableType",
179
- speed: float = 2.0,
180
- min_opacity: float = 0.3,
181
- max_opacity: float = 1.0,
182
- color: "CLIStyleColorName" = "white",
183
- duration: Optional[float] = None,
184
- ):
185
- super().__init__(renderable, duration)
186
- self.speed = speed
187
- self.min_opacity = min_opacity
188
- self.max_opacity = max_opacity
189
- self.color = color
190
-
191
- def apply(self, console: "Console", options: "ConsoleOptions") -> "RenderResult":
192
- # Calculate opacity using sine wave
193
- opacity = self.min_opacity + (self.max_opacity - self.min_opacity) * (
194
- 0.5 + 0.5 * math.sin(self.time_elapsed * self.speed)
195
- )
196
-
197
- # Convert opacity to RGB values for fading effect
198
- rgb_value = int(opacity * 255)
199
- fade_color = f"rgb({rgb_value},{rgb_value},{rgb_value})"
200
-
201
- if isinstance(self.renderable, str):
202
- yield Text(self.renderable, style=fade_color)
203
- else:
204
- # For Panel and other renderables, we need to use opacity styling
205
- if isinstance(self.renderable, Panel):
206
- # Create a new panel with modified style
207
- new_panel = Panel(
208
- self.renderable.renderable,
209
- title=self.renderable.title,
210
- title_align=self.renderable.title_align,
211
- subtitle=self.renderable.subtitle,
212
- subtitle_align=self.renderable.subtitle_align,
213
- box=self.renderable.box,
214
- style=fade_color,
215
- border_style=fade_color,
216
- expand=self.renderable.expand,
217
- padding=self.renderable.padding,
218
- width=self.renderable.width,
219
- height=self.renderable.height,
220
- )
221
- yield new_panel
222
- else:
223
- # For other renderables, wrap in a panel with the fade effect
224
- yield Panel(self.renderable, style=fade_color, border_style=fade_color)
225
-
226
-
227
- class CLIShakingAnimation(CLIAnimation):
228
- """Makes text shake/jitter."""
229
-
230
- def __init__(
231
- self,
232
- renderable: "RenderableType",
233
- intensity: int = 1,
234
- speed: float = 0.1,
235
- duration: Optional[float] = None,
236
- ):
237
- super().__init__(renderable, duration)
238
- self.intensity = intensity
239
- self.speed = speed
240
- self.last_shake = 0
241
-
242
- def apply(self, console: "Console", options: "ConsoleOptions") -> "RenderResult":
243
- if self.time_elapsed - self.last_shake > self.speed:
244
- self.last_shake = self.time_elapsed
245
-
246
- # Add random spaces for shake effect
247
- shake = " " * random.randint(0, self.intensity)
248
-
249
- if isinstance(self.renderable, str):
250
- yield Text(shake + self.renderable)
251
- else:
252
- yield Text(shake) + self.renderable
253
- else:
254
- # Keep previous position
255
- yield self.renderable
256
-
257
-
258
- class CLITypingAnimation(CLIAnimation):
259
- """Typewriter effect."""
260
-
261
- def __init__(
262
- self,
263
- text: str,
264
- speed: float = 0.05,
265
- typing_speed: Optional[float] = None,
266
- cursor: str = "█",
267
- show_cursor: bool = True,
268
- duration: Optional[float] = None,
269
- ):
270
- super().__init__(text, duration)
271
- self.text = text
272
- # Use typing_speed if provided, otherwise use speed
273
- self.speed = typing_speed if typing_speed is not None else speed
274
- self.cursor = cursor
275
- self.show_cursor = show_cursor
276
-
277
- def apply(self, console: "Console", options: "ConsoleOptions") -> "RenderResult":
278
- # Calculate how many characters to show
279
- chars_to_show = int(self.time_elapsed / self.speed)
280
- chars_to_show = min(chars_to_show, len(self.text))
281
-
282
- if chars_to_show < len(self.text):
283
- # Still typing - show cursor if enabled
284
- text_content = self.text[:chars_to_show]
285
- if self.show_cursor:
286
- text_content += self.cursor
287
- yield Text(text_content)
288
- else:
289
- # Finished typing - show complete text without cursor
290
- yield Text(self.text)
291
-
292
-
293
- class CLISpinningAnimation(CLIAnimation):
294
- """Spinner effect for any renderable."""
295
-
296
- def __init__(
297
- self,
298
- renderable: "RenderableType",
299
- frames: Optional[List[str]] = None,
300
- speed: float = 0.1,
301
- prefix: bool = True,
302
- duration: Optional[float] = None,
303
- ):
304
- super().__init__(renderable, duration)
305
- self.frames = frames or ["⋅", "•", "●", "◉", "●", "•"]
306
- self.speed = speed
307
- self.prefix = prefix
308
-
309
- def apply(self, console: "Console", options: "ConsoleOptions") -> "RenderResult":
310
- frame_index = int(self.time_elapsed / self.speed) % len(self.frames)
311
- spinner = self.frames[frame_index]
312
-
313
- if isinstance(self.renderable, str):
314
- if self.prefix:
315
- yield Text(f"{spinner} {self.renderable}")
316
- else:
317
- yield Text(f"{self.renderable} {spinner}")
318
- else:
319
- if self.prefix:
320
- yield Text(f"{spinner} ") + self.renderable
321
- else:
322
- yield self.renderable + Text(f" {spinner}")
323
-
324
-
325
- RainbowPreset = Literal["classic", "bright", "pastel", "neon"]
326
-
327
- RAINBOW_PRESETS = {
328
- "classic": ["red", "yellow", "green", "cyan", "blue", "magenta"],
329
- "bright": [
330
- "bright_red",
331
- "bright_yellow",
332
- "bright_green",
333
- "bright_cyan",
334
- "bright_blue",
335
- "bright_magenta",
336
- ],
337
- "pastel": [
338
- "light_pink3",
339
- "khaki1",
340
- "light_green",
341
- "light_cyan1",
342
- "light_blue",
343
- "plum2",
344
- ],
345
- "neon": ["hot_pink", "yellow1", "green1", "cyan1", "blue1", "magenta1"],
346
- }
347
-
348
-
349
- class CLIRainbowAnimation(CLIAnimation):
350
- """Rainbow color cycling effect."""
351
-
352
- def __init__(
353
- self,
354
- renderable: "RenderableType",
355
- speed: float = 0.5,
356
- colors: "RainbowPreset | List[CLIStyleColorName] | None" = None,
357
- duration: Optional[float] = None,
358
- ):
359
- super().__init__(renderable, duration)
360
- self.speed = speed
361
-
362
- # Handle color selection
363
- if colors is None:
364
- colors = "classic"
365
-
366
- if isinstance(colors, str) and colors in RAINBOW_PRESETS:
367
- self.colors = RAINBOW_PRESETS[colors]
368
- elif isinstance(colors, list):
369
- self.colors = colors
370
- else:
371
- self.colors = RAINBOW_PRESETS["classic"]
372
-
373
- def apply(self, console: "Console", options: "ConsoleOptions") -> "RenderResult":
374
- if isinstance(self.renderable, str):
375
- # Apply rainbow to each character
376
- result = Text()
377
- for i, char in enumerate(self.renderable):
378
- color_offset = int(
379
- (self.time_elapsed / self.speed + i) % len(self.colors)
380
- )
381
- color = self.colors[color_offset]
382
- result.append(char, style=color)
383
- yield result
384
- else:
385
- # Cycle through colors for the whole renderable
386
- color_index = int(self.time_elapsed / self.speed) % len(self.colors)
387
- yield Text.from_markup(
388
- f"[{self.colors[color_index]}]{self.renderable}[/{self.colors[color_index]}]"
389
- )
390
-
391
-
392
- def animate_flashing(
393
- renderable: "RenderableType",
394
- duration: Optional[float] = None,
395
- speed: float = 0.5,
396
- on_color: CLIStyleColorName = "white",
397
- off_color: CLIStyleColorName = "dim white",
398
- refresh_rate: int = 20,
399
- transient: bool = True,
400
- ) -> None:
401
- """Create and run a flashing animation on any renderable.
402
-
403
- Args:
404
- renderable: The object to animate (text, panel, etc.)
405
- duration: Duration of the animation in seconds (defaults to 2.0)
406
- speed: Speed of the flashing effect (defaults to 0.5)
407
- on_color: Color when flashing "on" (defaults to "white")
408
- off_color: Color when flashing "off" (defaults to "dim white")
409
- refresh_rate: Refresh rate per second (defaults to 20)
410
- transient: Whether to clear animation after completion (defaults to True)
411
-
412
- Examples:
413
- >>> animate_flashing("Alert!", duration=3.0, speed=0.3)
414
- >>> animate_flashing(Panel("Warning"), on_color="red", off_color="dark_red")
415
- """
416
- animation = CLIFlashingAnimation(
417
- renderable,
418
- duration=duration,
419
- speed=speed,
420
- on_color=on_color,
421
- off_color=off_color,
422
- )
423
- animation.animate(duration=duration, refresh_rate=refresh_rate)
424
-
425
-
426
- def animate_pulsing(
427
- renderable: "RenderableType",
428
- duration: Optional[float] = None,
429
- speed: float = 1.0,
430
- min_opacity: float = 0.3,
431
- max_opacity: float = 1.0,
432
- refresh_rate: int = 20,
433
- transient: bool = True,
434
- ) -> None:
435
- """Create and run a pulsing animation on any renderable.
436
-
437
- Args:
438
- renderable: The object to animate (text, panel, etc.)
439
- duration: Duration of the animation in seconds (defaults to 2.0)
440
- speed: Speed of the pulsing effect (defaults to 1.0)
441
- min_opacity: Minimum opacity during pulse (defaults to 0.3)
442
- max_opacity: Maximum opacity during pulse (defaults to 1.0)
443
- refresh_rate: Refresh rate per second (defaults to 20)
444
- transient: Whether to clear animation after completion (defaults to True)
445
-
446
- Examples:
447
- >>> animate_pulsing("Loading...", duration=5.0, speed=2.0)
448
- >>> animate_pulsing(Panel("Status"), min_opacity=0.1, max_opacity=0.9)
449
- """
450
- animation = CLIPulsingAnimation(
451
- renderable,
452
- duration=duration,
453
- speed=speed,
454
- min_opacity=min_opacity,
455
- max_opacity=max_opacity,
456
- )
457
- animation.animate(duration=duration, refresh_rate=refresh_rate)
458
-
459
-
460
- def animate_shaking(
461
- renderable: "RenderableType",
462
- duration: Optional[float] = None,
463
- intensity: int = 2,
464
- speed: float = 10.0,
465
- refresh_rate: int = 20,
466
- transient: bool = True,
467
- ) -> None:
468
- """Create and run a shaking animation on any renderable.
469
-
470
- Args:
471
- renderable: The object to animate (text, panel, etc.)
472
- duration: Duration of the animation in seconds (defaults to 2.0)
473
- intensity: Intensity of the shake effect (defaults to 2)
474
- speed: Speed of the shaking motion (defaults to 10.0)
475
- refresh_rate: Refresh rate per second (defaults to 20)
476
- transient: Whether to clear animation after completion (defaults to True)
477
-
478
- Examples:
479
- >>> animate_shaking("Error!", duration=1.5, intensity=3)
480
- >>> animate_shaking(Panel("Critical Alert"), speed=15.0)
481
- """
482
- animation = CLIShakingAnimation(
483
- renderable, duration=duration, intensity=intensity, speed=speed
484
- )
485
- animation.animate(duration=duration, refresh_rate=refresh_rate)
486
-
487
-
488
- def animate_spinning(
489
- renderable: "RenderableType",
490
- duration: Optional[float] = None,
491
- frames: Optional[List[str]] = None,
492
- speed: float = 0.1,
493
- prefix: bool = True,
494
- refresh_rate: int = 20,
495
- transient: bool = True,
496
- ) -> None:
497
- """Create and run a spinning animation on any renderable.
498
-
499
- Args:
500
- renderable: The object to animate (text, panel, etc.)
501
- duration: Duration of the animation in seconds (defaults to 2.0)
502
- frames: List of spinner frames (defaults to ["⋅", "•", "●", "◉", "●", "•"])
503
- speed: Speed between frame changes (defaults to 0.1)
504
- prefix: Whether to show spinner before text (defaults to True)
505
- refresh_rate: Refresh rate per second (defaults to 20)
506
- transient: Whether to clear animation after completion (defaults to True)
507
-
508
- Examples:
509
- >>> animate_spinning("Processing...", duration=10.0, speed=0.2)
510
- >>> animate_spinning("Done", frames=["◐", "◓", "◑", "◒"], prefix=False)
511
- """
512
- animation = CLISpinningAnimation(
513
- renderable, duration=duration, frames=frames, speed=speed, prefix=prefix
514
- )
515
- animation.animate(duration=duration, refresh_rate=refresh_rate)
516
-
517
-
518
- def animate_rainbow(
519
- renderable: "RenderableType",
520
- duration: Optional[float] = None,
521
- speed: float = 0.5,
522
- refresh_rate: int = 20,
523
- transient: bool = True,
524
- ) -> None:
525
- """Create and run a rainbow animation on any renderable.
526
-
527
- Args:
528
- renderable: The object to animate (text, panel, etc.)
529
- duration: Duration of the animation in seconds (defaults to 2.0)
530
- speed: Speed of the color cycling effect (defaults to 0.5)
531
- refresh_rate: Refresh rate per second (defaults to 20)
532
- transient: Whether to clear animation after completion (defaults to True)
533
-
534
- Examples:
535
- >>> animate_rainbow("Colorful Text!", duration=4.0, speed=1.0)
536
- >>> animate_rainbow(Panel("Rainbow Panel"), speed=0.3)
537
- """
538
- animation = CLIRainbowAnimation(renderable, duration=duration, speed=speed)
539
- animation.animate(duration=duration, refresh_rate=refresh_rate)
540
-
541
-
542
- def animate_typing(
543
- text: str,
544
- duration: Optional[float] = None,
545
- typing_speed: float = 0.05,
546
- cursor: str = "▌",
547
- show_cursor: bool = True,
548
- refresh_rate: int = 20,
549
- transient: bool = True,
550
- ) -> None:
551
- """Create and run a typewriter animation.
552
-
553
- Args:
554
- text: The text to type out
555
- duration: Duration of the animation in seconds (defaults to 2.0)
556
- typing_speed: Speed between character reveals (defaults to 0.05)
557
- cursor: Cursor character to show (defaults to "▌")
558
- show_cursor: Whether to show the typing cursor (defaults to True)
559
- refresh_rate: Refresh rate per second (defaults to 20)
560
- transient: Whether to clear animation after completion (defaults to True)
561
-
562
- Examples:
563
- >>> animate_typing("Hello, World!", typing_speed=0.1)
564
- >>> animate_typing("Fast typing", duration=1.0, cursor="|", show_cursor=False)
565
- """
566
- animation = CLITypingAnimation(
567
- text,
568
- duration=duration,
569
- typing_speed=typing_speed,
570
- cursor=cursor,
571
- show_cursor=show_cursor,
572
- )
573
- animation.animate(duration=duration, refresh_rate=refresh_rate)