hammad-python 0.0.11__py3-none-any.whl → 0.0.13__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 (80) hide show
  1. hammad/__init__.py +169 -56
  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/{based → base}/fields.py +23 -23
  21. hammad/{based → base}/model.py +124 -14
  22. hammad/base/utils.py +280 -0
  23. hammad/cache/__init__.py +30 -12
  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 +10 -2
  30. hammad/cli/{styles/animations.py → animations.py} +79 -23
  31. hammad/cli/{plugins/__init__.py → plugins.py} +85 -90
  32. hammad/cli/styles/__init__.py +50 -0
  33. hammad/cli/styles/settings.py +4 -0
  34. hammad/configuration/__init__.py +35 -0
  35. hammad/{data/types/files → configuration}/configuration.py +96 -7
  36. hammad/data/__init__.py +14 -26
  37. hammad/data/collections/__init__.py +4 -2
  38. hammad/data/collections/collection.py +300 -75
  39. hammad/data/collections/vector_collection.py +118 -12
  40. hammad/data/databases/__init__.py +2 -2
  41. hammad/data/databases/database.py +383 -32
  42. hammad/json/__init__.py +2 -2
  43. hammad/logging/__init__.py +13 -5
  44. hammad/logging/decorators.py +404 -2
  45. hammad/logging/logger.py +442 -22
  46. hammad/multimodal/__init__.py +24 -0
  47. hammad/{data/types/files → multimodal}/audio.py +21 -6
  48. hammad/{data/types/files → multimodal}/image.py +5 -5
  49. hammad/multithreading/__init__.py +304 -0
  50. hammad/pydantic/__init__.py +2 -2
  51. hammad/pydantic/converters.py +1 -1
  52. hammad/pydantic/models/__init__.py +2 -2
  53. hammad/text/__init__.py +59 -14
  54. hammad/text/converters.py +723 -0
  55. hammad/text/{utils/markdown/formatting.py → markdown.py} +25 -23
  56. hammad/text/text.py +12 -14
  57. hammad/types/__init__.py +11 -0
  58. hammad/{data/types/files → types}/file.py +18 -18
  59. hammad/typing/__init__.py +138 -84
  60. hammad/web/__init__.py +3 -2
  61. hammad/web/models.py +245 -0
  62. hammad/web/search/client.py +75 -23
  63. hammad/web/utils.py +14 -5
  64. hammad/yaml/__init__.py +2 -2
  65. hammad/yaml/converters.py +1 -1
  66. {hammad_python-0.0.11.dist-info → hammad_python-0.0.13.dist-info}/METADATA +4 -1
  67. hammad_python-0.0.13.dist-info/RECORD +85 -0
  68. hammad/based/__init__.py +0 -52
  69. hammad/based/utils.py +0 -455
  70. hammad/cache/_cache.py +0 -746
  71. hammad/data/types/__init__.py +0 -33
  72. hammad/data/types/files/__init__.py +0 -1
  73. hammad/data/types/files/document.py +0 -195
  74. hammad/text/utils/__init__.py +0 -1
  75. hammad/text/utils/converters.py +0 -229
  76. hammad/text/utils/markdown/__init__.py +0 -1
  77. hammad/text/utils/markdown/converters.py +0 -506
  78. hammad_python-0.0.11.dist-info/RECORD +0 -65
  79. {hammad_python-0.0.11.dist-info → hammad_python-0.0.13.dist-info}/WHEEL +0 -0
  80. {hammad_python-0.0.11.dist-info → hammad_python-0.0.13.dist-info}/licenses/LICENSE +0 -0
@@ -1,14 +1,124 @@
1
- """hammad.core.base.model"""
1
+ """hammad.base.model"""
2
2
 
3
3
  import copy
4
4
  from functools import lru_cache
5
- from typing import Any, Dict, List, Literal, Optional, Self, Set, Union
5
+ from typing import (
6
+ Any,
7
+ Callable,
8
+ Dict,
9
+ List,
10
+ Literal,
11
+ Mapping,
12
+ Optional,
13
+ Self,
14
+ Set,
15
+ Type,
16
+ Union,
17
+ )
6
18
 
7
19
  import msgspec
8
20
  from msgspec.json import decode, encode, schema
9
21
  from msgspec.structs import Struct, asdict, fields
10
22
 
11
- __all__ = ("BasedModel",)
23
+ __all__ = ("Model", "model_settings")
24
+
25
+
26
+ def model_settings(
27
+ *,
28
+ tag: Union[None, bool, str, int, Callable[[str], Union[str, int]]] = None,
29
+ tag_field: Union[None, str] = None,
30
+ rename: Union[
31
+ None,
32
+ Literal["lower", "upper", "camel", "pascal", "kebab"],
33
+ Callable[[str], Optional[str]],
34
+ Mapping[str, str],
35
+ ] = None,
36
+ omit_defaults: bool = False,
37
+ forbid_unknown_fields: bool = False,
38
+ frozen: bool = False,
39
+ eq: bool = True,
40
+ order: bool = False,
41
+ kw_only: bool = False,
42
+ repr_omit_defaults: bool = False,
43
+ array_like: bool = False,
44
+ gc: bool = True,
45
+ weakref: bool = False,
46
+ dict: bool = False,
47
+ cache_hash: bool = False,
48
+ ) -> Callable[[Type], Type]:
49
+ """Decorator to configure msgspec Struct parameters for Model classes.
50
+
51
+ This decorator allows you to configure all msgspec Struct parameters
52
+ while preserving type safety and IDE completion.
53
+
54
+ Args:
55
+ tag: Tag configuration for the struct
56
+ tag_field: Field to use for tagging
57
+ rename: Field renaming strategy
58
+ omit_defaults: Whether to omit default values in serialization
59
+ forbid_unknown_fields: Whether to forbid unknown fields during deserialization
60
+ frozen: Whether the struct should be immutable
61
+ eq: Whether to generate __eq__ method
62
+ order: Whether to generate ordering methods
63
+ kw_only: Whether fields should be keyword-only
64
+ repr_omit_defaults: Whether to omit defaults in repr
65
+ array_like: Whether to treat the struct as array-like
66
+ gc: Whether to enable garbage collection
67
+ weakref: Whether to enable weak references
68
+ dict: Whether to enable dict-like access
69
+ cache_hash: Whether to cache hash values
70
+
71
+ Returns:
72
+ Class decorator that configures the Model class
73
+
74
+ Example:
75
+ @model_settings(frozen=True, kw_only=True)
76
+ class User(Model):
77
+ name: str
78
+ age: int = 0
79
+ """
80
+
81
+ def decorator(cls: Type) -> Type:
82
+ # Store the configuration parameters
83
+ config_kwargs = {
84
+ "tag": tag,
85
+ "tag_field": tag_field,
86
+ "rename": rename,
87
+ "omit_defaults": omit_defaults,
88
+ "forbid_unknown_fields": forbid_unknown_fields,
89
+ "frozen": frozen,
90
+ "eq": eq,
91
+ "order": order,
92
+ "kw_only": kw_only,
93
+ "repr_omit_defaults": repr_omit_defaults,
94
+ "array_like": array_like,
95
+ "gc": gc,
96
+ "weakref": weakref,
97
+ "dict": dict,
98
+ "cache_hash": cache_hash,
99
+ }
100
+
101
+ # Filter out None values to avoid passing them to __init_subclass__
102
+ filtered_kwargs = {k: v for k, v in config_kwargs.items() if v is not None}
103
+
104
+ # Create a new class with the same name and bases but with the configuration
105
+ class ConfiguredModel(cls):
106
+ def __init_subclass__(cls, **kwargs):
107
+ # Merge the decorator kwargs with any kwargs passed to __init_subclass__
108
+ merged_kwargs = {**filtered_kwargs, **kwargs}
109
+ super().__init_subclass__(**merged_kwargs)
110
+
111
+ # Preserve the original class name and module
112
+ ConfiguredModel.__name__ = cls.__name__
113
+ ConfiguredModel.__qualname__ = cls.__qualname__
114
+ ConfiguredModel.__module__ = cls.__module__
115
+
116
+ # Apply the configuration by calling __init_subclass__ manually
117
+ ConfiguredModel.__init_subclass__(**filtered_kwargs)
118
+
119
+ return ConfiguredModel
120
+
121
+ return decorator
12
122
 
13
123
 
14
124
  def _get_field_schema(field) -> dict[str, Any]:
@@ -83,7 +193,7 @@ def _get_type_schema(type_hint) -> dict[str, Any]:
83
193
  return {"type": "object"}
84
194
 
85
195
 
86
- class BasedModel(Struct):
196
+ class Model(Struct):
87
197
  """Based, as defined by Lil B is:
88
198
 
89
199
  ```markdown
@@ -96,7 +206,7 @@ class BasedModel(Struct):
96
206
  does not support the `keys`, `values`, `items`, and `get`
97
207
  methods to allow for usage of those fields as key names.
98
208
 
99
- These wise words define this model. A `BasedModel` is
209
+ These wise words define this model. A `Model` is
100
210
  interactable both through the dictionary interface, and
101
211
  dot notation, and utilizes `msgspec` to provide an interface
102
212
  identical to a `pydantic.BaseModel`, with the benefit of
@@ -423,7 +533,7 @@ class BasedModel(Struct):
423
533
  cls,
424
534
  fields: str,
425
535
  schema: Literal[
426
- "based",
536
+ "base",
427
537
  "dataclass",
428
538
  "pydantic",
429
539
  "msgspec",
@@ -431,7 +541,7 @@ class BasedModel(Struct):
431
541
  "namedtuple",
432
542
  "attrs",
433
543
  "dict",
434
- ] = "based",
544
+ ] = "base",
435
545
  # Simple Override Params To Edit The Final Model
436
546
  # This method always goes field(s) -> model not to field
437
547
  title: Optional[str] = None,
@@ -446,7 +556,7 @@ class BasedModel(Struct):
446
556
 
447
557
  Args:
448
558
  fields: The field to be converted into the model
449
- schema: The target schema format to convert to (Defaults to a basedmodel)
559
+ schema: The target schema format to convert to (Defaults to a Model)
450
560
  title : An optional title or title override for the model (uses the field name if not provided)
451
561
  description : An optional description for the model (uses the field description if not provided)
452
562
  field_name : The name of the field within this new model representing the target field (defaults to "value")
@@ -489,8 +599,8 @@ class BasedModel(Struct):
489
599
  model_title = title or fields.title()
490
600
  model_description = description or f"Model wrapping field '{fields}'"
491
601
 
492
- if schema == "based":
493
- from .fields import basedfield
602
+ if schema == "base":
603
+ from .fields import field
494
604
 
495
605
  # Create annotations for the dynamic class
496
606
  annotations = {field_name: field_type}
@@ -500,18 +610,18 @@ class BasedModel(Struct):
500
610
 
501
611
  # Add default if available
502
612
  if field_default is not msgspec.UNSET:
503
- class_dict[field_name] = basedfield(
613
+ class_dict[field_name] = field(
504
614
  default=field_default,
505
615
  description=field_description,
506
616
  examples=field_examples,
507
617
  )
508
618
  elif field_description or field_examples:
509
- class_dict[field_name] = basedfield(
619
+ class_dict[field_name] = field(
510
620
  description=field_description, examples=field_examples
511
621
  )
512
622
 
513
623
  # Create the dynamic class
514
- DynamicModel = type(model_title.replace(" ", ""), (BasedModel,), class_dict)
624
+ DynamicModel = type(model_title.replace(" ", ""), (Model,), class_dict)
515
625
 
516
626
  if init and field_default is not msgspec.UNSET:
517
627
  return DynamicModel(**{field_name: field_default})
@@ -817,7 +927,7 @@ class BasedModel(Struct):
817
927
  return instance.model_convert(schema, exclude)
818
928
 
819
929
  def model_to_pydantic(self):
820
- """Converts the `BasedModel` to a `pydantic.BaseModel`."""
930
+ """Converts the `Model` to a `pydantic.BaseModel`."""
821
931
  from pydantic import BaseModel, create_model
822
932
 
823
933
  # Get the field information from the current instance
hammad/base/utils.py ADDED
@@ -0,0 +1,280 @@
1
+ """hammad.base.utils"""
2
+
3
+ from functools import lru_cache
4
+ from typing import Any, Callable, Optional, Union, Tuple, Dict
5
+
6
+ from msgspec.structs import Struct
7
+
8
+ from .fields import FieldInfo, field, Field
9
+ from .model import Model
10
+
11
+
12
+ __all__ = (
13
+ "create_model",
14
+ "get_field_info",
15
+ "is_field",
16
+ "is_model",
17
+ "validator",
18
+ )
19
+
20
+
21
+ def create_model(
22
+ __model_name: str,
23
+ *,
24
+ __base__: Optional[Union[type, Tuple[type, ...]]] = None,
25
+ __module__: Optional[str] = None,
26
+ __qualname__: Optional[str] = None,
27
+ __doc__: Optional[str] = None,
28
+ __validators__: Optional[Dict[str, Any]] = None,
29
+ __config__: Optional[type] = None,
30
+ **field_definitions: Any,
31
+ ) -> type[Model]:
32
+ """Create a Model dynamically with Pydantic-compatible interface.
33
+
34
+ This function provides a drop-in replacement for pydantic.create_model()
35
+ that creates Model classes instead of pydantic BaseModel classes.
36
+
37
+ Args:
38
+ __model_name: Name of the model class to create
39
+ __base__: Base class(es) to inherit from. If None, uses Model.
40
+ Can be a single class or tuple of classes.
41
+ __module__: Module name for the created class
42
+ __qualname__: Qualified name for the created class
43
+ __doc__: Docstring for the created class
44
+ __validators__: Dictionary of validators (for compatibility - not fully implemented)
45
+ __config__: Configuration class (for compatibility - not fully implemented)
46
+ **field_definitions: Field definitions as keyword arguments.
47
+ Each can be:
48
+ - A type annotation (e.g., str, int)
49
+ - A tuple of (type, default_value)
50
+ - A tuple of (type, Field(...))
51
+ - A Field instance
52
+
53
+ Returns:
54
+ A new Model class with the specified fields
55
+
56
+ Examples:
57
+ # Simple model with basic types
58
+ User = create_model('User', name=str, age=int)
59
+
60
+ # Model with defaults
61
+ Config = create_model('Config',
62
+ host=(str, 'localhost'),
63
+ port=(int, 8080))
64
+
65
+ # Model with field constraints
66
+ Product = create_model('Product',
67
+ name=str,
68
+ price=(float, field(gt=0)),
69
+ tags=(List[str], field(default_factory=list)))
70
+
71
+ # Model with custom base class
72
+ class BaseEntity(Model):
73
+ id: int
74
+ created_at: str
75
+
76
+ User = create_model('User',
77
+ name=str,
78
+ email=str,
79
+ __base__=BaseEntity)
80
+ """
81
+ # Handle base class specification
82
+ if __base__ is not None and __config__ is not None:
83
+ raise ValueError(
84
+ "Cannot specify both '__base__' and '__config__' - "
85
+ "use a base class with the desired configuration instead"
86
+ )
87
+
88
+ # Determine base classes
89
+ if __base__ is None:
90
+ bases = (Model,)
91
+ elif isinstance(__base__, tuple):
92
+ # Ensure all bases are compatible
93
+ for base in __base__:
94
+ if not (issubclass(base, Model) or issubclass(base, Struct)):
95
+ raise ValueError(
96
+ f"Base class {base} must be a subclass of Model or msgspec.Struct"
97
+ )
98
+ bases = __base__
99
+ else:
100
+ if not (issubclass(__base__, Model) or issubclass(__base__, Struct)):
101
+ raise ValueError(
102
+ f"Base class {__base__} must be a subclass of Model or msgspec.Struct"
103
+ )
104
+ bases = (__base__,)
105
+
106
+ # Build class dictionary
107
+ class_dict = {}
108
+ annotations = {}
109
+
110
+ # Set metadata
111
+ if __doc__ is not None:
112
+ class_dict["__doc__"] = __doc__
113
+ if __module__ is not None:
114
+ class_dict["__module__"] = __module__
115
+ if __qualname__ is not None:
116
+ class_dict["__qualname__"] = __qualname__
117
+
118
+ # Process field definitions in two passes to ensure proper ordering
119
+ # First pass: collect required and optional fields separately
120
+ required_fields = {}
121
+ optional_fields = {}
122
+
123
+ for field_name, field_definition in field_definitions.items():
124
+ if field_name.startswith("__") and field_name.endswith("__"):
125
+ # Skip special attributes that were passed as field definitions
126
+ continue
127
+
128
+ # Parse field definition
129
+ is_optional = False
130
+
131
+ if isinstance(field_definition, tuple):
132
+ if len(field_definition) == 2:
133
+ field_type, field_value = field_definition
134
+ annotations[field_name] = field_type
135
+
136
+ # Check if field_value is a Field instance or field
137
+ if hasattr(field_value, "__class__") and (
138
+ "field" in field_value.__class__.__name__.lower()
139
+ or hasattr(field_value, "default")
140
+ or callable(getattr(field_value, "__call__", None))
141
+ ):
142
+ # It's a field descriptor
143
+ optional_fields[field_name] = field_value
144
+ else:
145
+ # It's a default value - create a field with this default
146
+ optional_fields[field_name] = field(default=field_value)
147
+ is_optional = True
148
+ else:
149
+ raise ValueError(
150
+ f"Field definition for '{field_name}' must be a 2-tuple of (type, default/Field)"
151
+ )
152
+ elif hasattr(field_definition, "__origin__") or hasattr(
153
+ field_definition, "__class__"
154
+ ):
155
+ # It's a type annotation (like str, int, List[str], etc.) - required field
156
+ annotations[field_name] = field_definition
157
+ required_fields[field_name] = None
158
+ else:
159
+ # It's likely a default value without type annotation
160
+ # We'll infer the type from the value
161
+ annotations[field_name] = type(field_definition)
162
+ optional_fields[field_name] = field(default=field_definition)
163
+ is_optional = True
164
+
165
+ # Second pass: add fields in correct order (required first, then optional)
166
+ # This ensures msgspec field ordering requirements are met
167
+ for field_name, field_value in required_fields.items():
168
+ if field_value is not None:
169
+ class_dict[field_name] = field_value
170
+
171
+ for field_name, field_value in optional_fields.items():
172
+ class_dict[field_name] = field_value
173
+
174
+ # Set annotations in proper order (required fields first, then optional)
175
+ ordered_annotations = {}
176
+
177
+ # Add required field annotations first
178
+ for field_name in required_fields:
179
+ if field_name in annotations:
180
+ ordered_annotations[field_name] = annotations[field_name]
181
+
182
+ # Add optional field annotations second
183
+ for field_name in optional_fields:
184
+ if field_name in annotations:
185
+ ordered_annotations[field_name] = annotations[field_name]
186
+
187
+ class_dict["__annotations__"] = ordered_annotations
188
+
189
+ # Handle validators (basic implementation for compatibility)
190
+ if __validators__:
191
+ # Store validators for potential future use
192
+ class_dict["_validators"] = __validators__
193
+ # Note: Full validator implementation would require more complex integration
194
+
195
+ # Create the dynamic class
196
+ try:
197
+ DynamicModel = type(__model_name, bases, class_dict)
198
+ except Exception as e:
199
+ raise ValueError(f"Failed to create model '{__model_name}': {e}") from e
200
+
201
+ return DynamicModel
202
+
203
+
204
+ @lru_cache(maxsize=None)
205
+ def get_field_info(field: Any) -> Optional[FieldInfo]:
206
+ """Extract FieldInfo from a field descriptor with caching."""
207
+ if isinstance(field, tuple) and len(field) == 2:
208
+ _, field_info = field
209
+ if isinstance(field_info, FieldInfo):
210
+ return field_info
211
+ elif hasattr(field, "_field_info"):
212
+ return field._field_info
213
+ elif hasattr(field, "field_info"):
214
+ return field.field_info
215
+ elif isinstance(field, Field):
216
+ return field.field_info
217
+ elif hasattr(field, "__class__") and field.__class__.__name__ == "FieldDescriptor":
218
+ return field.field_info
219
+ return None
220
+
221
+
222
+ def is_field(field: Any) -> bool:
223
+ """Check if a field is a field."""
224
+ return get_field_info(field) is not None
225
+
226
+
227
+ def is_model(model: Any) -> bool:
228
+ """Check if a model is a model."""
229
+ # Check if it's an instance of Model
230
+ if isinstance(model, Model):
231
+ return True
232
+
233
+ # Check if it's a Model class (not instance)
234
+ if isinstance(model, type) and issubclass(model, Model):
235
+ return True
236
+
237
+ # Check for Model characteristics using duck typing
238
+ # Look for key Model/msgspec.Struct attributes and methods
239
+ if hasattr(model, "__struct_fields__") and hasattr(model, "model_dump"):
240
+ # Check for Model-specific methods
241
+ if (
242
+ hasattr(model, "model_copy")
243
+ and hasattr(model, "model_validate")
244
+ and hasattr(model, "model_to_pydantic")
245
+ ):
246
+ return True
247
+
248
+ # Check if it's an instance of any msgspec Struct with Model methods
249
+ try:
250
+ if isinstance(model, Struct) and hasattr(model, "model_dump"):
251
+ return True
252
+ except ImportError:
253
+ pass
254
+
255
+ return False
256
+
257
+
258
+ def validator(
259
+ *fields: str, pre: bool = False, post: bool = False, always: bool = False
260
+ ):
261
+ """Decorator to create a validator for specific fields.
262
+
263
+ Args:
264
+ *fields: Field names to validate
265
+ pre: Whether this is a pre-validator
266
+ post: Whether this is a post-validator
267
+ always: Whether to run even if the value is not set
268
+
269
+ Returns:
270
+ Decorator function
271
+ """
272
+
273
+ def decorator(func: Callable) -> Callable:
274
+ func._validator_fields = fields
275
+ func._validator_pre = pre
276
+ func._validator_post = post
277
+ func._validator_always = always
278
+ return func
279
+
280
+ return decorator
hammad/cache/__init__.py CHANGED
@@ -1,30 +1,48 @@
1
- """hammad.cache"""
1
+ """hammad.cache
2
+
3
+ Contains helpful resources for creating simple cache systems, and
4
+ decorators that implement "automatic" hashing & caching of function calls.
5
+ """
2
6
 
3
7
  from typing import TYPE_CHECKING
4
- from ..based.utils import auto_create_lazy_loader
8
+ from .._core._utils._import_utils import _auto_create_getattr_loader
5
9
 
6
10
  if TYPE_CHECKING:
7
- from ._cache import (
8
- TTLCache,
9
- DiskCache,
10
- CacheParams,
11
- CacheReturn,
11
+ from .base_cache import BaseCache, CacheParams, CacheReturn, CacheType
12
+ from .file_cache import FileCache
13
+ from .ttl_cache import TTLCache
14
+ from .cache import Cache, create_cache
15
+ from .decorators import (
12
16
  cached,
13
17
  auto_cached,
14
- create_cache,
18
+ get_decorator_cache,
19
+ clear_decorator_cache,
15
20
  )
16
21
 
17
22
 
18
23
  __all__ = (
19
- "auto_cached",
20
- "cached",
24
+ # hammad.cache.base_cache
25
+ "BaseCache",
26
+ "CacheParams",
27
+ "CacheReturn",
28
+ "CacheType",
29
+ # hammad.cache.file_cache
30
+ "FileCache",
31
+ # hammad.cache.ttl_cache
32
+ "TTLCache",
33
+ # hammad.cache.cache
34
+ "Cache",
21
35
  "create_cache",
36
+ # hammad.cache.decorators
37
+ "cached",
38
+ "auto_cached",
39
+ "get_decorator_cache",
40
+ "clear_decorator_cache",
22
41
  )
23
42
 
24
43
 
25
- __getattr__ = auto_create_lazy_loader(__all__)
44
+ __getattr__ = _auto_create_getattr_loader(__all__)
26
45
 
27
46
 
28
47
  def __dir__() -> list[str]:
29
- """Get the attributes of the cache module."""
30
48
  return list(__all__)