athena-intelligence 0.1.106__tar.gz → 0.1.108__tar.gz
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_intelligence-0.1.106 → athena_intelligence-0.1.108}/PKG-INFO +1 -1
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/pyproject.toml +1 -1
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/client.py +123 -8
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/client_wrapper.py +1 -1
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/README.md +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/__init__.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/base_client.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/__init__.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/api_error.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/datetime_utils.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/file.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/http_client.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/jsonable_encoder.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/pydantic_utilities.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/query_encoder.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/remove_none_from_dict.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/request_options.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/environment.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/errors/__init__.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/errors/bad_request_error.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/errors/content_too_large_error.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/errors/internal_server_error.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/errors/not_found_error.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/errors/unauthorized_error.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/errors/unprocessable_entity_error.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/errors/unsupported_media_type_error.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/py.typed +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/query/__init__.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/query/client.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/query/types/__init__.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/query/types/query_execute_request_database_asset_ids.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/tools/__init__.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/tools/client.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/tools/types/__init__.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/tools/types/tools_data_frame_request_columns_item.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/types/__init__.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/types/asset_not_found_error.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/types/data_frame_request_out.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/types/data_frame_request_out_columns_item.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/types/data_frame_request_out_data_item_item.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/types/data_frame_request_out_index_item.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/types/data_frame_unknown_format_error.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/types/file_too_large_error.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/types/parent_folder_error.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/types/save_asset_request_out.py +0 -0
- {athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/version.py +0 -0
@@ -1,3 +1,4 @@
|
|
1
|
+
import dataclasses
|
1
2
|
import enum
|
2
3
|
import io
|
3
4
|
import os
|
@@ -41,6 +42,26 @@ class SpecialEnvironments(enum.Enum):
|
|
41
42
|
AUTODETECT_ENVIRONMENT = 'AUTO'
|
42
43
|
|
43
44
|
|
45
|
+
@dataclasses.dataclass
|
46
|
+
class AthenaAsset:
|
47
|
+
asset_id: str
|
48
|
+
data: bytes
|
49
|
+
media_type: str
|
50
|
+
|
51
|
+
def _repr_mimebundle_(self, include=None, exclude=None):
|
52
|
+
if self.media_type == "application/sql":
|
53
|
+
# it is safe to import IPython in `_repr_mimebundle_`
|
54
|
+
# as this is only intended to be invoked by IPython.
|
55
|
+
from IPython import display # type: ignore[import]
|
56
|
+
|
57
|
+
code = display.Code(
|
58
|
+
data=self.data,
|
59
|
+
language="sql",
|
60
|
+
)
|
61
|
+
return {"text/html": code._repr_html_()}
|
62
|
+
return {self.media_type: self.data}
|
63
|
+
|
64
|
+
|
44
65
|
class WrappedToolsClient(ToolsClient):
|
45
66
|
|
46
67
|
def get_file(self, asset_id: str) -> io.BytesIO:
|
@@ -113,6 +134,10 @@ class WrappedToolsClient(ToolsClient):
|
|
113
134
|
A pandas data frame, series, or core.File
|
114
135
|
|
115
136
|
parent_folder_id : typing.Optional[str]
|
137
|
+
Identifier of the folder into which the asset should be saved
|
138
|
+
|
139
|
+
name : typing.Optional[str]
|
140
|
+
The name for the asset
|
116
141
|
|
117
142
|
request_options : typing.Optional[RequestOptions]
|
118
143
|
Request-specific configuration.
|
@@ -133,6 +158,74 @@ class WrappedToolsClient(ToolsClient):
|
|
133
158
|
return super().save_asset(
|
134
159
|
file=asset_object, parent_folder_id=parent_folder_id, **kwargs
|
135
160
|
)
|
161
|
+
|
162
|
+
def get_asset(self, asset_id: str) -> Union["pd.DataFrame", AthenaAsset]:
|
163
|
+
"""
|
164
|
+
Parameters
|
165
|
+
----------
|
166
|
+
asset_id : str
|
167
|
+
|
168
|
+
Returns
|
169
|
+
-------
|
170
|
+
pd.DataFrame or AthenaAsset
|
171
|
+
|
172
|
+
Examples
|
173
|
+
--------
|
174
|
+
from athena.client import Athena
|
175
|
+
|
176
|
+
client = Athena(api_key="YOUR_API_KEY")
|
177
|
+
client.tools.get_asset(asset_id="asset_id")
|
178
|
+
"""
|
179
|
+
# while we wait for https://github.com/fern-api/fern/issues/4316
|
180
|
+
result = self._client_wrapper.httpx_client.request(
|
181
|
+
"api/v0/tools/file/raw-data", method="GET", params={"asset_id": asset_id}
|
182
|
+
)
|
183
|
+
if result.status_code != 200:
|
184
|
+
# let fern handle errors codes
|
185
|
+
self.raw_data(asset_id=asset_id)
|
186
|
+
raise Exception(
|
187
|
+
f"Could not get assset - unhandled error code: {result.status_code}"
|
188
|
+
)
|
189
|
+
|
190
|
+
file_bytes = io.BytesIO(result.read())
|
191
|
+
|
192
|
+
media_type = result.headers.get("content-type", "").split(";")[0]
|
193
|
+
|
194
|
+
if media_type == "":
|
195
|
+
# fallback to `libmagic` inference
|
196
|
+
media_type = _infer_media_type(bytes_io=file_bytes)
|
197
|
+
|
198
|
+
media_type_aliases = {"image/jpg": "image/jpeg"}
|
199
|
+
media_type = media_type_aliases.get(media_type, media_type)
|
200
|
+
|
201
|
+
supported_media_types = {
|
202
|
+
"application/json",
|
203
|
+
"application/pdf",
|
204
|
+
"image/jpeg",
|
205
|
+
"image/gif",
|
206
|
+
"image/png",
|
207
|
+
"image/svg+xml",
|
208
|
+
"image/webp",
|
209
|
+
"text/html",
|
210
|
+
"text/latex",
|
211
|
+
"text/markdown",
|
212
|
+
"text/plain",
|
213
|
+
"application/sql",
|
214
|
+
}
|
215
|
+
|
216
|
+
data = file_bytes.read()
|
217
|
+
|
218
|
+
if media_type in supported_media_types:
|
219
|
+
return AthenaAsset(
|
220
|
+
asset_id=asset_id,
|
221
|
+
data=data,
|
222
|
+
media_type=media_type,
|
223
|
+
)
|
224
|
+
|
225
|
+
if media_type in _pandas_media_types:
|
226
|
+
return _to_pandas_df(file_bytes, media_type=media_type)
|
227
|
+
|
228
|
+
raise NotImplementedError("Assets of `{media_type}` type are not yet supported")
|
136
229
|
|
137
230
|
|
138
231
|
class WrappedQueryClient(QueryClient):
|
@@ -376,24 +469,46 @@ def _check_pandas_installed():
|
|
376
469
|
assert pandas
|
377
470
|
|
378
471
|
|
379
|
-
def
|
380
|
-
import pandas as pd
|
472
|
+
def _infer_media_type(bytes_io: io.BytesIO) -> str:
|
381
473
|
import magic
|
382
474
|
|
383
475
|
# ideally this would be read from response header, but fern SDK for Python hides this info from us
|
384
476
|
media_type = magic.from_buffer(bytes_io.read(2048), mime=True)
|
385
477
|
bytes_io.seek(0)
|
478
|
+
return media_type
|
386
479
|
|
387
|
-
|
388
|
-
|
389
|
-
|
480
|
+
|
481
|
+
_pandas_media_types = {
|
482
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
483
|
+
"application/vnd.apache.parquet",
|
484
|
+
"application/octet-stream",
|
485
|
+
"application/vnd.ms-excel",
|
486
|
+
"text/csv",
|
487
|
+
"application/csv",
|
488
|
+
}
|
489
|
+
|
490
|
+
|
491
|
+
def _to_pandas_df(
|
492
|
+
bytes_io: io.BytesIO, *args, media_type: Union[str, None] = None, **kwargs
|
493
|
+
):
|
494
|
+
import pandas as pd
|
495
|
+
|
496
|
+
if media_type is None:
|
497
|
+
media_type = _infer_media_type(bytes_io)
|
498
|
+
|
499
|
+
if (
|
500
|
+
media_type
|
501
|
+
== "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
502
|
+
):
|
503
|
+
return pd.read_excel(bytes_io, *args, engine="openpyxl", **kwargs)
|
504
|
+
elif media_type in {"application/vnd.apache.parquet", "application/octet-stream"}:
|
390
505
|
return pd.read_parquet(bytes_io, *args, **kwargs)
|
391
|
-
elif media_type ==
|
506
|
+
elif media_type == "application/vnd.ms-excel":
|
392
507
|
return pd.read_excel(bytes_io, *args, **kwargs)
|
393
|
-
elif media_type in {
|
508
|
+
elif media_type in {"text/csv", "application/csv"}:
|
394
509
|
return pd.read_csv(bytes_io, *args, **kwargs)
|
395
510
|
else:
|
396
|
-
raise Exception("Unknown media type")
|
511
|
+
raise Exception(f"Unknown media type: {media_type}")
|
397
512
|
|
398
513
|
|
399
514
|
def _convert_asset_object(
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/client_wrapper.py
RENAMED
@@ -17,7 +17,7 @@ class BaseClientWrapper:
|
|
17
17
|
headers: typing.Dict[str, str] = {
|
18
18
|
"X-Fern-Language": "Python",
|
19
19
|
"X-Fern-SDK-Name": "athena-intelligence",
|
20
|
-
"X-Fern-SDK-Version": "0.1.
|
20
|
+
"X-Fern-SDK-Version": "0.1.108",
|
21
21
|
}
|
22
22
|
headers["X-API-KEY"] = self.api_key
|
23
23
|
return headers
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/datetime_utils.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/jsonable_encoder.py
RENAMED
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/pydantic_utilities.py
RENAMED
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/query_encoder.py
RENAMED
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/remove_none_from_dict.py
RENAMED
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/core/request_options.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/errors/bad_request_error.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/errors/not_found_error.py
RENAMED
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/errors/unauthorized_error.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/query/types/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/tools/types/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/types/file_too_large_error.py
RENAMED
File without changes
|
{athena_intelligence-0.1.106 → athena_intelligence-0.1.108}/src/athena/types/parent_folder_error.py
RENAMED
File without changes
|
File without changes
|
File without changes
|