Skip to content

Commit fd2e46b

Browse files
committed
Optimize root import time with lazy reexports
1 parent 04b468d commit fd2e46b

3 files changed

Lines changed: 219 additions & 11 deletions

File tree

src/anthropic/__init__.py

Lines changed: 137 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

3+
from __future__ import annotations
4+
35
import typing as _t
46

5-
from . import types
67
from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given
78
from ._utils import file_from_path
89
from ._client import (
@@ -45,7 +46,64 @@
4546
)
4647
from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient
4748
from ._utils._logs import setup_logging as _setup_logging
48-
from .lib._parse._transform import transform_schema
49+
50+
if _t.TYPE_CHECKING:
51+
from . import types as types
52+
from .lib.aws import AnthropicAWS as AnthropicAWS, AsyncAnthropicAWS as AsyncAnthropicAWS
53+
from .lib.tools import beta_tool as beta_tool, beta_async_tool as beta_async_tool
54+
from .lib.vertex import AnthropicVertex as AnthropicVertex, AsyncAnthropicVertex as AsyncAnthropicVertex
55+
from .lib.bedrock import (
56+
AnthropicBedrock as AnthropicBedrock,
57+
AsyncAnthropicBedrock as AsyncAnthropicBedrock,
58+
AnthropicBedrockMantle as AnthropicBedrockMantle,
59+
AsyncAnthropicBedrockMantle as AsyncAnthropicBedrockMantle,
60+
)
61+
from .lib.foundry import AnthropicFoundry as AnthropicFoundry, AsyncAnthropicFoundry as AsyncAnthropicFoundry
62+
from .lib.streaming import (
63+
TextEvent as TextEvent,
64+
BetaTextEvent as BetaTextEvent,
65+
MessageStream as MessageStream,
66+
InputJsonEvent as InputJsonEvent,
67+
MessageStopEvent as MessageStopEvent,
68+
BetaMessageStream as BetaMessageStream,
69+
AsyncMessageStream as AsyncMessageStream,
70+
BetaInputJsonEvent as BetaInputJsonEvent,
71+
MessageStreamEvent as MessageStreamEvent,
72+
ParsedBetaTextEvent as ParsedBetaTextEvent,
73+
MessageStreamManager as MessageStreamManager,
74+
ContentBlockStopEvent as ContentBlockStopEvent,
75+
BetaAsyncMessageStream as BetaAsyncMessageStream,
76+
BetaMessageStreamEvent as BetaMessageStreamEvent,
77+
ParsedMessageStopEvent as ParsedMessageStopEvent,
78+
BetaMessageStreamManager as BetaMessageStreamManager,
79+
ParsedMessageStreamEvent as ParsedMessageStreamEvent,
80+
AsyncMessageStreamManager as AsyncMessageStreamManager,
81+
BetaContentBlockStopEvent as BetaContentBlockStopEvent,
82+
ParsedBetaMessageStopEvent as ParsedBetaMessageStopEvent,
83+
ParsedContentBlockStopEvent as ParsedContentBlockStopEvent,
84+
ParsedBetaMessageStreamEvent as ParsedBetaMessageStreamEvent,
85+
BetaAsyncMessageStreamManager as BetaAsyncMessageStreamManager,
86+
ParsedBetaContentBlockStopEvent as ParsedBetaContentBlockStopEvent,
87+
)
88+
from .lib.credentials import (
89+
EnvToken as EnvToken,
90+
TokenCache as TokenCache,
91+
AccessToken as AccessToken,
92+
StaticToken as StaticToken,
93+
InMemoryConfig as InMemoryConfig,
94+
AccessTokenAuth as AccessTokenAuth,
95+
CredentialsFile as CredentialsFile,
96+
CredentialResult as CredentialResult,
97+
IdentityTokenFile as IdentityTokenFile,
98+
AccessTokenProvider as AccessTokenProvider,
99+
IdentityTokenProvider as IdentityTokenProvider,
100+
WorkloadIdentityError as WorkloadIdentityError,
101+
WorkloadIdentityCredentials as WorkloadIdentityCredentials,
102+
default_credentials as default_credentials,
103+
exchange_federation_assertion as exchange_federation_assertion,
104+
)
105+
from .lib._parse._transform import transform_schema as transform_schema
106+
from ._utils._resources_proxy import resources as resources
49107

50108
__all__ = [
51109
"types",
@@ -100,13 +158,81 @@
100158
if not _t.TYPE_CHECKING:
101159
from ._utils._resources_proxy import resources as resources
102160

103-
from .lib.aws import AnthropicAWS as AnthropicAWS, AsyncAnthropicAWS as AsyncAnthropicAWS
104-
from .lib.tools import beta_tool, beta_async_tool
105-
from .lib.vertex import *
106-
from .lib.bedrock import *
107-
from .lib.foundry import AnthropicFoundry as AnthropicFoundry, AsyncAnthropicFoundry as AsyncAnthropicFoundry
108-
from .lib.streaming import *
109-
from .lib.credentials import *
161+
_LAZY_ATTRS: dict[str, tuple[str, str | None]] = {
162+
"types": (".types", None),
163+
"AnthropicAWS": (".lib.aws", "AnthropicAWS"),
164+
"AsyncAnthropicAWS": (".lib.aws", "AsyncAnthropicAWS"),
165+
"beta_tool": (".lib.tools", "beta_tool"),
166+
"beta_async_tool": (".lib.tools", "beta_async_tool"),
167+
"AnthropicVertex": (".lib.vertex", "AnthropicVertex"),
168+
"AsyncAnthropicVertex": (".lib.vertex", "AsyncAnthropicVertex"),
169+
"AnthropicBedrock": (".lib.bedrock", "AnthropicBedrock"),
170+
"AsyncAnthropicBedrock": (".lib.bedrock", "AsyncAnthropicBedrock"),
171+
"AnthropicBedrockMantle": (".lib.bedrock", "AnthropicBedrockMantle"),
172+
"AsyncAnthropicBedrockMantle": (".lib.bedrock", "AsyncAnthropicBedrockMantle"),
173+
"AnthropicFoundry": (".lib.foundry", "AnthropicFoundry"),
174+
"AsyncAnthropicFoundry": (".lib.foundry", "AsyncAnthropicFoundry"),
175+
"TextEvent": (".lib.streaming", "TextEvent"),
176+
"InputJsonEvent": (".lib.streaming", "InputJsonEvent"),
177+
"MessageStream": (".lib.streaming", "MessageStream"),
178+
"BetaTextEvent": (".lib.streaming", "BetaTextEvent"),
179+
"AsyncMessageStream": (".lib.streaming", "AsyncMessageStream"),
180+
"MessageStopEvent": (".lib.streaming", "MessageStopEvent"),
181+
"MessageStreamEvent": (".lib.streaming", "MessageStreamEvent"),
182+
"BetaInputJsonEvent": (".lib.streaming", "BetaInputJsonEvent"),
183+
"MessageStreamManager": (".lib.streaming", "MessageStreamManager"),
184+
"ContentBlockStopEvent": (".lib.streaming", "ContentBlockStopEvent"),
185+
"ParsedBetaTextEvent": (".lib.streaming", "ParsedBetaTextEvent"),
186+
"BetaMessageStream": (".lib.streaming", "BetaMessageStream"),
187+
"BetaAsyncMessageStream": (".lib.streaming", "BetaAsyncMessageStream"),
188+
"AsyncMessageStreamManager": (".lib.streaming", "AsyncMessageStreamManager"),
189+
"BetaMessageStreamEvent": (".lib.streaming", "BetaMessageStreamEvent"),
190+
"ParsedMessageStopEvent": (".lib.streaming", "ParsedMessageStopEvent"),
191+
"BetaMessageStreamManager": (".lib.streaming", "BetaMessageStreamManager"),
192+
"ParsedMessageStreamEvent": (".lib.streaming", "ParsedMessageStreamEvent"),
193+
"BetaContentBlockStopEvent": (".lib.streaming", "BetaContentBlockStopEvent"),
194+
"ParsedBetaMessageStopEvent": (".lib.streaming", "ParsedBetaMessageStopEvent"),
195+
"ParsedContentBlockStopEvent": (".lib.streaming", "ParsedContentBlockStopEvent"),
196+
"BetaAsyncMessageStreamManager": (".lib.streaming", "BetaAsyncMessageStreamManager"),
197+
"ParsedBetaMessageStreamEvent": (".lib.streaming", "ParsedBetaMessageStreamEvent"),
198+
"ParsedBetaContentBlockStopEvent": (".lib.streaming", "ParsedBetaContentBlockStopEvent"),
199+
"EnvToken": (".lib.credentials", "EnvToken"),
200+
"TokenCache": (".lib.credentials", "TokenCache"),
201+
"AccessToken": (".lib.credentials", "AccessToken"),
202+
"StaticToken": (".lib.credentials", "StaticToken"),
203+
"AccessTokenAuth": (".lib.credentials", "AccessTokenAuth"),
204+
"InMemoryConfig": (".lib.credentials", "InMemoryConfig"),
205+
"CredentialsFile": (".lib.credentials", "CredentialsFile"),
206+
"CredentialResult": (".lib.credentials", "CredentialResult"),
207+
"IdentityTokenFile": (".lib.credentials", "IdentityTokenFile"),
208+
"AccessTokenProvider": (".lib.credentials", "AccessTokenProvider"),
209+
"default_credentials": (".lib.credentials", "default_credentials"),
210+
"IdentityTokenProvider": (".lib.credentials", "IdentityTokenProvider"),
211+
"WorkloadIdentityError": (".lib.credentials", "WorkloadIdentityError"),
212+
"WorkloadIdentityCredentials": (".lib.credentials", "WorkloadIdentityCredentials"),
213+
"exchange_federation_assertion": (".lib.credentials", "exchange_federation_assertion"),
214+
"transform_schema": (".lib._parse._transform", "transform_schema"),
215+
}
216+
217+
218+
def __getattr__(name: str) -> _t.Any:
219+
if name not in _LAZY_ATTRS:
220+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
221+
222+
import importlib
223+
224+
module_name, attr_name = _LAZY_ATTRS[name]
225+
module = importlib.import_module(module_name, __name__)
226+
attr = module if attr_name is None else getattr(module, attr_name)
227+
globals()[name] = attr
228+
229+
try:
230+
attr.__module__ = "anthropic"
231+
except (TypeError, AttributeError):
232+
pass
233+
234+
return attr
235+
110236

111237
_setup_logging()
112238

@@ -119,6 +245,8 @@
119245
if not __name.startswith("__"):
120246
try:
121247
__locals[__name].__module__ = "anthropic"
248+
except KeyError:
249+
pass
122250
except (TypeError, AttributeError):
123251
# Some of our exported symbols are builtins which we can't set attributes for.
124252
pass

src/anthropic/_exceptions.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22

33
from __future__ import annotations
44

5-
from typing import Union, cast
5+
from typing import TYPE_CHECKING, Union, cast
66
from typing_extensions import Literal
77

88
import httpx
99

1010
from ._utils import is_dict
11-
from .types.shared.error_type import ErrorType
11+
12+
if TYPE_CHECKING:
13+
from .types.shared.error_type import ErrorType
14+
else:
15+
ErrorType = str
1216

1317
__all__ = [
1418
"BadRequestError",

tests/test_imports.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
from __future__ import annotations
2+
3+
import os
4+
import sys
5+
import json
6+
import subprocess
7+
from typing import Any
8+
from pathlib import Path
9+
10+
ROOT = Path(__file__).resolve().parents[1]
11+
12+
13+
def run_import_check(code: str) -> dict[str, Any]:
14+
env = os.environ.copy()
15+
env["PYTHONPATH"] = str(ROOT / "src")
16+
result = subprocess.run([sys.executable, "-c", code], check=True, capture_output=True, text=True, env=env)
17+
return json.loads(result.stdout)
18+
19+
20+
def test_import_anthropic_does_not_load_heavy_reexports() -> None:
21+
result = run_import_check(
22+
"""
23+
import json
24+
import sys
25+
26+
import anthropic
27+
28+
modules = [
29+
"anthropic.types",
30+
"anthropic.resources",
31+
"anthropic.lib.tools",
32+
"anthropic.lib.vertex",
33+
"anthropic.lib.bedrock",
34+
"anthropic.lib.streaming",
35+
"anthropic.lib._parse._transform",
36+
]
37+
38+
print(json.dumps({module: module in sys.modules for module in modules}))
39+
"""
40+
)
41+
42+
assert result == {
43+
"anthropic.types": False,
44+
"anthropic.resources": False,
45+
"anthropic.lib.tools": False,
46+
"anthropic.lib.vertex": False,
47+
"anthropic.lib.bedrock": False,
48+
"anthropic.lib.streaming": False,
49+
"anthropic.lib._parse._transform": False,
50+
}
51+
52+
53+
def test_lazy_root_reexports_still_resolve() -> None:
54+
result = run_import_check(
55+
"""
56+
import json
57+
58+
from anthropic import AnthropicBedrock, AnthropicVertex, beta_tool, transform_schema, types
59+
60+
print(json.dumps({
61+
"types": types.__name__,
62+
"AnthropicVertex": AnthropicVertex.__name__,
63+
"AnthropicBedrock": AnthropicBedrock.__name__,
64+
"beta_tool": beta_tool.__name__,
65+
"transform_schema": transform_schema.__name__,
66+
}))
67+
"""
68+
)
69+
70+
assert result == {
71+
"types": "anthropic.types",
72+
"AnthropicVertex": "AnthropicVertex",
73+
"AnthropicBedrock": "AnthropicBedrock",
74+
"beta_tool": "beta_tool",
75+
"transform_schema": "transform_schema",
76+
}

0 commit comments

Comments
 (0)