athena-intelligence 0.1.127__py3-none-any.whl → 0.1.184__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.
- athena/__init__.py +24 -3
- athena/agents/__init__.py +2 -0
- athena/agents/client.py +51 -95
- athena/agents/drive/__init__.py +2 -0
- athena/agents/drive/client.py +31 -80
- athena/agents/drive/raw_client.py +155 -0
- athena/agents/general/__init__.py +2 -0
- athena/agents/general/client.py +91 -238
- athena/agents/general/raw_client.py +369 -0
- athena/agents/raw_client.py +176 -0
- athena/agents/research/__init__.py +2 -0
- athena/agents/research/client.py +31 -80
- athena/agents/research/raw_client.py +155 -0
- athena/agents/sql/__init__.py +2 -0
- athena/agents/sql/client.py +31 -80
- athena/agents/sql/raw_client.py +155 -0
- athena/assets/__init__.py +4 -0
- athena/assets/client.py +144 -0
- athena/assets/raw_client.py +164 -0
- athena/base_client.py +25 -11
- athena/client.py +1 -1
- athena/core/__init__.py +5 -0
- athena/core/api_error.py +13 -5
- athena/core/client_wrapper.py +33 -8
- athena/core/force_multipart.py +16 -0
- athena/core/http_client.py +70 -26
- athena/core/http_response.py +55 -0
- athena/core/jsonable_encoder.py +0 -1
- athena/core/pydantic_utilities.py +70 -111
- athena/core/serialization.py +7 -3
- athena/errors/__init__.py +2 -0
- athena/errors/bad_request_error.py +4 -2
- athena/errors/content_too_large_error.py +4 -2
- athena/errors/internal_server_error.py +4 -3
- athena/errors/not_found_error.py +4 -2
- athena/errors/unauthorized_error.py +4 -3
- athena/errors/unprocessable_entity_error.py +4 -3
- athena/errors/unsupported_media_type_error.py +4 -2
- athena/query/__init__.py +2 -0
- athena/query/client.py +39 -219
- athena/query/raw_client.py +344 -0
- athena/query/types/__init__.py +2 -0
- athena/tools/__init__.py +2 -0
- athena/tools/calendar/__init__.py +2 -0
- athena/tools/calendar/client.py +35 -79
- athena/tools/calendar/raw_client.py +172 -0
- athena/tools/client.py +114 -876
- athena/tools/email/__init__.py +2 -0
- athena/tools/email/client.py +39 -115
- athena/tools/email/raw_client.py +248 -0
- athena/tools/raw_client.py +1328 -0
- athena/tools/structured_data_extractor/__init__.py +2 -0
- athena/tools/structured_data_extractor/client.py +42 -96
- athena/tools/structured_data_extractor/raw_client.py +240 -0
- athena/tools/tasks/__init__.py +2 -0
- athena/tools/tasks/client.py +31 -43
- athena/tools/tasks/raw_client.py +96 -0
- athena/tools/types/__init__.py +2 -0
- athena/types/__init__.py +24 -2
- athena/types/asset_content_request_out.py +3 -3
- athena/types/asset_node.py +3 -3
- athena/types/asset_not_found_error.py +2 -2
- athena/types/asset_screenshot_response_out.py +4 -4
- athena/types/chunk.py +3 -3
- athena/types/chunk_content_item.py +3 -2
- athena/types/chunk_result.py +3 -3
- athena/types/content.py +7 -0
- athena/types/custom_agent_response.py +2 -2
- athena/types/data_frame_request_out.py +3 -3
- athena/types/data_frame_unknown_format_error.py +2 -2
- athena/types/document_chunk.py +2 -2
- athena/types/drive_agent_response.py +2 -2
- athena/types/file_chunk_request_out.py +3 -3
- athena/types/file_too_large_error.py +2 -2
- athena/types/folder_response.py +10 -4
- athena/types/general_agent_config.py +3 -3
- athena/types/general_agent_config_enabled_tools_item.py +1 -2
- athena/types/general_agent_request.py +15 -4
- athena/types/general_agent_response.py +4 -3
- athena/types/general_agent_response_message.py +100 -0
- athena/types/general_agent_response_message_kwargs.py +74 -0
- athena/types/{tool.py → id.py} +1 -1
- athena/types/image_url_content.py +2 -2
- athena/types/input_message.py +29 -0
- athena/types/input_message_content_item.py +39 -0
- athena/types/paginated_assets_out.py +52 -0
- athena/types/parent_folder_error.py +2 -2
- athena/types/prompt_message.py +3 -3
- athena/types/public_asset_out.py +97 -0
- athena/types/research_agent_response.py +2 -2
- athena/types/save_asset_request_out.py +2 -2
- athena/types/sql_agent_response.py +2 -2
- athena/types/structured_data_extractor_response.py +3 -3
- athena/types/text_content.py +2 -2
- athena/types/type.py +1 -1
- {athena_intelligence-0.1.127.dist-info → athena_intelligence-0.1.184.dist-info}/METADATA +3 -7
- athena_intelligence-0.1.184.dist-info/RECORD +112 -0
- {athena_intelligence-0.1.127.dist-info → athena_intelligence-0.1.184.dist-info}/WHEEL +1 -1
- athena_intelligence-0.1.127.dist-info/RECORD +0 -89
@@ -0,0 +1,164 @@
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
2
|
+
|
3
|
+
import typing
|
4
|
+
from json.decoder import JSONDecodeError
|
5
|
+
|
6
|
+
from ..core.api_error import ApiError
|
7
|
+
from ..core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
|
8
|
+
from ..core.http_response import AsyncHttpResponse, HttpResponse
|
9
|
+
from ..core.pydantic_utilities import parse_obj_as
|
10
|
+
from ..core.request_options import RequestOptions
|
11
|
+
from ..errors.unprocessable_entity_error import UnprocessableEntityError
|
12
|
+
from ..types.paginated_assets_out import PaginatedAssetsOut
|
13
|
+
|
14
|
+
|
15
|
+
class RawAssetsClient:
|
16
|
+
def __init__(self, *, client_wrapper: SyncClientWrapper):
|
17
|
+
self._client_wrapper = client_wrapper
|
18
|
+
|
19
|
+
def list(
|
20
|
+
self,
|
21
|
+
*,
|
22
|
+
limit: typing.Optional[int] = None,
|
23
|
+
offset: typing.Optional[int] = None,
|
24
|
+
filters: typing.Optional[str] = None,
|
25
|
+
sort: typing.Optional[str] = None,
|
26
|
+
request_options: typing.Optional[RequestOptions] = None,
|
27
|
+
) -> HttpResponse[PaginatedAssetsOut]:
|
28
|
+
"""
|
29
|
+
Retrieve a paginated list of assets with optional filtering and sorting. Assets include documents, presentations, spreadsheets, images, videos, and other file types managed by Athena Intelligence.
|
30
|
+
|
31
|
+
Parameters
|
32
|
+
----------
|
33
|
+
limit : typing.Optional[int]
|
34
|
+
Maximum number of assets to return per page (1-500)
|
35
|
+
|
36
|
+
offset : typing.Optional[int]
|
37
|
+
Number of assets to skip for pagination
|
38
|
+
|
39
|
+
filters : typing.Optional[str]
|
40
|
+
JSON string of filter criteria. Supports: created_by_id, created_by_email, tags, created_after/before, updated_after/before, title_substring, is_archived, is_hidden, athena_metadata, media_type, athena_converted_type, athena_original_type, summary_ready, summary_status
|
41
|
+
|
42
|
+
sort : typing.Optional[str]
|
43
|
+
JSON string of sort criteria: [{"field": "updated_at", "direction": "desc"}]. Supported fields: created_by_id, created_by_email, created_at, updated_at, is_archived, is_hidden, summary_ready, summary_status
|
44
|
+
|
45
|
+
request_options : typing.Optional[RequestOptions]
|
46
|
+
Request-specific configuration.
|
47
|
+
|
48
|
+
Returns
|
49
|
+
-------
|
50
|
+
HttpResponse[PaginatedAssetsOut]
|
51
|
+
Successfully retrieved paginated list of assets
|
52
|
+
"""
|
53
|
+
_response = self._client_wrapper.httpx_client.request(
|
54
|
+
"api/v0/assets",
|
55
|
+
method="GET",
|
56
|
+
params={
|
57
|
+
"limit": limit,
|
58
|
+
"offset": offset,
|
59
|
+
"filters": filters,
|
60
|
+
"sort": sort,
|
61
|
+
},
|
62
|
+
request_options=request_options,
|
63
|
+
)
|
64
|
+
try:
|
65
|
+
if 200 <= _response.status_code < 300:
|
66
|
+
_data = typing.cast(
|
67
|
+
PaginatedAssetsOut,
|
68
|
+
parse_obj_as(
|
69
|
+
type_=PaginatedAssetsOut, # type: ignore
|
70
|
+
object_=_response.json(),
|
71
|
+
),
|
72
|
+
)
|
73
|
+
return HttpResponse(response=_response, data=_data)
|
74
|
+
if _response.status_code == 422:
|
75
|
+
raise UnprocessableEntityError(
|
76
|
+
headers=dict(_response.headers),
|
77
|
+
body=typing.cast(
|
78
|
+
typing.Optional[typing.Any],
|
79
|
+
parse_obj_as(
|
80
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
81
|
+
object_=_response.json(),
|
82
|
+
),
|
83
|
+
),
|
84
|
+
)
|
85
|
+
_response_json = _response.json()
|
86
|
+
except JSONDecodeError:
|
87
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
88
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
89
|
+
|
90
|
+
|
91
|
+
class AsyncRawAssetsClient:
|
92
|
+
def __init__(self, *, client_wrapper: AsyncClientWrapper):
|
93
|
+
self._client_wrapper = client_wrapper
|
94
|
+
|
95
|
+
async def list(
|
96
|
+
self,
|
97
|
+
*,
|
98
|
+
limit: typing.Optional[int] = None,
|
99
|
+
offset: typing.Optional[int] = None,
|
100
|
+
filters: typing.Optional[str] = None,
|
101
|
+
sort: typing.Optional[str] = None,
|
102
|
+
request_options: typing.Optional[RequestOptions] = None,
|
103
|
+
) -> AsyncHttpResponse[PaginatedAssetsOut]:
|
104
|
+
"""
|
105
|
+
Retrieve a paginated list of assets with optional filtering and sorting. Assets include documents, presentations, spreadsheets, images, videos, and other file types managed by Athena Intelligence.
|
106
|
+
|
107
|
+
Parameters
|
108
|
+
----------
|
109
|
+
limit : typing.Optional[int]
|
110
|
+
Maximum number of assets to return per page (1-500)
|
111
|
+
|
112
|
+
offset : typing.Optional[int]
|
113
|
+
Number of assets to skip for pagination
|
114
|
+
|
115
|
+
filters : typing.Optional[str]
|
116
|
+
JSON string of filter criteria. Supports: created_by_id, created_by_email, tags, created_after/before, updated_after/before, title_substring, is_archived, is_hidden, athena_metadata, media_type, athena_converted_type, athena_original_type, summary_ready, summary_status
|
117
|
+
|
118
|
+
sort : typing.Optional[str]
|
119
|
+
JSON string of sort criteria: [{"field": "updated_at", "direction": "desc"}]. Supported fields: created_by_id, created_by_email, created_at, updated_at, is_archived, is_hidden, summary_ready, summary_status
|
120
|
+
|
121
|
+
request_options : typing.Optional[RequestOptions]
|
122
|
+
Request-specific configuration.
|
123
|
+
|
124
|
+
Returns
|
125
|
+
-------
|
126
|
+
AsyncHttpResponse[PaginatedAssetsOut]
|
127
|
+
Successfully retrieved paginated list of assets
|
128
|
+
"""
|
129
|
+
_response = await self._client_wrapper.httpx_client.request(
|
130
|
+
"api/v0/assets",
|
131
|
+
method="GET",
|
132
|
+
params={
|
133
|
+
"limit": limit,
|
134
|
+
"offset": offset,
|
135
|
+
"filters": filters,
|
136
|
+
"sort": sort,
|
137
|
+
},
|
138
|
+
request_options=request_options,
|
139
|
+
)
|
140
|
+
try:
|
141
|
+
if 200 <= _response.status_code < 300:
|
142
|
+
_data = typing.cast(
|
143
|
+
PaginatedAssetsOut,
|
144
|
+
parse_obj_as(
|
145
|
+
type_=PaginatedAssetsOut, # type: ignore
|
146
|
+
object_=_response.json(),
|
147
|
+
),
|
148
|
+
)
|
149
|
+
return AsyncHttpResponse(response=_response, data=_data)
|
150
|
+
if _response.status_code == 422:
|
151
|
+
raise UnprocessableEntityError(
|
152
|
+
headers=dict(_response.headers),
|
153
|
+
body=typing.cast(
|
154
|
+
typing.Optional[typing.Any],
|
155
|
+
parse_obj_as(
|
156
|
+
type_=typing.Optional[typing.Any], # type: ignore
|
157
|
+
object_=_response.json(),
|
158
|
+
),
|
159
|
+
),
|
160
|
+
)
|
161
|
+
_response_json = _response.json()
|
162
|
+
except JSONDecodeError:
|
163
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
|
164
|
+
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response_json)
|
athena/base_client.py
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
# This file was auto-generated by Fern from our API Definition.
|
2
2
|
|
3
3
|
import typing
|
4
|
-
|
4
|
+
|
5
5
|
import httpx
|
6
|
-
from .
|
7
|
-
from .
|
8
|
-
from .
|
9
|
-
from .
|
10
|
-
from .
|
11
|
-
from .
|
12
|
-
from .query.client import AsyncQueryClient
|
13
|
-
from .tools.client import AsyncToolsClient
|
6
|
+
from .agents.client import AgentsClient, AsyncAgentsClient
|
7
|
+
from .assets.client import AssetsClient, AsyncAssetsClient
|
8
|
+
from .core.client_wrapper import AsyncClientWrapper, SyncClientWrapper
|
9
|
+
from .environment import AthenaEnvironment
|
10
|
+
from .query.client import AsyncQueryClient, QueryClient
|
11
|
+
from .tools.client import AsyncToolsClient, ToolsClient
|
14
12
|
|
15
13
|
|
16
14
|
class BaseAthena:
|
@@ -32,6 +30,9 @@ class BaseAthena:
|
|
32
30
|
|
33
31
|
|
34
32
|
api_key : str
|
33
|
+
headers : typing.Optional[typing.Dict[str, str]]
|
34
|
+
Additional headers to send with every request.
|
35
|
+
|
35
36
|
timeout : typing.Optional[float]
|
36
37
|
The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
|
37
38
|
|
@@ -56,14 +57,18 @@ class BaseAthena:
|
|
56
57
|
base_url: typing.Optional[str] = None,
|
57
58
|
environment: AthenaEnvironment = AthenaEnvironment.PRODUCTION,
|
58
59
|
api_key: str,
|
60
|
+
headers: typing.Optional[typing.Dict[str, str]] = None,
|
59
61
|
timeout: typing.Optional[float] = None,
|
60
62
|
follow_redirects: typing.Optional[bool] = True,
|
61
63
|
httpx_client: typing.Optional[httpx.Client] = None,
|
62
64
|
):
|
63
|
-
_defaulted_timeout =
|
65
|
+
_defaulted_timeout = (
|
66
|
+
timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
|
67
|
+
)
|
64
68
|
self._client_wrapper = SyncClientWrapper(
|
65
69
|
base_url=_get_base_url(base_url=base_url, environment=environment),
|
66
70
|
api_key=api_key,
|
71
|
+
headers=headers,
|
67
72
|
httpx_client=httpx_client
|
68
73
|
if httpx_client is not None
|
69
74
|
else httpx.Client(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
|
@@ -72,6 +77,7 @@ class BaseAthena:
|
|
72
77
|
timeout=_defaulted_timeout,
|
73
78
|
)
|
74
79
|
self.agents = AgentsClient(client_wrapper=self._client_wrapper)
|
80
|
+
self.assets = AssetsClient(client_wrapper=self._client_wrapper)
|
75
81
|
self.query = QueryClient(client_wrapper=self._client_wrapper)
|
76
82
|
self.tools = ToolsClient(client_wrapper=self._client_wrapper)
|
77
83
|
|
@@ -95,6 +101,9 @@ class AsyncBaseAthena:
|
|
95
101
|
|
96
102
|
|
97
103
|
api_key : str
|
104
|
+
headers : typing.Optional[typing.Dict[str, str]]
|
105
|
+
Additional headers to send with every request.
|
106
|
+
|
98
107
|
timeout : typing.Optional[float]
|
99
108
|
The timeout to be used, in seconds, for requests. By default the timeout is 60 seconds, unless a custom httpx client is used, in which case this default is not enforced.
|
100
109
|
|
@@ -119,14 +128,18 @@ class AsyncBaseAthena:
|
|
119
128
|
base_url: typing.Optional[str] = None,
|
120
129
|
environment: AthenaEnvironment = AthenaEnvironment.PRODUCTION,
|
121
130
|
api_key: str,
|
131
|
+
headers: typing.Optional[typing.Dict[str, str]] = None,
|
122
132
|
timeout: typing.Optional[float] = None,
|
123
133
|
follow_redirects: typing.Optional[bool] = True,
|
124
134
|
httpx_client: typing.Optional[httpx.AsyncClient] = None,
|
125
135
|
):
|
126
|
-
_defaulted_timeout =
|
136
|
+
_defaulted_timeout = (
|
137
|
+
timeout if timeout is not None else 60 if httpx_client is None else httpx_client.timeout.read
|
138
|
+
)
|
127
139
|
self._client_wrapper = AsyncClientWrapper(
|
128
140
|
base_url=_get_base_url(base_url=base_url, environment=environment),
|
129
141
|
api_key=api_key,
|
142
|
+
headers=headers,
|
130
143
|
httpx_client=httpx_client
|
131
144
|
if httpx_client is not None
|
132
145
|
else httpx.AsyncClient(timeout=_defaulted_timeout, follow_redirects=follow_redirects)
|
@@ -135,6 +148,7 @@ class AsyncBaseAthena:
|
|
135
148
|
timeout=_defaulted_timeout,
|
136
149
|
)
|
137
150
|
self.agents = AsyncAgentsClient(client_wrapper=self._client_wrapper)
|
151
|
+
self.assets = AsyncAssetsClient(client_wrapper=self._client_wrapper)
|
138
152
|
self.query = AsyncQueryClient(client_wrapper=self._client_wrapper)
|
139
153
|
self.tools = AsyncToolsClient(client_wrapper=self._client_wrapper)
|
140
154
|
|
athena/client.py
CHANGED
@@ -169,7 +169,7 @@ class WrappedToolsClient(ToolsClient):
|
|
169
169
|
Gets the file togehter with media type returned by server
|
170
170
|
"""
|
171
171
|
# while we wait for https://github.com/fern-api/fern/issues/4316
|
172
|
-
result = self._client_wrapper.httpx_client.request(
|
172
|
+
result = self.with_raw_response._client_wrapper.httpx_client.request(
|
173
173
|
"api/v0/tools/file/raw-data", method="GET", params={"asset_id": asset_id}
|
174
174
|
)
|
175
175
|
if result.status_code != 200:
|
athena/core/__init__.py
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
# This file was auto-generated by Fern from our API Definition.
|
2
2
|
|
3
|
+
# isort: skip_file
|
4
|
+
|
3
5
|
from .api_error import ApiError
|
4
6
|
from .client_wrapper import AsyncClientWrapper, BaseClientWrapper, SyncClientWrapper
|
5
7
|
from .datetime_utils import serialize_datetime
|
6
8
|
from .file import File, convert_file_dict_to_httpx_tuples, with_content_type
|
7
9
|
from .http_client import AsyncHttpClient, HttpClient
|
10
|
+
from .http_response import AsyncHttpResponse, HttpResponse
|
8
11
|
from .jsonable_encoder import jsonable_encoder
|
9
12
|
from .pydantic_utilities import (
|
10
13
|
IS_PYDANTIC_V2,
|
@@ -24,10 +27,12 @@ __all__ = [
|
|
24
27
|
"ApiError",
|
25
28
|
"AsyncClientWrapper",
|
26
29
|
"AsyncHttpClient",
|
30
|
+
"AsyncHttpResponse",
|
27
31
|
"BaseClientWrapper",
|
28
32
|
"FieldMetadata",
|
29
33
|
"File",
|
30
34
|
"HttpClient",
|
35
|
+
"HttpResponse",
|
31
36
|
"IS_PYDANTIC_V2",
|
32
37
|
"RequestOptions",
|
33
38
|
"SyncClientWrapper",
|
athena/core/api_error.py
CHANGED
@@ -1,15 +1,23 @@
|
|
1
1
|
# This file was auto-generated by Fern from our API Definition.
|
2
2
|
|
3
|
-
import
|
3
|
+
from typing import Any, Dict, Optional
|
4
4
|
|
5
5
|
|
6
6
|
class ApiError(Exception):
|
7
|
-
|
8
|
-
|
7
|
+
headers: Optional[Dict[str, str]]
|
8
|
+
status_code: Optional[int]
|
9
|
+
body: Any
|
9
10
|
|
10
|
-
def __init__(
|
11
|
+
def __init__(
|
12
|
+
self,
|
13
|
+
*,
|
14
|
+
headers: Optional[Dict[str, str]] = None,
|
15
|
+
status_code: Optional[int] = None,
|
16
|
+
body: Any = None,
|
17
|
+
) -> None:
|
18
|
+
self.headers = headers
|
11
19
|
self.status_code = status_code
|
12
20
|
self.body = body
|
13
21
|
|
14
22
|
def __str__(self) -> str:
|
15
|
-
return f"status_code: {self.status_code}, body: {self.body}"
|
23
|
+
return f"headers: {self.headers}, status_code: {self.status_code}, body: {self.body}"
|
athena/core/client_wrapper.py
CHANGED
@@ -1,26 +1,39 @@
|
|
1
1
|
# This file was auto-generated by Fern from our API Definition.
|
2
2
|
|
3
3
|
import typing
|
4
|
+
|
4
5
|
import httpx
|
5
|
-
from .http_client import HttpClient
|
6
|
-
from .http_client import AsyncHttpClient
|
6
|
+
from .http_client import AsyncHttpClient, HttpClient
|
7
7
|
|
8
8
|
|
9
9
|
class BaseClientWrapper:
|
10
|
-
def __init__(
|
10
|
+
def __init__(
|
11
|
+
self,
|
12
|
+
*,
|
13
|
+
api_key: str,
|
14
|
+
headers: typing.Optional[typing.Dict[str, str]] = None,
|
15
|
+
base_url: str,
|
16
|
+
timeout: typing.Optional[float] = None,
|
17
|
+
):
|
11
18
|
self.api_key = api_key
|
19
|
+
self._headers = headers
|
12
20
|
self._base_url = base_url
|
13
21
|
self._timeout = timeout
|
14
22
|
|
15
23
|
def get_headers(self) -> typing.Dict[str, str]:
|
16
24
|
headers: typing.Dict[str, str] = {
|
25
|
+
"User-Agent": "athena-intelligence/0.1.184",
|
17
26
|
"X-Fern-Language": "Python",
|
18
27
|
"X-Fern-SDK-Name": "athena-intelligence",
|
19
|
-
"X-Fern-SDK-Version": "0.1.
|
28
|
+
"X-Fern-SDK-Version": "0.1.184",
|
29
|
+
**(self.get_custom_headers() or {}),
|
20
30
|
}
|
21
31
|
headers["X-API-KEY"] = self.api_key
|
22
32
|
return headers
|
23
33
|
|
34
|
+
def get_custom_headers(self) -> typing.Optional[typing.Dict[str, str]]:
|
35
|
+
return self._headers
|
36
|
+
|
24
37
|
def get_base_url(self) -> str:
|
25
38
|
return self._base_url
|
26
39
|
|
@@ -30,9 +43,15 @@ class BaseClientWrapper:
|
|
30
43
|
|
31
44
|
class SyncClientWrapper(BaseClientWrapper):
|
32
45
|
def __init__(
|
33
|
-
self,
|
46
|
+
self,
|
47
|
+
*,
|
48
|
+
api_key: str,
|
49
|
+
headers: typing.Optional[typing.Dict[str, str]] = None,
|
50
|
+
base_url: str,
|
51
|
+
timeout: typing.Optional[float] = None,
|
52
|
+
httpx_client: httpx.Client,
|
34
53
|
):
|
35
|
-
super().__init__(api_key=api_key, base_url=base_url, timeout=timeout)
|
54
|
+
super().__init__(api_key=api_key, headers=headers, base_url=base_url, timeout=timeout)
|
36
55
|
self.httpx_client = HttpClient(
|
37
56
|
httpx_client=httpx_client,
|
38
57
|
base_headers=self.get_headers,
|
@@ -43,9 +62,15 @@ class SyncClientWrapper(BaseClientWrapper):
|
|
43
62
|
|
44
63
|
class AsyncClientWrapper(BaseClientWrapper):
|
45
64
|
def __init__(
|
46
|
-
self,
|
65
|
+
self,
|
66
|
+
*,
|
67
|
+
api_key: str,
|
68
|
+
headers: typing.Optional[typing.Dict[str, str]] = None,
|
69
|
+
base_url: str,
|
70
|
+
timeout: typing.Optional[float] = None,
|
71
|
+
httpx_client: httpx.AsyncClient,
|
47
72
|
):
|
48
|
-
super().__init__(api_key=api_key, base_url=base_url, timeout=timeout)
|
73
|
+
super().__init__(api_key=api_key, headers=headers, base_url=base_url, timeout=timeout)
|
49
74
|
self.httpx_client = AsyncHttpClient(
|
50
75
|
httpx_client=httpx_client,
|
51
76
|
base_headers=self.get_headers,
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# This file was auto-generated by Fern from our API Definition.
|
2
|
+
|
3
|
+
|
4
|
+
class ForceMultipartDict(dict):
|
5
|
+
"""
|
6
|
+
A dictionary subclass that always evaluates to True in boolean contexts.
|
7
|
+
|
8
|
+
This is used to force multipart/form-data encoding in HTTP requests even when
|
9
|
+
the dictionary is empty, which would normally evaluate to False.
|
10
|
+
"""
|
11
|
+
|
12
|
+
def __bool__(self):
|
13
|
+
return True
|
14
|
+
|
15
|
+
|
16
|
+
FORCE_MULTIPART = ForceMultipartDict()
|
athena/core/http_client.py
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
import asyncio
|
4
4
|
import email.utils
|
5
|
-
import json
|
6
5
|
import re
|
7
6
|
import time
|
8
7
|
import typing
|
@@ -11,12 +10,13 @@ from contextlib import asynccontextmanager, contextmanager
|
|
11
10
|
from random import random
|
12
11
|
|
13
12
|
import httpx
|
14
|
-
|
15
13
|
from .file import File, convert_file_dict_to_httpx_tuples
|
14
|
+
from .force_multipart import FORCE_MULTIPART
|
16
15
|
from .jsonable_encoder import jsonable_encoder
|
17
16
|
from .query_encoder import encode_query
|
18
17
|
from .remove_none_from_dict import remove_none_from_dict
|
19
18
|
from .request_options import RequestOptions
|
19
|
+
from httpx._types import RequestFiles
|
20
20
|
|
21
21
|
INITIAL_RETRY_DELAY_SECONDS = 0.5
|
22
22
|
MAX_RETRY_DELAY_SECONDS = 10
|
@@ -180,11 +180,17 @@ class HttpClient:
|
|
180
180
|
json: typing.Optional[typing.Any] = None,
|
181
181
|
data: typing.Optional[typing.Any] = None,
|
182
182
|
content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
|
183
|
-
files: typing.Optional[
|
183
|
+
files: typing.Optional[
|
184
|
+
typing.Union[
|
185
|
+
typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
|
186
|
+
typing.List[typing.Tuple[str, File]],
|
187
|
+
]
|
188
|
+
] = None,
|
184
189
|
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
185
190
|
request_options: typing.Optional[RequestOptions] = None,
|
186
191
|
retries: int = 2,
|
187
192
|
omit: typing.Optional[typing.Any] = None,
|
193
|
+
force_multipart: typing.Optional[bool] = None,
|
188
194
|
) -> httpx.Response:
|
189
195
|
base_url = self.get_base_url(base_url)
|
190
196
|
timeout = (
|
@@ -195,6 +201,15 @@ class HttpClient:
|
|
195
201
|
|
196
202
|
json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
|
197
203
|
|
204
|
+
request_files: typing.Optional[RequestFiles] = (
|
205
|
+
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
206
|
+
if (files is not None and files is not omit and isinstance(files, dict))
|
207
|
+
else None
|
208
|
+
)
|
209
|
+
|
210
|
+
if (request_files is None or len(request_files) == 0) and force_multipart:
|
211
|
+
request_files = FORCE_MULTIPART
|
212
|
+
|
198
213
|
response = self.httpx_client.request(
|
199
214
|
method=method,
|
200
215
|
url=urllib.parse.urljoin(f"{base_url}/", path),
|
@@ -227,11 +242,7 @@ class HttpClient:
|
|
227
242
|
json=json_body,
|
228
243
|
data=data_body,
|
229
244
|
content=content,
|
230
|
-
files=
|
231
|
-
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
232
|
-
if (files is not None and files is not omit)
|
233
|
-
else None
|
234
|
-
),
|
245
|
+
files=request_files,
|
235
246
|
timeout=timeout,
|
236
247
|
)
|
237
248
|
|
@@ -266,11 +277,17 @@ class HttpClient:
|
|
266
277
|
json: typing.Optional[typing.Any] = None,
|
267
278
|
data: typing.Optional[typing.Any] = None,
|
268
279
|
content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
|
269
|
-
files: typing.Optional[
|
280
|
+
files: typing.Optional[
|
281
|
+
typing.Union[
|
282
|
+
typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
|
283
|
+
typing.List[typing.Tuple[str, File]],
|
284
|
+
]
|
285
|
+
] = None,
|
270
286
|
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
271
287
|
request_options: typing.Optional[RequestOptions] = None,
|
272
288
|
retries: int = 2,
|
273
289
|
omit: typing.Optional[typing.Any] = None,
|
290
|
+
force_multipart: typing.Optional[bool] = None,
|
274
291
|
) -> typing.Iterator[httpx.Response]:
|
275
292
|
base_url = self.get_base_url(base_url)
|
276
293
|
timeout = (
|
@@ -279,6 +296,15 @@ class HttpClient:
|
|
279
296
|
else self.base_timeout()
|
280
297
|
)
|
281
298
|
|
299
|
+
request_files: typing.Optional[RequestFiles] = (
|
300
|
+
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
301
|
+
if (files is not None and files is not omit and isinstance(files, dict))
|
302
|
+
else None
|
303
|
+
)
|
304
|
+
|
305
|
+
if (request_files is None or len(request_files) == 0) and force_multipart:
|
306
|
+
request_files = FORCE_MULTIPART
|
307
|
+
|
282
308
|
json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
|
283
309
|
|
284
310
|
with self.httpx_client.stream(
|
@@ -313,11 +339,7 @@ class HttpClient:
|
|
313
339
|
json=json_body,
|
314
340
|
data=data_body,
|
315
341
|
content=content,
|
316
|
-
files=
|
317
|
-
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
318
|
-
if (files is not None and files is not omit)
|
319
|
-
else None
|
320
|
-
),
|
342
|
+
files=request_files,
|
321
343
|
timeout=timeout,
|
322
344
|
) as stream:
|
323
345
|
yield stream
|
@@ -356,11 +378,17 @@ class AsyncHttpClient:
|
|
356
378
|
json: typing.Optional[typing.Any] = None,
|
357
379
|
data: typing.Optional[typing.Any] = None,
|
358
380
|
content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
|
359
|
-
files: typing.Optional[
|
381
|
+
files: typing.Optional[
|
382
|
+
typing.Union[
|
383
|
+
typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
|
384
|
+
typing.List[typing.Tuple[str, File]],
|
385
|
+
]
|
386
|
+
] = None,
|
360
387
|
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
361
388
|
request_options: typing.Optional[RequestOptions] = None,
|
362
389
|
retries: int = 2,
|
363
390
|
omit: typing.Optional[typing.Any] = None,
|
391
|
+
force_multipart: typing.Optional[bool] = None,
|
364
392
|
) -> httpx.Response:
|
365
393
|
base_url = self.get_base_url(base_url)
|
366
394
|
timeout = (
|
@@ -369,6 +397,15 @@ class AsyncHttpClient:
|
|
369
397
|
else self.base_timeout()
|
370
398
|
)
|
371
399
|
|
400
|
+
request_files: typing.Optional[RequestFiles] = (
|
401
|
+
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
402
|
+
if (files is not None and files is not omit and isinstance(files, dict))
|
403
|
+
else None
|
404
|
+
)
|
405
|
+
|
406
|
+
if (request_files is None or len(request_files) == 0) and force_multipart:
|
407
|
+
request_files = FORCE_MULTIPART
|
408
|
+
|
372
409
|
json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
|
373
410
|
|
374
411
|
# Add the input to each of these and do None-safety checks
|
@@ -404,11 +441,7 @@ class AsyncHttpClient:
|
|
404
441
|
json=json_body,
|
405
442
|
data=data_body,
|
406
443
|
content=content,
|
407
|
-
files=
|
408
|
-
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
409
|
-
if files is not None
|
410
|
-
else None
|
411
|
-
),
|
444
|
+
files=request_files,
|
412
445
|
timeout=timeout,
|
413
446
|
)
|
414
447
|
|
@@ -442,11 +475,17 @@ class AsyncHttpClient:
|
|
442
475
|
json: typing.Optional[typing.Any] = None,
|
443
476
|
data: typing.Optional[typing.Any] = None,
|
444
477
|
content: typing.Optional[typing.Union[bytes, typing.Iterator[bytes], typing.AsyncIterator[bytes]]] = None,
|
445
|
-
files: typing.Optional[
|
478
|
+
files: typing.Optional[
|
479
|
+
typing.Union[
|
480
|
+
typing.Dict[str, typing.Optional[typing.Union[File, typing.List[File]]]],
|
481
|
+
typing.List[typing.Tuple[str, File]],
|
482
|
+
]
|
483
|
+
] = None,
|
446
484
|
headers: typing.Optional[typing.Dict[str, typing.Any]] = None,
|
447
485
|
request_options: typing.Optional[RequestOptions] = None,
|
448
486
|
retries: int = 2,
|
449
487
|
omit: typing.Optional[typing.Any] = None,
|
488
|
+
force_multipart: typing.Optional[bool] = None,
|
450
489
|
) -> typing.AsyncIterator[httpx.Response]:
|
451
490
|
base_url = self.get_base_url(base_url)
|
452
491
|
timeout = (
|
@@ -455,6 +494,15 @@ class AsyncHttpClient:
|
|
455
494
|
else self.base_timeout()
|
456
495
|
)
|
457
496
|
|
497
|
+
request_files: typing.Optional[RequestFiles] = (
|
498
|
+
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
499
|
+
if (files is not None and files is not omit and isinstance(files, dict))
|
500
|
+
else None
|
501
|
+
)
|
502
|
+
|
503
|
+
if (request_files is None or len(request_files) == 0) and force_multipart:
|
504
|
+
request_files = FORCE_MULTIPART
|
505
|
+
|
458
506
|
json_body, data_body = get_request_body(json=json, data=data, request_options=request_options, omit=omit)
|
459
507
|
|
460
508
|
async with self.httpx_client.stream(
|
@@ -489,11 +537,7 @@ class AsyncHttpClient:
|
|
489
537
|
json=json_body,
|
490
538
|
data=data_body,
|
491
539
|
content=content,
|
492
|
-
files=
|
493
|
-
convert_file_dict_to_httpx_tuples(remove_omit_from_dict(remove_none_from_dict(files), omit))
|
494
|
-
if files is not None
|
495
|
-
else None
|
496
|
-
),
|
540
|
+
files=request_files,
|
497
541
|
timeout=timeout,
|
498
542
|
) as stream:
|
499
543
|
yield stream
|