hammad-python 0.0.30__py3-none-any.whl → 0.0.32__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.
- ham/__init__.py +200 -0
- {hammad_python-0.0.30.dist-info → hammad_python-0.0.32.dist-info}/METADATA +6 -32
- hammad_python-0.0.32.dist-info/RECORD +6 -0
- hammad/__init__.py +0 -84
- hammad/_internal.py +0 -256
- hammad/_main.py +0 -226
- hammad/cache/__init__.py +0 -40
- hammad/cache/base_cache.py +0 -181
- hammad/cache/cache.py +0 -169
- hammad/cache/decorators.py +0 -261
- hammad/cache/file_cache.py +0 -80
- hammad/cache/ttl_cache.py +0 -74
- hammad/cli/__init__.py +0 -33
- hammad/cli/animations.py +0 -573
- hammad/cli/plugins.py +0 -867
- hammad/cli/styles/__init__.py +0 -55
- hammad/cli/styles/settings.py +0 -139
- hammad/cli/styles/types.py +0 -358
- hammad/cli/styles/utils.py +0 -634
- hammad/data/__init__.py +0 -90
- hammad/data/collections/__init__.py +0 -49
- hammad/data/collections/collection.py +0 -326
- hammad/data/collections/indexes/__init__.py +0 -37
- hammad/data/collections/indexes/qdrant/__init__.py +0 -1
- hammad/data/collections/indexes/qdrant/index.py +0 -723
- hammad/data/collections/indexes/qdrant/settings.py +0 -94
- hammad/data/collections/indexes/qdrant/utils.py +0 -210
- hammad/data/collections/indexes/tantivy/__init__.py +0 -1
- hammad/data/collections/indexes/tantivy/index.py +0 -426
- hammad/data/collections/indexes/tantivy/settings.py +0 -40
- hammad/data/collections/indexes/tantivy/utils.py +0 -176
- hammad/data/configurations/__init__.py +0 -35
- hammad/data/configurations/configuration.py +0 -564
- hammad/data/models/__init__.py +0 -50
- hammad/data/models/extensions/__init__.py +0 -4
- hammad/data/models/extensions/pydantic/__init__.py +0 -42
- hammad/data/models/extensions/pydantic/converters.py +0 -759
- hammad/data/models/fields.py +0 -546
- hammad/data/models/model.py +0 -1078
- hammad/data/models/utils.py +0 -280
- hammad/data/sql/__init__.py +0 -24
- hammad/data/sql/database.py +0 -576
- hammad/data/sql/types.py +0 -127
- hammad/data/types/__init__.py +0 -75
- hammad/data/types/file.py +0 -431
- hammad/data/types/multimodal/__init__.py +0 -36
- hammad/data/types/multimodal/audio.py +0 -200
- hammad/data/types/multimodal/image.py +0 -182
- hammad/data/types/text.py +0 -1308
- hammad/formatting/__init__.py +0 -33
- hammad/formatting/json/__init__.py +0 -27
- hammad/formatting/json/converters.py +0 -158
- hammad/formatting/text/__init__.py +0 -63
- hammad/formatting/text/converters.py +0 -723
- hammad/formatting/text/markdown.py +0 -131
- hammad/formatting/yaml/__init__.py +0 -26
- hammad/formatting/yaml/converters.py +0 -5
- hammad/genai/__init__.py +0 -217
- hammad/genai/a2a/__init__.py +0 -32
- hammad/genai/a2a/workers.py +0 -552
- hammad/genai/agents/__init__.py +0 -59
- hammad/genai/agents/agent.py +0 -1973
- hammad/genai/agents/run.py +0 -1024
- hammad/genai/agents/types/__init__.py +0 -42
- hammad/genai/agents/types/agent_context.py +0 -13
- hammad/genai/agents/types/agent_event.py +0 -128
- hammad/genai/agents/types/agent_hooks.py +0 -220
- hammad/genai/agents/types/agent_messages.py +0 -31
- hammad/genai/agents/types/agent_response.py +0 -125
- hammad/genai/agents/types/agent_stream.py +0 -327
- hammad/genai/graphs/__init__.py +0 -125
- hammad/genai/graphs/_utils.py +0 -190
- hammad/genai/graphs/base.py +0 -1828
- hammad/genai/graphs/plugins.py +0 -316
- hammad/genai/graphs/types.py +0 -638
- hammad/genai/models/__init__.py +0 -1
- hammad/genai/models/embeddings/__init__.py +0 -43
- hammad/genai/models/embeddings/model.py +0 -226
- hammad/genai/models/embeddings/run.py +0 -163
- hammad/genai/models/embeddings/types/__init__.py +0 -37
- hammad/genai/models/embeddings/types/embedding_model_name.py +0 -75
- hammad/genai/models/embeddings/types/embedding_model_response.py +0 -76
- hammad/genai/models/embeddings/types/embedding_model_run_params.py +0 -66
- hammad/genai/models/embeddings/types/embedding_model_settings.py +0 -47
- hammad/genai/models/language/__init__.py +0 -57
- hammad/genai/models/language/model.py +0 -1098
- hammad/genai/models/language/run.py +0 -878
- hammad/genai/models/language/types/__init__.py +0 -40
- hammad/genai/models/language/types/language_model_instructor_mode.py +0 -47
- hammad/genai/models/language/types/language_model_messages.py +0 -28
- hammad/genai/models/language/types/language_model_name.py +0 -239
- hammad/genai/models/language/types/language_model_request.py +0 -127
- hammad/genai/models/language/types/language_model_response.py +0 -217
- hammad/genai/models/language/types/language_model_response_chunk.py +0 -56
- hammad/genai/models/language/types/language_model_settings.py +0 -89
- hammad/genai/models/language/types/language_model_stream.py +0 -600
- hammad/genai/models/language/utils/__init__.py +0 -28
- hammad/genai/models/language/utils/requests.py +0 -421
- hammad/genai/models/language/utils/structured_outputs.py +0 -135
- hammad/genai/models/model_provider.py +0 -4
- hammad/genai/models/multimodal.py +0 -47
- hammad/genai/models/reranking.py +0 -26
- hammad/genai/types/__init__.py +0 -1
- hammad/genai/types/base.py +0 -215
- hammad/genai/types/history.py +0 -290
- hammad/genai/types/tools.py +0 -507
- hammad/logging/__init__.py +0 -35
- hammad/logging/decorators.py +0 -834
- hammad/logging/logger.py +0 -1018
- hammad/mcp/__init__.py +0 -53
- hammad/mcp/client/__init__.py +0 -35
- hammad/mcp/client/client.py +0 -624
- hammad/mcp/client/client_service.py +0 -400
- hammad/mcp/client/settings.py +0 -178
- hammad/mcp/servers/__init__.py +0 -26
- hammad/mcp/servers/launcher.py +0 -1161
- hammad/runtime/__init__.py +0 -32
- hammad/runtime/decorators.py +0 -142
- hammad/runtime/run.py +0 -299
- hammad/service/__init__.py +0 -49
- hammad/service/create.py +0 -527
- hammad/service/decorators.py +0 -283
- hammad/types.py +0 -288
- hammad/typing/__init__.py +0 -435
- hammad/web/__init__.py +0 -43
- hammad/web/http/__init__.py +0 -1
- hammad/web/http/client.py +0 -944
- hammad/web/models.py +0 -275
- hammad/web/openapi/__init__.py +0 -1
- hammad/web/openapi/client.py +0 -740
- hammad/web/search/__init__.py +0 -1
- hammad/web/search/client.py +0 -1023
- hammad/web/utils.py +0 -472
- hammad_python-0.0.30.dist-info/RECORD +0 -135
- {hammad → ham}/py.typed +0 -0
- {hammad_python-0.0.30.dist-info → hammad_python-0.0.32.dist-info}/WHEEL +0 -0
- {hammad_python-0.0.30.dist-info → hammad_python-0.0.32.dist-info}/licenses/LICENSE +0 -0
ham/__init__.py
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
"""ham
|
2
|
+
|
3
|
+
```markdown
|
4
|
+
## `hammad-python`
|
5
|
+
|
6
|
+
Fun bunch of stuff ***:)***
|
7
|
+
|
8
|
+
This module is a collection over various sub-packages that
|
9
|
+
define the `ham` namespace. These packages include:
|
10
|
+
|
11
|
+
- `hammad-python-core`
|
12
|
+
- `hammad-python-data`
|
13
|
+
- `hammad-python-genai`
|
14
|
+
- `hammad-python-http`
|
15
|
+
```
|
16
|
+
|
17
|
+
You can access a variety of the primary resources from these modules
|
18
|
+
directly from this top level module.
|
19
|
+
"""
|
20
|
+
|
21
|
+
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
|
22
|
+
|
23
|
+
from typing import TYPE_CHECKING
|
24
|
+
|
25
|
+
try:
|
26
|
+
from ham.core._internal import type_checking_importer
|
27
|
+
except ImportError:
|
28
|
+
from .core._internal import type_checking_importer # type: ignore
|
29
|
+
|
30
|
+
|
31
|
+
if TYPE_CHECKING:
|
32
|
+
try:
|
33
|
+
# ham.core
|
34
|
+
from ham.core._internal._logging import set_debug, set_verbose
|
35
|
+
from ham.core.cache import cached, auto_cached
|
36
|
+
from ham.core.cli import print, animate, input, log, log_iterable, log_progress
|
37
|
+
from ham.core.conversion import (
|
38
|
+
convert_to_text,
|
39
|
+
convert_to_json_schema,
|
40
|
+
convert_to_model,
|
41
|
+
convert_to_pydantic_model,
|
42
|
+
)
|
43
|
+
from ham.core.logging import get_logger, trace, trace_http
|
44
|
+
|
45
|
+
# ham.data
|
46
|
+
from ham.data.collections import (
|
47
|
+
create_collection,
|
48
|
+
)
|
49
|
+
|
50
|
+
# ham.genai
|
51
|
+
from ham.genai.models.embeddings import run_embedding_model
|
52
|
+
from ham.genai.models.language import run_language_model
|
53
|
+
from ham.genai.models.reranking import run_reranking_model
|
54
|
+
from ham.genai.models.multimodal import (
|
55
|
+
run_image_generation_model,
|
56
|
+
run_transcription_model,
|
57
|
+
run_tts_model,
|
58
|
+
)
|
59
|
+
from ham.genai.agents import create_agent, run_agent, run_agent_iter
|
60
|
+
from ham.genai.graphs import (
|
61
|
+
# NOTE: lol... uh i just really wanted everything to be lowercase..
|
62
|
+
# this may need a once over
|
63
|
+
BaseGraph as basegraph,
|
64
|
+
action as graphaction,
|
65
|
+
)
|
66
|
+
from ham.genai.prompted import (
|
67
|
+
prompted_fn as prompted,
|
68
|
+
contextualize,
|
69
|
+
itemize,
|
70
|
+
select,
|
71
|
+
tool,
|
72
|
+
)
|
73
|
+
from ham.genai.a2a import as_a2a_app
|
74
|
+
|
75
|
+
# ham.http
|
76
|
+
from ham.http import (
|
77
|
+
create_client,
|
78
|
+
create_openapi_client,
|
79
|
+
create_http_client,
|
80
|
+
create_mcp_client,
|
81
|
+
create_server,
|
82
|
+
create_fast_service,
|
83
|
+
function_server,
|
84
|
+
function_mcp_server,
|
85
|
+
run_web_request,
|
86
|
+
read_web_page,
|
87
|
+
read_web_pages,
|
88
|
+
run_web_search,
|
89
|
+
run_news_search,
|
90
|
+
extract_web_page_links,
|
91
|
+
create_search_client,
|
92
|
+
)
|
93
|
+
except ImportError:
|
94
|
+
from ham.core._internal import ( # type: ignore
|
95
|
+
set_debug,
|
96
|
+
set_verbose,
|
97
|
+
)
|
98
|
+
from ham.data import ( # type: ignore
|
99
|
+
create_collection,
|
100
|
+
)
|
101
|
+
from ham.genai import ( # type: ignore
|
102
|
+
create_agent,
|
103
|
+
run_agent,
|
104
|
+
run_agent_iter,
|
105
|
+
run_embedding_model,
|
106
|
+
run_language_model,
|
107
|
+
run_reranking_model,
|
108
|
+
run_image_generation_model,
|
109
|
+
run_transcription_model,
|
110
|
+
run_tts_model,
|
111
|
+
basegraph,
|
112
|
+
graphaction,
|
113
|
+
prompted,
|
114
|
+
contextualize,
|
115
|
+
itemize,
|
116
|
+
select,
|
117
|
+
tool,
|
118
|
+
)
|
119
|
+
from ham.http import ( # type: ignore
|
120
|
+
create_client,
|
121
|
+
create_openapi_client,
|
122
|
+
create_http_client,
|
123
|
+
create_mcp_client,
|
124
|
+
create_server,
|
125
|
+
create_fast_service,
|
126
|
+
function_server,
|
127
|
+
function_mcp_server,
|
128
|
+
run_web_request,
|
129
|
+
read_web_page,
|
130
|
+
read_web_pages,
|
131
|
+
run_web_search,
|
132
|
+
run_news_search,
|
133
|
+
extract_web_page_links,
|
134
|
+
create_search_client,
|
135
|
+
)
|
136
|
+
|
137
|
+
|
138
|
+
__all__ = (
|
139
|
+
# ham.core
|
140
|
+
"set_debug",
|
141
|
+
"set_verbose",
|
142
|
+
"cached",
|
143
|
+
"auto_cached",
|
144
|
+
"print",
|
145
|
+
"animate",
|
146
|
+
"input",
|
147
|
+
"log",
|
148
|
+
"log_iterable",
|
149
|
+
"log_progress",
|
150
|
+
"convert_to_text",
|
151
|
+
"convert_to_json_schema",
|
152
|
+
"convert_to_model",
|
153
|
+
"convert_to_pydantic_model",
|
154
|
+
"get_logger",
|
155
|
+
"trace",
|
156
|
+
"trace_http",
|
157
|
+
# ham.data
|
158
|
+
"create_collection",
|
159
|
+
# ham.genai
|
160
|
+
"create_agent",
|
161
|
+
"run_agent",
|
162
|
+
"run_agent_iter",
|
163
|
+
"run_embedding_model",
|
164
|
+
"run_language_model",
|
165
|
+
"run_reranking_model",
|
166
|
+
"run_image_generation_model",
|
167
|
+
"run_transcription_model",
|
168
|
+
"run_tts_model",
|
169
|
+
"basegraph",
|
170
|
+
"graphaction",
|
171
|
+
"prompted",
|
172
|
+
"contextualize",
|
173
|
+
"itemize",
|
174
|
+
"select",
|
175
|
+
"tool",
|
176
|
+
# ham.http
|
177
|
+
"create_client",
|
178
|
+
"create_openapi_client",
|
179
|
+
"create_http_client",
|
180
|
+
"create_mcp_client",
|
181
|
+
"create_server",
|
182
|
+
"create_fast_service",
|
183
|
+
"function_server",
|
184
|
+
"function_mcp_server",
|
185
|
+
"run_web_request",
|
186
|
+
"read_web_page",
|
187
|
+
"read_web_pages",
|
188
|
+
"run_web_search",
|
189
|
+
"run_news_search",
|
190
|
+
"extract_web_page_links",
|
191
|
+
"create_search_client",
|
192
|
+
)
|
193
|
+
|
194
|
+
|
195
|
+
__getattr__ = type_checking_importer(__all__)
|
196
|
+
|
197
|
+
|
198
|
+
def __dir__() -> list[str]:
|
199
|
+
"""Get the attributes of the hammad module."""
|
200
|
+
return __all__
|
@@ -1,6 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: hammad-python
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.32
|
4
|
+
Summary: Personal Python utilities and tools
|
4
5
|
Author-email: Hammad Saeed <hammadaidev@gmail.com>
|
5
6
|
License: MIT License
|
6
7
|
|
@@ -25,37 +26,10 @@ License: MIT License
|
|
25
26
|
SOFTWARE.
|
26
27
|
License-File: LICENSE
|
27
28
|
Requires-Python: >=3.11
|
28
|
-
Requires-Dist:
|
29
|
-
Requires-Dist:
|
30
|
-
Requires-Dist:
|
31
|
-
Requires-Dist:
|
32
|
-
Requires-Dist: nest-asyncio>=1.6.0
|
33
|
-
Requires-Dist: pydantic>=2.11.7
|
34
|
-
Requires-Dist: rich>=14.0.0
|
35
|
-
Requires-Dist: selectolax>=0.3.31
|
36
|
-
Requires-Dist: sqlalchemy>=2.0.41
|
37
|
-
Requires-Dist: tantivy>=0.24.0
|
38
|
-
Requires-Dist: tenacity>=8.2.3
|
39
|
-
Requires-Dist: typing-inspect>=0.9.0
|
40
|
-
Provides-Extra: ai
|
41
|
-
Requires-Dist: instructor>=1.9.0; extra == 'ai'
|
42
|
-
Requires-Dist: litellm>=1.73.6; extra == 'ai'
|
43
|
-
Requires-Dist: qdrant-client>=1.14.3; extra == 'ai'
|
44
|
-
Provides-Extra: genai
|
45
|
-
Requires-Dist: fastapi>=0.115.6; extra == 'genai'
|
46
|
-
Requires-Dist: instructor>=1.9.0; extra == 'genai'
|
47
|
-
Requires-Dist: litellm>=1.73.6; extra == 'genai'
|
48
|
-
Requires-Dist: mcp>=1.10.1; extra == 'genai'
|
49
|
-
Requires-Dist: pydantic-graph>=0.4.2; extra == 'genai'
|
50
|
-
Requires-Dist: qdrant-client>=1.14.3; extra == 'genai'
|
51
|
-
Requires-Dist: uvicorn>=0.34.0; extra == 'genai'
|
52
|
-
Provides-Extra: graph
|
53
|
-
Requires-Dist: pydantic-graph>=0.4.2; extra == 'graph'
|
54
|
-
Provides-Extra: mcp
|
55
|
-
Requires-Dist: mcp>=1.10.1; extra == 'mcp'
|
56
|
-
Provides-Extra: serve
|
57
|
-
Requires-Dist: fastapi>=0.115.6; extra == 'serve'
|
58
|
-
Requires-Dist: uvicorn>=0.34.0; extra == 'serve'
|
29
|
+
Requires-Dist: hammad-python-core>=0.0.2
|
30
|
+
Requires-Dist: hammad-python-data>=0.0.2
|
31
|
+
Requires-Dist: hammad-python-genai>=0.0.2
|
32
|
+
Requires-Dist: hammad-python-http>=0.0.2
|
59
33
|
Description-Content-Type: text/markdown
|
60
34
|
|
61
35
|
## hammad-python
|
@@ -0,0 +1,6 @@
|
|
1
|
+
ham/__init__.py,sha256=J1ye-mmybVCdFvMaYJjYVNJa7CEME4W6bIzLuGsQvKE,5215
|
2
|
+
ham/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
+
hammad_python-0.0.32.dist-info/METADATA,sha256=Nn4_482LfJu6FYy39l6SW0qkTTHKqK_rrizDS7SxhY0,5454
|
4
|
+
hammad_python-0.0.32.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
5
|
+
hammad_python-0.0.32.dist-info/licenses/LICENSE,sha256=h74yFUWjbBaodcWG5wNmm30npjl8obVcxD-1nQfUp2I,1069
|
6
|
+
hammad_python-0.0.32.dist-info/RECORD,,
|
hammad/__init__.py
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
"""hammad-python
|
2
|
-
|
3
|
-
A vast ecosystem of ('nightly', dont trust literally any interface to stay the same
|
4
|
-
for more than a few days) resources, utilities and components for building applications
|
5
|
-
in Python."""
|
6
|
-
|
7
|
-
from typing import TYPE_CHECKING
|
8
|
-
from ._internal import create_getattr_importer as __hammad_importer__
|
9
|
-
|
10
|
-
|
11
|
-
if TYPE_CHECKING:
|
12
|
-
from . import types
|
13
|
-
|
14
|
-
# 'builtins'
|
15
|
-
from .cache import cached
|
16
|
-
from .cli import print, input, animate
|
17
|
-
from .genai import (
|
18
|
-
BaseGraph,
|
19
|
-
plugin,
|
20
|
-
action,
|
21
|
-
select,
|
22
|
-
agent_decorator as agent,
|
23
|
-
language_model_decorator as llm,
|
24
|
-
run_embedding_model as embedding,
|
25
|
-
define_tool as tool,
|
26
|
-
)
|
27
|
-
from .data.collections import create_collection as collection
|
28
|
-
from .formatting.text import convert_to_text as markdown
|
29
|
-
from .mcp import launch_mcp_servers
|
30
|
-
from .logging import create_logger as logger
|
31
|
-
from .service import serve, serve_mcp
|
32
|
-
from .web import (
|
33
|
-
run_web_search as web_search,
|
34
|
-
run_web_request as web_request,
|
35
|
-
)
|
36
|
-
|
37
|
-
from ._main import (
|
38
|
-
to,
|
39
|
-
run,
|
40
|
-
fn,
|
41
|
-
new,
|
42
|
-
read,
|
43
|
-
settings,
|
44
|
-
)
|
45
|
-
|
46
|
-
|
47
|
-
__all__ = (
|
48
|
-
# types
|
49
|
-
"types",
|
50
|
-
# -- 'builtins'
|
51
|
-
"cached",
|
52
|
-
"print",
|
53
|
-
"animate",
|
54
|
-
"input",
|
55
|
-
"llm",
|
56
|
-
"agent",
|
57
|
-
"embedding",
|
58
|
-
"tool",
|
59
|
-
"markdown",
|
60
|
-
"launch_mcp_servers",
|
61
|
-
"action",
|
62
|
-
"plugin",
|
63
|
-
"select",
|
64
|
-
"BaseGraph",
|
65
|
-
"collection",
|
66
|
-
"logger",
|
67
|
-
"serve",
|
68
|
-
"serve_mcp",
|
69
|
-
"web_search",
|
70
|
-
"web_request",
|
71
|
-
"to",
|
72
|
-
"run",
|
73
|
-
"fn",
|
74
|
-
"new",
|
75
|
-
"read",
|
76
|
-
"settings",
|
77
|
-
)
|
78
|
-
|
79
|
-
|
80
|
-
__getattr__ = __hammad_importer__(__all__)
|
81
|
-
|
82
|
-
|
83
|
-
def __dir__() -> list[str]:
|
84
|
-
return list(__all__)
|
hammad/_internal.py
DELETED
@@ -1,256 +0,0 @@
|
|
1
|
-
"""hammad._internal
|
2
|
-
|
3
|
-
Internal utilities"""
|
4
|
-
|
5
|
-
from typing import Any, Callable, List, Tuple, Union
|
6
|
-
import inspect
|
7
|
-
import ast
|
8
|
-
import hashlib
|
9
|
-
|
10
|
-
# pretty
|
11
|
-
from rich.traceback import install
|
12
|
-
|
13
|
-
install()
|
14
|
-
|
15
|
-
__all__ = ("create_getattr_importer",)
|
16
|
-
|
17
|
-
|
18
|
-
class GetAttrImporterError(Exception):
|
19
|
-
"""An error that occurs when the `create_getattr_importer` function
|
20
|
-
fails to create a lazy loader function."""
|
21
|
-
|
22
|
-
|
23
|
-
class GetAttrImporterCache:
|
24
|
-
"""Minimal cache implementation for internal use only
|
25
|
-
within the `create_getattr_importer` function."""
|
26
|
-
|
27
|
-
def __init__(self, maxsize: int = 128):
|
28
|
-
self.maxsize = maxsize
|
29
|
-
self._cache: dict[str, Any] = {}
|
30
|
-
|
31
|
-
def _make_key(self, data: str) -> str:
|
32
|
-
"""Create a simple hash key from string data."""
|
33
|
-
return hashlib.sha256(data.encode("utf-8")).hexdigest()[:16]
|
34
|
-
|
35
|
-
def get(self, key: str, default: Any = None) -> Any:
|
36
|
-
"""Get value from cache."""
|
37
|
-
return self._cache.get(key, default)
|
38
|
-
|
39
|
-
def set(self, key: str, value: Any) -> None:
|
40
|
-
"""Set value in cache with basic LRU eviction."""
|
41
|
-
if len(self._cache) >= self.maxsize and key not in self._cache:
|
42
|
-
# Simple eviction: remove oldest (first) item
|
43
|
-
oldest_key = next(iter(self._cache))
|
44
|
-
del self._cache[oldest_key]
|
45
|
-
self._cache[key] = value
|
46
|
-
|
47
|
-
def cached_call(self, func: Callable[[str], Any]) -> Callable[[str], Any]:
|
48
|
-
"""Decorator to cache function calls."""
|
49
|
-
|
50
|
-
def wrapper(arg: str) -> Any:
|
51
|
-
key = self._make_key(arg)
|
52
|
-
result = self.get(key)
|
53
|
-
if result is None:
|
54
|
-
result = func(arg)
|
55
|
-
self.set(key, result)
|
56
|
-
return result
|
57
|
-
|
58
|
-
return wrapper
|
59
|
-
|
60
|
-
|
61
|
-
# NOTE:
|
62
|
-
# SINGLETON
|
63
|
-
GETATTR_IMPORTER_PARSE_CACHE = GetAttrImporterCache(maxsize=64)
|
64
|
-
"""Library-wide singleton instance providing caching for the
|
65
|
-
`_parse_type_checking_imports` function."""
|
66
|
-
|
67
|
-
|
68
|
-
GETATTR_IMPORTER_TYPE_CHECKING_CACHE = {}
|
69
|
-
"""Cache for the `_parse_type_checking_imports` function."""
|
70
|
-
|
71
|
-
|
72
|
-
def _parse_type_checking_imports(source_code: str) -> dict[str, tuple[str, str]]:
|
73
|
-
"""Parses the TYPE_CHECKING imports from a source code file, to create
|
74
|
-
a dictionary of local names to (module_path, original_name) tuples.
|
75
|
-
|
76
|
-
This is used to create the mapping used within the `_create_getattr_importer_from_import_dict`
|
77
|
-
function.
|
78
|
-
|
79
|
-
Args:
|
80
|
-
source_code : The source code to parse
|
81
|
-
|
82
|
-
Returns:
|
83
|
-
A dictionary mapping local names to (module_path, original_name) tuples
|
84
|
-
"""
|
85
|
-
|
86
|
-
@GETATTR_IMPORTER_PARSE_CACHE.cached_call
|
87
|
-
def _exec(source_code: str) -> dict[str, tuple[str, str]]:
|
88
|
-
tree = ast.parse(source_code)
|
89
|
-
imports = {}
|
90
|
-
|
91
|
-
# Walk through the AST and find TYPE_CHECKING blocks
|
92
|
-
for node in ast.walk(tree):
|
93
|
-
if isinstance(node, ast.If):
|
94
|
-
# Check if this is a TYPE_CHECKING block
|
95
|
-
is_type_checking = False
|
96
|
-
|
97
|
-
if isinstance(node.test, ast.Name) and node.test.id == "TYPE_CHECKING":
|
98
|
-
is_type_checking = True
|
99
|
-
elif isinstance(node.test, ast.Attribute):
|
100
|
-
if (
|
101
|
-
isinstance(node.test.value, ast.Name)
|
102
|
-
and node.test.value.id == "typing"
|
103
|
-
and node.test.attr == "TYPE_CHECKING"
|
104
|
-
):
|
105
|
-
is_type_checking = True
|
106
|
-
|
107
|
-
if is_type_checking:
|
108
|
-
# Process imports in this block
|
109
|
-
for stmt in node.body:
|
110
|
-
if isinstance(stmt, ast.ImportFrom) and stmt.module:
|
111
|
-
# Only add '.' prefix for relative imports
|
112
|
-
# If stmt.level > 0, it's already a relative import
|
113
|
-
# If stmt.level == 0 and module doesn't start with '.', it's absolute
|
114
|
-
if stmt.level > 0:
|
115
|
-
# Already relative import
|
116
|
-
module_path = "." * stmt.level + (stmt.module or "")
|
117
|
-
elif stmt.module.startswith("."):
|
118
|
-
# Explicit relative import
|
119
|
-
module_path = stmt.module
|
120
|
-
elif any(
|
121
|
-
stmt.module.startswith(name)
|
122
|
-
for name in ["litellm", "openai", "instructor", "httpx"]
|
123
|
-
):
|
124
|
-
# Known absolute third-party imports
|
125
|
-
module_path = stmt.module
|
126
|
-
else:
|
127
|
-
# Default to relative import for internal modules
|
128
|
-
module_path = f".{stmt.module}"
|
129
|
-
|
130
|
-
for alias in stmt.names:
|
131
|
-
original_name = alias.name
|
132
|
-
local_name = alias.asname or original_name
|
133
|
-
imports[local_name] = (module_path, original_name)
|
134
|
-
|
135
|
-
return imports
|
136
|
-
|
137
|
-
return _exec(source_code)
|
138
|
-
|
139
|
-
|
140
|
-
def _create_getattr_importer_from_import_dict(
|
141
|
-
imports_dict: dict[str, tuple[str, str]],
|
142
|
-
package: str,
|
143
|
-
all_attrs: Union[Tuple[str, ...], List[str]],
|
144
|
-
) -> Callable[[str], Any]:
|
145
|
-
"""Creates a lazy loader function for the `__getattr__` method
|
146
|
-
within `__init__.py` modules in Python packages.
|
147
|
-
|
148
|
-
Args:
|
149
|
-
imports_dict : Dictionary mapping attribute names to (module_path, original_name) tuples
|
150
|
-
package : The package name for import_module
|
151
|
-
all_attrs : List of all valid attributes for this module
|
152
|
-
|
153
|
-
Returns:
|
154
|
-
A __getattr__ function that lazily imports modules
|
155
|
-
"""
|
156
|
-
from importlib import import_module
|
157
|
-
|
158
|
-
cache = {}
|
159
|
-
|
160
|
-
def __getattr__(name: str) -> Any:
|
161
|
-
if name in cache:
|
162
|
-
return cache[name]
|
163
|
-
|
164
|
-
if name in imports_dict:
|
165
|
-
module_path, original_name = imports_dict[name]
|
166
|
-
module = import_module(module_path, package)
|
167
|
-
result = getattr(module, original_name)
|
168
|
-
cache[name] = result
|
169
|
-
return result
|
170
|
-
|
171
|
-
# Try to import as a submodule
|
172
|
-
try:
|
173
|
-
module_path = f".{name}"
|
174
|
-
module = import_module(module_path, package)
|
175
|
-
cache[name] = module
|
176
|
-
return module
|
177
|
-
except ImportError:
|
178
|
-
pass
|
179
|
-
|
180
|
-
raise GetAttrImporterError(f"module '{package}' has no attribute '{name}'")
|
181
|
-
|
182
|
-
return __getattr__
|
183
|
-
|
184
|
-
|
185
|
-
def create_getattr_importer(
|
186
|
-
all: Union[Tuple[str, ...], List[str]],
|
187
|
-
) -> Callable[[str], Any]:
|
188
|
-
"""Loader used internally within the `hammad` package to create lazy
|
189
|
-
loaders within `__init__.py` modules using the `TYPE_CHECKING` and
|
190
|
-
`all` source code within files.
|
191
|
-
|
192
|
-
This function is meant to be set as the `__getattr__` method / var
|
193
|
-
within modules to allow for direct lazy loading of attributes.
|
194
|
-
|
195
|
-
Example:
|
196
|
-
|
197
|
-
```
|
198
|
-
# Create a module that contains some imports and TYPE_CHECKING
|
199
|
-
from typing import TYPE_CHECKING
|
200
|
-
from hammad.performance.imports import create_getattr_importer
|
201
|
-
|
202
|
-
if TYPE_CHECKING:
|
203
|
-
from functools import wraps
|
204
|
-
|
205
|
-
all = ("wraps")
|
206
|
-
|
207
|
-
__getattr__ = create_getattr_importer(all)
|
208
|
-
|
209
|
-
# Now, when you import this module, the `wraps` attribute will be
|
210
|
-
# lazily loaded when it is first accessed.
|
211
|
-
```
|
212
|
-
|
213
|
-
Args:
|
214
|
-
all : The `all` tuple from the calling module
|
215
|
-
|
216
|
-
Returns:
|
217
|
-
A __getattr__ function that lazily imports modules
|
218
|
-
"""
|
219
|
-
# Get the calling module's frame
|
220
|
-
frame = inspect.currentframe()
|
221
|
-
if frame is None or frame.f_back is None:
|
222
|
-
raise RuntimeError("Cannot determine calling module")
|
223
|
-
|
224
|
-
calling_frame = frame.f_back
|
225
|
-
module_name = calling_frame.f_globals.get("__name__", "")
|
226
|
-
package = calling_frame.f_globals.get("__package__", "")
|
227
|
-
filename = calling_frame.f_globals.get("__file__", "")
|
228
|
-
|
229
|
-
# Check cache first
|
230
|
-
cache_key = (filename, tuple(all))
|
231
|
-
if cache_key in GETATTR_IMPORTER_TYPE_CHECKING_CACHE:
|
232
|
-
return GETATTR_IMPORTER_TYPE_CHECKING_CACHE[cache_key]
|
233
|
-
|
234
|
-
# Read the source file
|
235
|
-
try:
|
236
|
-
with open(filename, "r") as f:
|
237
|
-
source_code = f.read()
|
238
|
-
except (IOError, OSError):
|
239
|
-
# Fallback: try to get source from the module
|
240
|
-
import sys
|
241
|
-
|
242
|
-
module = sys.modules.get(module_name)
|
243
|
-
if module:
|
244
|
-
source_code = inspect.getsource(module)
|
245
|
-
else:
|
246
|
-
raise RuntimeError(f"Cannot read source for module {module_name}")
|
247
|
-
|
248
|
-
# Parse the source to extract TYPE_CHECKING imports
|
249
|
-
imports_map = _parse_type_checking_imports(source_code)
|
250
|
-
|
251
|
-
# Filter to only include exports that are in __all__
|
252
|
-
filtered_map = {name: path for name, path in imports_map.items() if name in all}
|
253
|
-
|
254
|
-
loader = _create_getattr_importer_from_import_dict(filtered_map, package, all)
|
255
|
-
GETATTR_IMPORTER_TYPE_CHECKING_CACHE[cache_key] = loader
|
256
|
-
return loader
|