hammad-python 0.0.14__py3-none-any.whl → 0.0.16__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.
- hammad/__init__.py +177 -0
- hammad/{performance/imports.py → _internal.py} +7 -1
- hammad/cache/__init__.py +1 -1
- hammad/cli/__init__.py +3 -1
- hammad/cli/_runner.py +265 -0
- hammad/cli/animations.py +1 -1
- hammad/cli/plugins.py +133 -78
- hammad/cli/styles/__init__.py +1 -1
- hammad/cli/styles/utils.py +149 -3
- hammad/data/__init__.py +56 -29
- hammad/data/collections/__init__.py +27 -17
- hammad/data/collections/collection.py +205 -383
- hammad/data/collections/indexes/__init__.py +37 -0
- hammad/data/collections/indexes/qdrant/__init__.py +1 -0
- hammad/data/collections/indexes/qdrant/index.py +735 -0
- hammad/data/collections/indexes/qdrant/settings.py +94 -0
- hammad/data/collections/indexes/qdrant/utils.py +220 -0
- hammad/data/collections/indexes/tantivy/__init__.py +1 -0
- hammad/data/collections/indexes/tantivy/index.py +428 -0
- hammad/data/collections/indexes/tantivy/settings.py +51 -0
- hammad/data/collections/indexes/tantivy/utils.py +200 -0
- hammad/data/configurations/__init__.py +2 -2
- hammad/data/configurations/configuration.py +2 -2
- hammad/data/models/__init__.py +20 -9
- hammad/data/models/extensions/__init__.py +4 -0
- hammad/data/models/{pydantic → extensions/pydantic}/__init__.py +6 -19
- hammad/data/models/{pydantic → extensions/pydantic}/converters.py +143 -16
- hammad/data/models/{base/fields.py → fields.py} +1 -1
- hammad/data/models/{base/model.py → model.py} +1 -1
- hammad/data/models/{base/utils.py → utils.py} +1 -1
- hammad/data/sql/__init__.py +23 -0
- hammad/data/sql/database.py +578 -0
- hammad/data/sql/types.py +141 -0
- hammad/data/types/__init__.py +1 -3
- hammad/data/types/file.py +3 -3
- hammad/data/types/multimodal/__init__.py +2 -2
- hammad/data/types/multimodal/audio.py +2 -2
- hammad/data/types/multimodal/image.py +2 -2
- hammad/formatting/__init__.py +9 -27
- hammad/formatting/json/__init__.py +8 -2
- hammad/formatting/json/converters.py +7 -1
- hammad/formatting/text/__init__.py +1 -1
- hammad/formatting/yaml/__init__.py +1 -1
- hammad/genai/__init__.py +78 -0
- hammad/genai/agents/__init__.py +1 -0
- hammad/genai/agents/types/__init__.py +35 -0
- hammad/genai/agents/types/history.py +277 -0
- hammad/genai/agents/types/tool.py +490 -0
- hammad/genai/embedding_models/__init__.py +41 -0
- hammad/{ai/embeddings/client/litellm_embeddings_client.py → genai/embedding_models/embedding_model.py} +47 -142
- hammad/genai/embedding_models/embedding_model_name.py +77 -0
- hammad/genai/embedding_models/embedding_model_request.py +65 -0
- hammad/{ai/embeddings/types.py → genai/embedding_models/embedding_model_response.py} +3 -3
- hammad/genai/embedding_models/run.py +161 -0
- hammad/genai/language_models/__init__.py +35 -0
- hammad/genai/language_models/_streaming.py +622 -0
- hammad/genai/language_models/_types.py +276 -0
- hammad/genai/language_models/_utils/__init__.py +31 -0
- hammad/genai/language_models/_utils/_completions.py +131 -0
- hammad/genai/language_models/_utils/_messages.py +89 -0
- hammad/genai/language_models/_utils/_requests.py +202 -0
- hammad/genai/language_models/_utils/_structured_outputs.py +124 -0
- hammad/genai/language_models/language_model.py +734 -0
- hammad/genai/language_models/language_model_request.py +135 -0
- hammad/genai/language_models/language_model_response.py +219 -0
- hammad/genai/language_models/language_model_response_chunk.py +53 -0
- hammad/genai/language_models/run.py +530 -0
- hammad/genai/multimodal_models.py +48 -0
- hammad/genai/rerank_models.py +26 -0
- hammad/logging/__init__.py +1 -1
- hammad/logging/decorators.py +1 -1
- hammad/logging/logger.py +2 -2
- hammad/mcp/__init__.py +1 -1
- hammad/mcp/client/__init__.py +35 -0
- hammad/mcp/client/client.py +105 -4
- hammad/mcp/client/client_service.py +10 -3
- hammad/mcp/servers/__init__.py +24 -0
- hammad/{performance/runtime → runtime}/__init__.py +2 -2
- hammad/{performance/runtime → runtime}/decorators.py +1 -1
- hammad/{performance/runtime → runtime}/run.py +1 -1
- hammad/service/__init__.py +1 -1
- hammad/service/create.py +3 -8
- hammad/service/decorators.py +8 -8
- hammad/typing/__init__.py +28 -0
- hammad/web/__init__.py +3 -3
- hammad/web/http/client.py +1 -1
- hammad/web/models.py +53 -21
- hammad/web/search/client.py +99 -52
- hammad/web/utils.py +13 -13
- hammad_python-0.0.16.dist-info/METADATA +191 -0
- hammad_python-0.0.16.dist-info/RECORD +110 -0
- hammad/ai/__init__.py +0 -1
- hammad/ai/_utils.py +0 -142
- hammad/ai/completions/__init__.py +0 -45
- hammad/ai/completions/client.py +0 -684
- hammad/ai/completions/create.py +0 -710
- hammad/ai/completions/settings.py +0 -100
- hammad/ai/completions/types.py +0 -792
- hammad/ai/completions/utils.py +0 -486
- hammad/ai/embeddings/__init__.py +0 -35
- hammad/ai/embeddings/client/__init__.py +0 -1
- hammad/ai/embeddings/client/base_embeddings_client.py +0 -26
- hammad/ai/embeddings/client/fastembed_text_embeddings_client.py +0 -200
- hammad/ai/embeddings/create.py +0 -159
- hammad/data/collections/base_collection.py +0 -58
- hammad/data/collections/searchable_collection.py +0 -556
- hammad/data/collections/vector_collection.py +0 -596
- hammad/data/databases/__init__.py +0 -21
- hammad/data/databases/database.py +0 -902
- hammad/data/models/base/__init__.py +0 -35
- hammad/data/models/pydantic/models/__init__.py +0 -28
- hammad/data/models/pydantic/models/arbitrary_model.py +0 -46
- hammad/data/models/pydantic/models/cacheable_model.py +0 -79
- hammad/data/models/pydantic/models/fast_model.py +0 -318
- hammad/data/models/pydantic/models/function_model.py +0 -176
- hammad/data/models/pydantic/models/subscriptable_model.py +0 -63
- hammad/performance/__init__.py +0 -36
- hammad/py.typed +0 -0
- hammad_python-0.0.14.dist-info/METADATA +0 -70
- hammad_python-0.0.14.dist-info/RECORD +0 -99
- {hammad_python-0.0.14.dist-info → hammad_python-0.0.16.dist-info}/WHEEL +0 -0
- {hammad_python-0.0.14.dist-info → hammad_python-0.0.16.dist-info}/licenses/LICENSE +0 -0
hammad/data/models/__init__.py
CHANGED
@@ -5,35 +5,46 @@ models, as well as modules & utilities specifically for various interfaces
|
|
5
5
|
of models such as `pydantic`."""
|
6
6
|
|
7
7
|
from typing import TYPE_CHECKING
|
8
|
-
from ...
|
8
|
+
from ..._internal import create_getattr_importer
|
9
9
|
|
10
10
|
if TYPE_CHECKING:
|
11
|
-
from .
|
11
|
+
from .model import (
|
12
12
|
Model,
|
13
|
-
|
13
|
+
model_settings,
|
14
|
+
)
|
15
|
+
from .fields import (
|
16
|
+
field
|
17
|
+
)
|
18
|
+
from .utils import (
|
14
19
|
validator,
|
15
20
|
is_field,
|
16
21
|
is_model,
|
17
|
-
model_settings
|
18
22
|
)
|
19
|
-
from .pydantic import (
|
23
|
+
from .extensions.pydantic.converters import (
|
20
24
|
convert_to_pydantic_model,
|
21
|
-
convert_to_pydantic_field
|
25
|
+
convert_to_pydantic_field,
|
26
|
+
is_pydantic_model_class
|
22
27
|
)
|
23
28
|
|
24
29
|
|
25
30
|
__all__ = (
|
26
|
-
# hammad.models.
|
31
|
+
# hammad.lib.data.models.model
|
27
32
|
"Model",
|
33
|
+
"model_settings",
|
34
|
+
|
35
|
+
# hammad.lib.data.models.fields
|
28
36
|
"field",
|
37
|
+
|
38
|
+
# hammad.lib.data.models.utils
|
29
39
|
"validator",
|
30
40
|
"is_field",
|
31
41
|
"is_model",
|
32
42
|
"model_settings",
|
33
43
|
|
34
|
-
# hammad.models.pydantic
|
44
|
+
# hammad.lib.data.models.extensions.pydantic.converters
|
35
45
|
"convert_to_pydantic_model",
|
36
46
|
"convert_to_pydantic_field",
|
47
|
+
"is_pydantic_model_class",
|
37
48
|
)
|
38
49
|
|
39
50
|
|
@@ -41,4 +52,4 @@ __getattr__ = create_getattr_importer(__all__)
|
|
41
52
|
|
42
53
|
|
43
54
|
def __dir__() -> list[str]:
|
44
|
-
return list(__all__)
|
55
|
+
return list(__all__)
|
@@ -1,19 +1,12 @@
|
|
1
|
-
"""hammad.models.pydantic
|
1
|
+
"""hammad.data.models.extensions.pydantic
|
2
2
|
|
3
3
|
Contains both models and pydantic **specific** utiltiies / resources
|
4
4
|
meant for general case usage."""
|
5
5
|
|
6
6
|
from typing import TYPE_CHECKING
|
7
|
-
from
|
7
|
+
from ....._internal import create_getattr_importer
|
8
8
|
|
9
9
|
if TYPE_CHECKING:
|
10
|
-
from .models import (
|
11
|
-
ArbitraryModel,
|
12
|
-
CacheableModel,
|
13
|
-
FastModel,
|
14
|
-
FunctionModel,
|
15
|
-
SubscriptableModel,
|
16
|
-
)
|
17
10
|
from .converters import (
|
18
11
|
convert_to_pydantic_model,
|
19
12
|
convert_to_pydantic_field,
|
@@ -27,14 +20,8 @@ if TYPE_CHECKING:
|
|
27
20
|
)
|
28
21
|
|
29
22
|
|
30
|
-
__all__ =
|
31
|
-
# hammad.
|
32
|
-
"ArbitraryModel",
|
33
|
-
"CacheableModel",
|
34
|
-
"FastModel",
|
35
|
-
"FunctionModel",
|
36
|
-
"SubscriptableModel",
|
37
|
-
# hammad.models.pydantic.converters
|
23
|
+
__all__ = [
|
24
|
+
# hammad.lib.pydantic.converters
|
38
25
|
"convert_to_pydantic_model",
|
39
26
|
"convert_to_pydantic_field",
|
40
27
|
"convert_dataclass_to_pydantic_model",
|
@@ -44,7 +31,7 @@ __all__ = (
|
|
44
31
|
"convert_type_to_pydantic_model",
|
45
32
|
"create_confirmation_pydantic_model",
|
46
33
|
"create_selection_pydantic_model",
|
47
|
-
|
34
|
+
]
|
48
35
|
|
49
36
|
|
50
37
|
__getattr__ = create_getattr_importer(__all__)
|
@@ -52,4 +39,4 @@ __getattr__ = create_getattr_importer(__all__)
|
|
52
39
|
|
53
40
|
def __dir__() -> list[str]:
|
54
41
|
"""Get the attributes of the models module."""
|
55
|
-
return
|
42
|
+
return __all__
|
@@ -1,4 +1,4 @@
|
|
1
|
-
"""hammad.data.models.pydantic.converters
|
1
|
+
"""hammad.data.models.extensions.pydantic.converters
|
2
2
|
|
3
3
|
Contains various converters for converting various objects into
|
4
4
|
a Pydantic model. These converters are used to convert
|
@@ -28,8 +28,6 @@ from typing import (
|
|
28
28
|
)
|
29
29
|
from pydantic import BaseModel, Field, create_model
|
30
30
|
|
31
|
-
from ....cache.decorators import cached
|
32
|
-
|
33
31
|
from typing import get_origin, get_args
|
34
32
|
from typing_inspect import is_generic_type
|
35
33
|
|
@@ -79,6 +77,38 @@ A mapping of types to their string representations. Used for hinting & JSON sche
|
|
79
77
|
generation.
|
80
78
|
"""
|
81
79
|
|
80
|
+
TYPE_NAME_MAPPING: Dict[Type, str] = {
|
81
|
+
int: "Integer",
|
82
|
+
float: "Float",
|
83
|
+
bool: "Boolean",
|
84
|
+
str: "String",
|
85
|
+
bytes: "Bytes",
|
86
|
+
list: "List",
|
87
|
+
tuple: "Tuple",
|
88
|
+
dict: "Dict",
|
89
|
+
set: "Set",
|
90
|
+
frozenset: "FrozenSet",
|
91
|
+
}
|
92
|
+
"""
|
93
|
+
A mapping of basic types to their semantic model names.
|
94
|
+
"""
|
95
|
+
|
96
|
+
FIELD_NAME_MAPPING: Dict[Type, str] = {
|
97
|
+
int: "value",
|
98
|
+
float: "value",
|
99
|
+
bool: "flag",
|
100
|
+
str: "text",
|
101
|
+
bytes: "data",
|
102
|
+
list: "items",
|
103
|
+
tuple: "values",
|
104
|
+
dict: "mapping",
|
105
|
+
set: "elements",
|
106
|
+
frozenset: "elements",
|
107
|
+
}
|
108
|
+
"""
|
109
|
+
A mapping of basic types to their semantic field names.
|
110
|
+
"""
|
111
|
+
|
82
112
|
|
83
113
|
# -----------------------------------------------------------------------------
|
84
114
|
# Pydantic Model Utils
|
@@ -92,6 +122,104 @@ def is_pydantic_model_class(obj: Any) -> bool:
|
|
92
122
|
return isinstance(obj, type) and issubclass(obj, BaseModel)
|
93
123
|
|
94
124
|
|
125
|
+
def generate_semantic_model_name(type_hint: Type) -> str:
|
126
|
+
"""
|
127
|
+
Generates a semantic model name based on the type.
|
128
|
+
|
129
|
+
Examples:
|
130
|
+
int -> "Integer"
|
131
|
+
str -> "String"
|
132
|
+
List[int] -> "IntegerList"
|
133
|
+
Dict[str, int] -> "StringIntegerDict"
|
134
|
+
Optional[int] -> "OptionalInteger"
|
135
|
+
Union[str, int] -> "StringIntegerUnion"
|
136
|
+
"""
|
137
|
+
# Handle basic types
|
138
|
+
if type_hint in TYPE_NAME_MAPPING:
|
139
|
+
return TYPE_NAME_MAPPING[type_hint]
|
140
|
+
|
141
|
+
# Handle Optional types
|
142
|
+
origin = get_origin(type_hint)
|
143
|
+
args = get_args(type_hint)
|
144
|
+
|
145
|
+
if origin is Union:
|
146
|
+
# Check if it's Optional (Union with None)
|
147
|
+
if type(None) in args and len(args) == 2:
|
148
|
+
# This is Optional[T]
|
149
|
+
inner_type = next(arg for arg in args if arg is not type(None))
|
150
|
+
return f"Optional{generate_semantic_model_name(inner_type)}"
|
151
|
+
else:
|
152
|
+
# Regular Union
|
153
|
+
type_names = [
|
154
|
+
generate_semantic_model_name(arg)
|
155
|
+
for arg in args
|
156
|
+
if arg is not type(None)
|
157
|
+
]
|
158
|
+
return "".join(type_names) + "Union"
|
159
|
+
|
160
|
+
# Handle generic types
|
161
|
+
if origin is not None:
|
162
|
+
origin_name = TYPE_NAME_MAPPING.get(origin, origin.__name__.capitalize())
|
163
|
+
|
164
|
+
if args:
|
165
|
+
# Generate names for type arguments
|
166
|
+
arg_names = [generate_semantic_model_name(arg) for arg in args]
|
167
|
+
if origin in (list, set, frozenset):
|
168
|
+
# For collections, append the element type
|
169
|
+
return f"{arg_names[0]}{origin_name}"
|
170
|
+
elif origin is dict:
|
171
|
+
# For dict, include both key and value types
|
172
|
+
return f"{arg_names[0]}{arg_names[1]}Dict"
|
173
|
+
elif origin is tuple:
|
174
|
+
# For tuple, join all types
|
175
|
+
return "".join(arg_names) + "Tuple"
|
176
|
+
else:
|
177
|
+
# For other generics, prepend type arguments
|
178
|
+
return "".join(arg_names) + origin_name
|
179
|
+
|
180
|
+
return origin_name
|
181
|
+
|
182
|
+
# Fallback to the type's name
|
183
|
+
if hasattr(type_hint, "__name__"):
|
184
|
+
return type_hint.__name__.capitalize()
|
185
|
+
|
186
|
+
return "GeneratedModel"
|
187
|
+
|
188
|
+
|
189
|
+
def generate_semantic_field_name(type_hint: Type) -> str:
|
190
|
+
"""
|
191
|
+
Generates a semantic field name based on the type.
|
192
|
+
|
193
|
+
Examples:
|
194
|
+
int -> "value"
|
195
|
+
str -> "text"
|
196
|
+
List[int] -> "items"
|
197
|
+
Dict[str, int] -> "mapping"
|
198
|
+
Optional[str] -> "text"
|
199
|
+
"""
|
200
|
+
# Handle basic types
|
201
|
+
if type_hint in FIELD_NAME_MAPPING:
|
202
|
+
return FIELD_NAME_MAPPING[type_hint]
|
203
|
+
|
204
|
+
# Handle Optional types - use the inner type's field name
|
205
|
+
origin = get_origin(type_hint)
|
206
|
+
args = get_args(type_hint)
|
207
|
+
|
208
|
+
if origin is Union:
|
209
|
+
# Check if it's Optional (Union with None)
|
210
|
+
if type(None) in args and len(args) == 2:
|
211
|
+
# This is Optional[T] - use inner type's field name
|
212
|
+
inner_type = next(arg for arg in args if arg is not type(None))
|
213
|
+
return generate_semantic_field_name(inner_type)
|
214
|
+
|
215
|
+
# Handle generic types - use the origin's field name
|
216
|
+
if origin is not None and origin in FIELD_NAME_MAPPING:
|
217
|
+
return FIELD_NAME_MAPPING[origin]
|
218
|
+
|
219
|
+
# Default fallback
|
220
|
+
return "value"
|
221
|
+
|
222
|
+
|
95
223
|
def get_pydantic_fields_from_function(func: Callable) -> Dict[str, Tuple[Type, Field]]:
|
96
224
|
"""
|
97
225
|
Extracts Pydantic fields from a function's signature and docstring.
|
@@ -143,7 +271,6 @@ def get_pydantic_fields_from_function(func: Callable) -> Dict[str, Tuple[Type, F
|
|
143
271
|
return {}
|
144
272
|
|
145
273
|
|
146
|
-
@cached
|
147
274
|
def convert_to_pydantic_field(
|
148
275
|
type_hint: Type,
|
149
276
|
index: Optional[int] = None,
|
@@ -155,8 +282,14 @@ def convert_to_pydantic_field(
|
|
155
282
|
Returns a dictionary mapping a generated field name to its (type, Field) tuple.
|
156
283
|
"""
|
157
284
|
try:
|
158
|
-
|
159
|
-
|
285
|
+
# Use semantic field name if no index is provided
|
286
|
+
if index is None:
|
287
|
+
field_name = generate_semantic_field_name(type_hint)
|
288
|
+
else:
|
289
|
+
# Use indexed field name for sequences
|
290
|
+
base_name = generate_semantic_field_name(type_hint)
|
291
|
+
field_name = f"{base_name}_{index}"
|
292
|
+
|
160
293
|
return {
|
161
294
|
field_name: (
|
162
295
|
type_hint,
|
@@ -178,7 +311,6 @@ def convert_to_pydantic_field(
|
|
178
311
|
# -----------------------------------------------------------------------------
|
179
312
|
|
180
313
|
|
181
|
-
@cached
|
182
314
|
def convert_dataclass_to_pydantic_model(
|
183
315
|
target: Union[Type, Any], # NOTE: DATACLASS TYPE OR INSTANCE
|
184
316
|
init: bool,
|
@@ -229,7 +361,6 @@ def convert_dataclass_to_pydantic_model(
|
|
229
361
|
return model_class
|
230
362
|
|
231
363
|
|
232
|
-
@cached
|
233
364
|
def convert_type_to_pydantic_model(
|
234
365
|
target: Type,
|
235
366
|
name: Optional[str],
|
@@ -237,19 +368,20 @@ def convert_type_to_pydantic_model(
|
|
237
368
|
field_name: Optional[str],
|
238
369
|
default: Any,
|
239
370
|
) -> Type[BaseModel]:
|
240
|
-
|
371
|
+
# Use semantic naming if no name is provided
|
372
|
+
model_name = name or generate_semantic_model_name(target)
|
373
|
+
|
241
374
|
field_mapping = convert_to_pydantic_field(
|
242
375
|
target, description=description, default=default
|
243
376
|
)
|
244
377
|
|
245
|
-
if field_name: # Override default field name
|
378
|
+
if field_name: # Override default field name if explicitly provided
|
246
379
|
current_field_def = list(field_mapping.values())[0]
|
247
380
|
field_mapping = {field_name: current_field_def}
|
248
381
|
|
249
382
|
return create_model(model_name, __doc__=(description or ""), **field_mapping)
|
250
383
|
|
251
384
|
|
252
|
-
@cached
|
253
385
|
def convert_function_to_pydantic_model(
|
254
386
|
target: Callable,
|
255
387
|
name: Optional[str],
|
@@ -263,7 +395,6 @@ def convert_function_to_pydantic_model(
|
|
263
395
|
return create_model(model_name, __doc__=model_doc, **fields)
|
264
396
|
|
265
397
|
|
266
|
-
@cached
|
267
398
|
def convert_sequence_to_pydantic_model(
|
268
399
|
target: Sequence[Type],
|
269
400
|
name: Optional[str],
|
@@ -308,7 +439,6 @@ def convert_sequence_to_pydantic_model(
|
|
308
439
|
return create_model(model_name, __doc__=(description or ""), **pydantic_fields)
|
309
440
|
|
310
441
|
|
311
|
-
@cached
|
312
442
|
def convert_dict_to_pydantic_model(
|
313
443
|
target: Dict[str, Any],
|
314
444
|
init: bool,
|
@@ -330,7 +460,6 @@ def convert_dict_to_pydantic_model(
|
|
330
460
|
return model_class
|
331
461
|
|
332
462
|
|
333
|
-
@cached
|
334
463
|
def _reconvert_to_pydantic_model_from_basemodel_instance(
|
335
464
|
target: BaseModel,
|
336
465
|
name: Optional[str],
|
@@ -563,7 +692,6 @@ def convert_to_pydantic_model(
|
|
563
692
|
# -----------------------------------------------------------------------------
|
564
693
|
|
565
694
|
|
566
|
-
@cached
|
567
695
|
def create_selection_pydantic_model(
|
568
696
|
fields: List[str],
|
569
697
|
name: str = "Selection",
|
@@ -605,7 +733,6 @@ def create_selection_pydantic_model(
|
|
605
733
|
)
|
606
734
|
|
607
735
|
|
608
|
-
@cached
|
609
736
|
def create_confirmation_pydantic_model(
|
610
737
|
name: str = "Confirmation",
|
611
738
|
description: Optional[str] = None,
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"""hammad.data.sql"""
|
2
|
+
|
3
|
+
from typing import TYPE_CHECKING
|
4
|
+
from ..._internal import create_getattr_importer
|
5
|
+
|
6
|
+
if TYPE_CHECKING:
|
7
|
+
from .types import DatabaseItemType, DatabaseItem
|
8
|
+
from .database import Database
|
9
|
+
|
10
|
+
|
11
|
+
__all__ = (
|
12
|
+
"DatabaseItemType",
|
13
|
+
"DatabaseItem",
|
14
|
+
"Database",
|
15
|
+
)
|
16
|
+
|
17
|
+
|
18
|
+
__getattr__ = create_getattr_importer(__all__)
|
19
|
+
|
20
|
+
|
21
|
+
def __dir__() -> list[str]:
|
22
|
+
"""Get the attributes of the hammad.data.sql module."""
|
23
|
+
return list(__all__)
|