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.
Files changed (137) hide show
  1. ham/__init__.py +200 -0
  2. {hammad_python-0.0.30.dist-info → hammad_python-0.0.32.dist-info}/METADATA +6 -32
  3. hammad_python-0.0.32.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.30.dist-info/RECORD +0 -135
  135. {hammad → ham}/py.typed +0 -0
  136. {hammad_python-0.0.30.dist-info → hammad_python-0.0.32.dist-info}/WHEEL +0 -0
  137. {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.30
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: ddgs>=9.0.0
29
- Requires-Dist: fasta2a>=0.5.0
30
- Requires-Dist: httpx>=0.28.1
31
- Requires-Dist: msgspec>=0.19.0
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