hammad-python 0.0.10__py3-none-any.whl → 0.0.12__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 (96) hide show
  1. hammad/__init__.py +177 -10
  2. hammad/_core/__init__.py +1 -0
  3. hammad/_core/_utils/__init__.py +4 -0
  4. hammad/_core/_utils/_import_utils.py +182 -0
  5. hammad/ai/__init__.py +59 -0
  6. hammad/ai/_utils.py +142 -0
  7. hammad/ai/completions/__init__.py +44 -0
  8. hammad/ai/completions/client.py +729 -0
  9. hammad/ai/completions/create.py +686 -0
  10. hammad/ai/completions/types.py +711 -0
  11. hammad/ai/completions/utils.py +374 -0
  12. hammad/ai/embeddings/__init__.py +35 -0
  13. hammad/ai/embeddings/client/__init__.py +1 -0
  14. hammad/ai/embeddings/client/base_embeddings_client.py +26 -0
  15. hammad/ai/embeddings/client/fastembed_text_embeddings_client.py +200 -0
  16. hammad/ai/embeddings/client/litellm_embeddings_client.py +288 -0
  17. hammad/ai/embeddings/create.py +159 -0
  18. hammad/ai/embeddings/types.py +69 -0
  19. hammad/base/__init__.py +35 -0
  20. hammad/base/fields.py +546 -0
  21. hammad/base/model.py +1078 -0
  22. hammad/base/utils.py +280 -0
  23. hammad/cache/__init__.py +48 -0
  24. hammad/cache/base_cache.py +181 -0
  25. hammad/cache/cache.py +169 -0
  26. hammad/cache/decorators.py +261 -0
  27. hammad/cache/file_cache.py +80 -0
  28. hammad/cache/ttl_cache.py +74 -0
  29. hammad/cli/__init__.py +33 -0
  30. hammad/cli/animations.py +604 -0
  31. hammad/cli/plugins.py +781 -0
  32. hammad/cli/styles/__init__.py +55 -0
  33. hammad/cli/styles/settings.py +139 -0
  34. hammad/cli/styles/types.py +358 -0
  35. hammad/cli/styles/utils.py +480 -0
  36. hammad/configuration/__init__.py +35 -0
  37. hammad/configuration/configuration.py +564 -0
  38. hammad/data/__init__.py +39 -0
  39. hammad/data/collections/__init__.py +34 -0
  40. hammad/data/collections/base_collection.py +58 -0
  41. hammad/data/collections/collection.py +452 -0
  42. hammad/data/collections/searchable_collection.py +556 -0
  43. hammad/data/collections/vector_collection.py +603 -0
  44. hammad/data/databases/__init__.py +21 -0
  45. hammad/data/databases/database.py +902 -0
  46. hammad/json/__init__.py +21 -0
  47. hammad/{utils/json → json}/converters.py +4 -1
  48. hammad/logging/__init__.py +35 -0
  49. hammad/logging/decorators.py +834 -0
  50. hammad/logging/logger.py +954 -0
  51. hammad/multimodal/__init__.py +24 -0
  52. hammad/multimodal/audio.py +96 -0
  53. hammad/multimodal/image.py +80 -0
  54. hammad/multithreading/__init__.py +304 -0
  55. hammad/pydantic/__init__.py +43 -0
  56. hammad/{utils/pydantic → pydantic}/converters.py +2 -1
  57. hammad/pydantic/models/__init__.py +28 -0
  58. hammad/pydantic/models/arbitrary_model.py +46 -0
  59. hammad/pydantic/models/cacheable_model.py +79 -0
  60. hammad/pydantic/models/fast_model.py +318 -0
  61. hammad/pydantic/models/function_model.py +176 -0
  62. hammad/pydantic/models/subscriptable_model.py +63 -0
  63. hammad/text/__init__.py +82 -0
  64. hammad/text/converters.py +723 -0
  65. hammad/{utils/markdown/formatting.py → text/markdown.py} +25 -23
  66. hammad/text/text.py +1066 -0
  67. hammad/types/__init__.py +11 -0
  68. hammad/types/file.py +358 -0
  69. hammad/{utils/typing/utils.py → typing/__init__.py} +142 -15
  70. hammad/web/__init__.py +43 -0
  71. hammad/web/http/__init__.py +1 -0
  72. hammad/web/http/client.py +944 -0
  73. hammad/web/models.py +245 -0
  74. hammad/web/openapi/client.py +740 -0
  75. hammad/web/search/__init__.py +1 -0
  76. hammad/web/search/client.py +988 -0
  77. hammad/web/utils.py +472 -0
  78. hammad/yaml/__init__.py +30 -0
  79. hammad/yaml/converters.py +19 -0
  80. {hammad_python-0.0.10.dist-info → hammad_python-0.0.12.dist-info}/METADATA +16 -7
  81. hammad_python-0.0.12.dist-info/RECORD +85 -0
  82. hammad/cache.py +0 -675
  83. hammad/database.py +0 -447
  84. hammad/logger.py +0 -273
  85. hammad/types/color.py +0 -951
  86. hammad/utils/markdown/__init__.py +0 -0
  87. hammad/utils/markdown/converters.py +0 -506
  88. hammad/utils/pydantic/__init__.py +0 -0
  89. hammad/utils/text/__init__.py +0 -0
  90. hammad/utils/text/converters.py +0 -229
  91. hammad/utils/typing/__init__.py +0 -0
  92. hammad_python-0.0.10.dist-info/RECORD +0 -22
  93. /hammad/{utils/__init__.py → py.typed} +0 -0
  94. /hammad/{utils/json → web/openapi}/__init__.py +0 -0
  95. {hammad_python-0.0.10.dist-info → hammad_python-0.0.12.dist-info}/WHEEL +0 -0
  96. {hammad_python-0.0.10.dist-info → hammad_python-0.0.12.dist-info}/licenses/LICENSE +0 -0
File without changes
@@ -1,506 +0,0 @@
1
- """hammad.utils.markdown.converters"""
2
-
3
- import json
4
- import logging
5
- import dataclasses
6
- from dataclasses import is_dataclass, fields as dataclass_fields
7
- from docstring_parser import parse
8
- from typing import (
9
- Any,
10
- Optional,
11
- Dict,
12
- List,
13
- Set,
14
- Callable,
15
- Union,
16
- )
17
-
18
- from ..typing.utils import (
19
- is_pydantic_basemodel,
20
- is_pydantic_basemodel_instance,
21
- is_msgspec_struct,
22
- )
23
- from ..text.converters import convert_type_to_text as convert_type_to_string
24
- from .formatting import (
25
- bold,
26
- italic,
27
- code,
28
- code_block,
29
- heading,
30
- list_item,
31
- table_row,
32
- horizontal_rule,
33
- )
34
-
35
-
36
- logger = logging.getLogger(__name__)
37
-
38
-
39
- class MarkdownError(Exception):
40
- """Exception raised for errors in the markdown converters."""
41
-
42
- def __init__(self, message: str):
43
- self.message = message
44
- super().__init__(self.message)
45
-
46
-
47
- def _escape_markdown(text: str) -> str:
48
- """Escape special Markdown characters."""
49
- # Only escape the most problematic characters
50
- chars_to_escape = ["*", "_", "`", "[", "]", "(", ")", "#", "+", "-", "!"]
51
- for char in chars_to_escape:
52
- text = text.replace(char, f"\\{char}")
53
- return text
54
-
55
-
56
- def convert_dataclass_to_markdown(
57
- obj: Any,
58
- name: Optional[str],
59
- description: Optional[str],
60
- table_format: bool,
61
- show_types: bool,
62
- show_defaults: bool,
63
- show_values: bool,
64
- indent_level: int,
65
- ) -> str:
66
- """Convert a dataclass to Markdown format."""
67
- is_class = isinstance(obj, type)
68
- obj_name = name or (obj.__name__ if is_class else obj.__class__.__name__)
69
-
70
- parts = []
71
- parts.append(heading(obj_name, min(indent_level + 1, 6)))
72
-
73
- if description:
74
- parts.append(f"\n{description}\n")
75
-
76
- fields_data = []
77
- for field in dataclass_fields(obj if is_class else obj.__class__):
78
- field_info = {
79
- "name": field.name,
80
- "type": convert_type_to_string(field.type) if show_types else None,
81
- "default": field.default
82
- if show_defaults and field.default is not dataclasses.MISSING
83
- else None,
84
- "value": getattr(obj, field.name) if show_values and not is_class else None,
85
- }
86
- fields_data.append(field_info)
87
-
88
- if table_format and fields_data:
89
- # Create table headers
90
- headers = ["Field"]
91
- if show_types:
92
- headers.append("Type")
93
- if show_defaults:
94
- headers.append("Default")
95
- if show_values and not is_class:
96
- headers.append("Value")
97
-
98
- parts.append("\n" + table_row(headers, is_header=True))
99
-
100
- # Add rows
101
- for field_info in fields_data:
102
- row = [code(field_info["name"])]
103
- if show_types:
104
- row.append(field_info["type"] or "")
105
- if show_defaults:
106
- row.append(
107
- str(field_info["default"])
108
- if field_info["default"] is not None
109
- else ""
110
- )
111
- if show_values and not is_class:
112
- row.append(
113
- str(field_info["value"]) if field_info["value"] is not None else ""
114
- )
115
- parts.append(table_row(row))
116
- else:
117
- # List format
118
- for field_info in fields_data:
119
- field_desc = code(field_info["name"])
120
- if field_info["type"]:
121
- field_desc += f" ({field_info['type']})"
122
- if field_info["default"] is not None:
123
- field_desc += f" - default: {field_info['default']}"
124
- if field_info["value"] is not None:
125
- field_desc += f" = {field_info['value']}"
126
- parts.append(list_item(field_desc, indent_level))
127
-
128
- return "\n".join(parts)
129
-
130
-
131
- def convert_pydantic_to_markdown(
132
- obj: Any,
133
- name: Optional[str],
134
- description: Optional[str],
135
- table_format: bool,
136
- show_types: bool,
137
- show_defaults: bool,
138
- show_values: bool,
139
- show_required: bool,
140
- indent_level: int,
141
- ) -> str:
142
- """Convert a Pydantic model to Markdown format."""
143
- is_class = isinstance(obj, type)
144
- is_instance = is_pydantic_basemodel_instance(obj)
145
-
146
- obj_name = name or (obj.__name__ if is_class else obj.__class__.__name__)
147
-
148
- parts = []
149
- parts.append(heading(obj_name, min(indent_level + 1, 6)))
150
-
151
- if description:
152
- parts.append(f"\n{description}\n")
153
-
154
- model_fields = getattr(obj if is_class else obj.__class__, "model_fields", {})
155
- fields_data = []
156
-
157
- for field_name, field_info in model_fields.items():
158
- field_data = {
159
- "name": field_name,
160
- "type": convert_type_to_string(field_info.annotation)
161
- if show_types
162
- else None,
163
- "required": getattr(field_info, "is_required", lambda: True)()
164
- if show_required
165
- else None,
166
- "default": getattr(field_info, "default", None) if show_defaults else None,
167
- "value": getattr(obj, field_name, None)
168
- if show_values and is_instance
169
- else None,
170
- "description": getattr(field_info, "description", None),
171
- }
172
- fields_data.append(field_data)
173
-
174
- if table_format and fields_data:
175
- # Create table
176
- headers = ["Field"]
177
- if show_types:
178
- headers.append("Type")
179
- if show_required:
180
- headers.append("Required")
181
- if show_defaults:
182
- headers.append("Default")
183
- if show_values and is_instance:
184
- headers.append("Value")
185
-
186
- parts.append("\n" + table_row(headers, is_header=True))
187
-
188
- for field_data in fields_data:
189
- row = [code(field_data["name"])]
190
- if show_types:
191
- row.append(field_data["type"] or "")
192
- if show_required:
193
- row.append("Yes" if field_data["required"] else "No")
194
- if show_defaults:
195
- row.append(
196
- str(field_data["default"])
197
- if field_data["default"] is not None
198
- else ""
199
- )
200
- if show_values and is_instance:
201
- row.append(
202
- str(field_data["value"]) if field_data["value"] is not None else ""
203
- )
204
- parts.append(table_row(row))
205
- else:
206
- # List format
207
- for field_data in fields_data:
208
- field_desc = code(field_data["name"])
209
- if field_data["type"]:
210
- field_desc += f" ({field_data['type']})"
211
- if field_data["required"] is not None:
212
- field_desc += (
213
- " " + bold("[Required]")
214
- if field_data["required"]
215
- else " " + italic("[Optional]")
216
- )
217
- if field_data["default"] is not None:
218
- field_desc += f" - default: {field_data['default']}"
219
- if field_data["value"] is not None:
220
- field_desc += f" = {field_data['value']}"
221
-
222
- parts.append(list_item(field_desc, indent_level))
223
-
224
- if field_data["description"]:
225
- parts.append(list_item(field_data["description"], indent_level + 1))
226
-
227
- return "\n".join(parts)
228
-
229
-
230
- def convert_function_to_markdown(
231
- obj: Callable,
232
- name: Optional[str],
233
- description: Optional[str],
234
- show_signature: bool,
235
- show_docstring: bool,
236
- indent_level: int,
237
- ) -> str:
238
- """Convert a function to Markdown format."""
239
- func_name = name or obj.__name__
240
-
241
- parts = []
242
- parts.append(heading(func_name, min(indent_level + 1, 6)))
243
-
244
- if show_signature:
245
- import inspect
246
-
247
- try:
248
- sig = inspect.signature(obj)
249
- parts.append(f"\n{code(f'{func_name}{sig}')}\n")
250
- except Exception:
251
- pass
252
-
253
- if description:
254
- parts.append(f"\n{description}\n")
255
- elif show_docstring and obj.__doc__:
256
- doc_info = parse(obj.__doc__)
257
- if doc_info.short_description:
258
- parts.append(f"\n{doc_info.short_description}\n")
259
- if doc_info.long_description:
260
- parts.append(f"\n{doc_info.long_description}\n")
261
-
262
- return "\n".join(parts)
263
-
264
-
265
- def convert_collection_to_markdown(
266
- obj: Union[List, Set, tuple],
267
- name: Optional[str],
268
- description: Optional[str],
269
- compact: bool,
270
- show_indices: bool,
271
- indent_level: int,
272
- visited: Set[int],
273
- ) -> str:
274
- """Convert a collection to Markdown format."""
275
- obj_name = name or obj.__class__.__name__
276
-
277
- parts = []
278
- if not compact:
279
- parts.append(heading(obj_name, min(indent_level + 1, 6)))
280
- if description:
281
- parts.append(f"\n{description}\n")
282
-
283
- if not obj:
284
- parts.append(italic("(empty)"))
285
- return "\n".join(parts)
286
-
287
- for i, item in enumerate(obj):
288
- if show_indices:
289
- item_text = (
290
- f"[{i}] {convert_to_markdown(item, compact=True, _visited=visited)}"
291
- )
292
- else:
293
- item_text = convert_to_markdown(item, compact=True, _visited=visited)
294
- parts.append(list_item(item_text, indent_level))
295
-
296
- return "\n".join(parts)
297
-
298
-
299
- def convert_dict_to_markdown(
300
- obj: Dict[Any, Any],
301
- name: Optional[str],
302
- description: Optional[str],
303
- table_format: bool,
304
- compact: bool,
305
- indent_level: int,
306
- visited: Set[int],
307
- ) -> str:
308
- """Convert a dictionary to Markdown format."""
309
- obj_name = name or "Dictionary"
310
-
311
- parts = []
312
- if not compact:
313
- parts.append(heading(obj_name, min(indent_level + 1, 6)))
314
- if description:
315
- parts.append(f"\n{description}\n")
316
-
317
- if not obj:
318
- parts.append(italic("(empty)"))
319
- return "\n".join(parts)
320
-
321
- if table_format and all(
322
- isinstance(v, (str, int, float, bool, type(None))) for v in obj.values()
323
- ):
324
- # Use table format for simple values
325
- parts.append("\n" + table_row(["Key", "Value"], is_header=True))
326
- for key, value in obj.items():
327
- parts.append(table_row([code(str(key)), str(value)]))
328
- else:
329
- # Use list format
330
- for key, value in obj.items():
331
- key_str = code(str(key))
332
- value_str = convert_to_markdown(value, compact=True, _visited=visited)
333
- parts.append(list_item(f"{key_str}: {value_str}", indent_level))
334
-
335
- return "\n".join(parts)
336
-
337
-
338
- # -----------------------------------------------------------------------------
339
- # Main Converter Function
340
- # -----------------------------------------------------------------------------
341
-
342
-
343
- def convert_to_markdown(
344
- obj: Any,
345
- *,
346
- # Formatting options
347
- name: Optional[str] = None,
348
- description: Optional[str] = None,
349
- heading_level: int = 1,
350
- table_format: bool = False,
351
- compact: bool = False,
352
- code_block_language: Optional[str] = None,
353
- # Display options
354
- show_types: bool = True,
355
- show_values: bool = True,
356
- show_defaults: bool = True,
357
- show_required: bool = True,
358
- show_docstring: bool = True,
359
- show_signature: bool = True,
360
- show_indices: bool = False,
361
- # Style options
362
- escape_special_chars: bool = False,
363
- add_toc: bool = False,
364
- add_horizontal_rules: bool = False,
365
- # Internal
366
- _visited: Optional[Set[int]] = None,
367
- _indent_level: int = 0,
368
- ) -> str:
369
- """
370
- Converts any object into a Markdown formatted string.
371
-
372
- Args:
373
- obj: The object to convert to Markdown
374
- name: Optional name/title for the object
375
- description: Optional description to add
376
- heading_level: Starting heading level (1-6)
377
- table_format: Use tables for structured data when possible
378
- compact: Minimize formatting for inline usage
379
- code_block_language: If set, wrap entire output in code block
380
- show_types: Include type information
381
- show_values: Show current values (for instances)
382
- show_defaults: Show default values
383
- show_required: Show required/optional status
384
- show_docstring: Include docstrings
385
- show_signature: Show function signatures
386
- show_indices: Show indices for collections
387
- escape_special_chars: Escape Markdown special characters
388
- add_toc: Add table of contents (not implemented)
389
- add_horizontal_rules: Add separators between sections
390
-
391
- Returns:
392
- Markdown formatted string representation of the object
393
- """
394
- # Handle circular references
395
- visited = _visited if _visited is not None else set()
396
- obj_id = id(obj)
397
-
398
- if obj_id in visited:
399
- return italic("(circular reference)")
400
-
401
- visited_copy = visited.copy()
402
- visited_copy.add(obj_id)
403
-
404
- # Handle None
405
- if obj is None:
406
- return code("None")
407
-
408
- # Handle primitives
409
- if isinstance(obj, (str, int, float, bool)):
410
- text = str(obj)
411
- if escape_special_chars and isinstance(obj, str):
412
- text = _escape_markdown(text)
413
- return text if compact else code(text)
414
-
415
- # Handle bytes
416
- if isinstance(obj, bytes):
417
- return code(f"b'{obj.hex()}'")
418
-
419
- # Wrap in code block if requested
420
- if code_block_language:
421
- try:
422
- if code_block_language.lower() == "json":
423
- content = json.dumps(obj, indent=2)
424
- else:
425
- content = str(obj)
426
- return code_block(content, code_block_language)
427
- except Exception:
428
- pass
429
-
430
- result = ""
431
-
432
- # Handle dataclasses
433
- if is_dataclass(obj):
434
- result = convert_dataclass_to_markdown(
435
- obj,
436
- name,
437
- description,
438
- table_format,
439
- show_types,
440
- show_defaults,
441
- show_values,
442
- _indent_level,
443
- )
444
-
445
- # Handle Pydantic models
446
- elif is_pydantic_basemodel(obj):
447
- result = convert_pydantic_to_markdown(
448
- obj,
449
- name,
450
- description,
451
- table_format,
452
- show_types,
453
- show_defaults,
454
- show_values,
455
- show_required,
456
- _indent_level,
457
- )
458
-
459
- # Handle msgspec structs
460
- elif is_msgspec_struct(obj):
461
- # Similar to dataclass handling
462
- result = convert_dataclass_to_markdown(
463
- obj,
464
- name,
465
- description,
466
- table_format,
467
- show_types,
468
- show_defaults,
469
- show_values,
470
- _indent_level,
471
- )
472
-
473
- # Handle functions
474
- elif callable(obj) and hasattr(obj, "__name__"):
475
- result = convert_function_to_markdown(
476
- obj, name, description, show_signature, show_docstring, _indent_level
477
- )
478
-
479
- # Handle collections
480
- elif isinstance(obj, (list, tuple, set)):
481
- result = convert_collection_to_markdown(
482
- obj, name, description, compact, show_indices, _indent_level, visited_copy
483
- )
484
-
485
- # Handle dictionaries
486
- elif isinstance(obj, dict):
487
- result = convert_dict_to_markdown(
488
- obj, name, description, table_format, compact, _indent_level, visited_copy
489
- )
490
-
491
- # Default handling
492
- else:
493
- obj_name = name or obj.__class__.__name__
494
- parts = []
495
- if not compact:
496
- parts.append(heading(obj_name, min(_indent_level + 1, 6)))
497
- if description:
498
- parts.append(f"\n{description}\n")
499
- parts.append(code(str(obj)))
500
- result = "\n".join(parts)
501
-
502
- # Add horizontal rule if requested
503
- if add_horizontal_rules and not compact and _indent_level == 0:
504
- result += f"\n\n{horizontal_rule()}\n"
505
-
506
- return result
File without changes
File without changes