atlasai-dstoolkit-client 0.0.1__py3-none-any.whl → 0.0.2__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.
- atlasai/toolkit/__init__.py +37 -0
- atlasai/toolkit/api.py +170 -0
- atlasai/toolkit/constants.py +10 -0
- atlasai/toolkit/fabric.py +67 -0
- atlasai/toolkit/feature.py +75 -0
- atlasai/toolkit/init.py +30 -0
- atlasai/toolkit/login.py +107 -0
- atlasai/toolkit/requests.py +52 -0
- atlasai/toolkit/utils.py +58 -0
- {atlasai_dstoolkit_client-0.0.1.dist-info → atlasai_dstoolkit_client-0.0.2.dist-info}/METADATA +1 -1
- atlasai_dstoolkit_client-0.0.2.dist-info/RECORD +14 -0
- atlasai_dstoolkit_client-0.0.2.dist-info/top_level.txt +1 -0
- atlasai_dstoolkit_client-0.0.1.dist-info/RECORD +0 -5
- atlasai_dstoolkit_client-0.0.1.dist-info/top_level.txt +0 -1
- {atlasai_dstoolkit_client-0.0.1.dist-info → atlasai_dstoolkit_client-0.0.2.dist-info}/LICENSE.txt +0 -0
- {atlasai_dstoolkit_client-0.0.1.dist-info → atlasai_dstoolkit_client-0.0.2.dist-info}/WHEEL +0 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
# Copyright 2025 AtlasAI PBC. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
# flake8: noqa
|
16
|
+
import os
|
17
|
+
import os.path as osp
|
18
|
+
|
19
|
+
from dotenv import load_dotenv
|
20
|
+
|
21
|
+
# do this first!
|
22
|
+
from .init import configure_logging
|
23
|
+
configure_logging()
|
24
|
+
del configure_logging
|
25
|
+
|
26
|
+
env_file = osp.join(osp.dirname(__file__), '.env')
|
27
|
+
if osp.exists(env_file):
|
28
|
+
load_dotenv(env_file)
|
29
|
+
|
30
|
+
del load_dotenv
|
31
|
+
del env_file
|
32
|
+
del osp
|
33
|
+
del os
|
34
|
+
|
35
|
+
|
36
|
+
from . import fabric, feature
|
37
|
+
from .login import login, logout
|
atlasai/toolkit/api.py
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
import os
|
2
|
+
from http import HTTPStatus
|
3
|
+
import json
|
4
|
+
import logging
|
5
|
+
|
6
|
+
from furl import furl
|
7
|
+
|
8
|
+
from .constants import DS_TOOLKIT_URL
|
9
|
+
from .requests import get_session
|
10
|
+
|
11
|
+
logger = logging.getLogger(__name__)
|
12
|
+
|
13
|
+
|
14
|
+
def _get_headers(access_token):
|
15
|
+
return {
|
16
|
+
'Authorization': f'Bearer {access_token}',
|
17
|
+
'Content-Type': 'application/json'
|
18
|
+
}
|
19
|
+
|
20
|
+
def _get_access_token():
|
21
|
+
env_name = os.getenv('ATLASAI_TOKEN_NAME', 'ATLASAI_TOKEN')
|
22
|
+
access_token = os.getenv(env_name)
|
23
|
+
if not access_token:
|
24
|
+
raise Exception('No access token found. Call the `login()` method first!')
|
25
|
+
return access_token
|
26
|
+
|
27
|
+
def _add_params(f, params=None):
|
28
|
+
if params is None:
|
29
|
+
params = {}
|
30
|
+
|
31
|
+
for k, v in params.items():
|
32
|
+
if v:
|
33
|
+
f.args[k] = v
|
34
|
+
return f
|
35
|
+
|
36
|
+
def _process_data(data):
|
37
|
+
if not data:
|
38
|
+
return '{}'
|
39
|
+
return json.dumps({k: v for k, v in data.items() if v is not None})
|
40
|
+
|
41
|
+
def _paginate(method, url, access_token=None, params=None):
|
42
|
+
if access_token is None:
|
43
|
+
access_token = _get_access_token()
|
44
|
+
results = []
|
45
|
+
if params is None:
|
46
|
+
params = {}
|
47
|
+
if params.get('limit') is None:
|
48
|
+
params['limit'] = 100
|
49
|
+
|
50
|
+
if params.get('offset') is None:
|
51
|
+
params['offset'] = 0
|
52
|
+
|
53
|
+
def get_results(_url, _params):
|
54
|
+
f = furl(_url)
|
55
|
+
f = _add_params(f, _params)
|
56
|
+
_response = session.request(method, f.url, headers=_get_headers(access_token))
|
57
|
+
_response.raise_for_status()
|
58
|
+
return _response
|
59
|
+
|
60
|
+
session = get_session()
|
61
|
+
while True:
|
62
|
+
response = get_results(url, params)
|
63
|
+
data = response.json()
|
64
|
+
if not data:
|
65
|
+
break
|
66
|
+
|
67
|
+
results.extend(data)
|
68
|
+
|
69
|
+
if len(data) < params['limit']:
|
70
|
+
break
|
71
|
+
params['offset'] = params['offset'] + params['limit']
|
72
|
+
return results
|
73
|
+
|
74
|
+
def _get(access_token=None, resource=None, _id=None, method='get', params=None):
|
75
|
+
if access_token is None:
|
76
|
+
access_token = _get_access_token()
|
77
|
+
session = get_session()
|
78
|
+
|
79
|
+
f = furl(DS_TOOLKIT_URL)
|
80
|
+
f.path = f'api/{resource}/{_id}' if _id else f'api/{resource}'
|
81
|
+
f = _add_params(f, params)
|
82
|
+
url = f.url
|
83
|
+
|
84
|
+
response = session.request(method, url, headers=_get_headers(access_token))
|
85
|
+
response.raise_for_status()
|
86
|
+
return response.status_code, response.json()
|
87
|
+
|
88
|
+
|
89
|
+
def _list(access_token=None, resource=None, method='get', params=None, is_paginated=True):
|
90
|
+
if access_token is None:
|
91
|
+
access_token = _get_access_token()
|
92
|
+
session = get_session()
|
93
|
+
|
94
|
+
f = furl(DS_TOOLKIT_URL)
|
95
|
+
f.path = f'api/{resource}'
|
96
|
+
url = f.url
|
97
|
+
|
98
|
+
# return all the records if limit not specified
|
99
|
+
if is_paginated and not params.get('limit') and not params.get('offset'):
|
100
|
+
return 200, _paginate(method, url, access_token, params)
|
101
|
+
|
102
|
+
f = _add_params(f, params)
|
103
|
+
url = f.url
|
104
|
+
response = session.request(method, url, headers=_get_headers(access_token))
|
105
|
+
response.raise_for_status()
|
106
|
+
return response.status_code, response.json()
|
107
|
+
|
108
|
+
def _post(access_token=None, resource=None, method='post', data=None, params=None, url=None):
|
109
|
+
if access_token is None:
|
110
|
+
access_token = _get_access_token()
|
111
|
+
session = get_session()
|
112
|
+
|
113
|
+
f = furl(url or DS_TOOLKIT_URL)
|
114
|
+
f.path = f'api/{resource}'
|
115
|
+
f = _add_params(f, params)
|
116
|
+
|
117
|
+
url = f.url
|
118
|
+
data = _process_data(data)
|
119
|
+
|
120
|
+
response = session.request(method, url, headers=_get_headers(access_token), data=data)
|
121
|
+
response.raise_for_status()
|
122
|
+
if response.status_code == HTTPStatus.NO_CONTENT:
|
123
|
+
return response.status_code, None
|
124
|
+
elif response.status_code == HTTPStatus.ACCEPTED:
|
125
|
+
return response.status_code, response.headers['Location']
|
126
|
+
else:
|
127
|
+
return response.status_code, response.json()
|
128
|
+
|
129
|
+
def _patch(access_token=None, resource=None, method='patch', data=None, params=None):
|
130
|
+
if access_token is None:
|
131
|
+
access_token = _get_access_token()
|
132
|
+
session = get_session()
|
133
|
+
|
134
|
+
f = furl(DS_TOOLKIT_URL)
|
135
|
+
f.path = f'api/{resource}'
|
136
|
+
f = _add_params(f, params)
|
137
|
+
|
138
|
+
url = f.url
|
139
|
+
data = _process_data(data)
|
140
|
+
|
141
|
+
response = session.request(method, url, headers=_get_headers(access_token), data=data)
|
142
|
+
response.raise_for_status()
|
143
|
+
if response.status_code == HTTPStatus.NO_CONTENT:
|
144
|
+
return response.status_code, None
|
145
|
+
elif response.status_code == HTTPStatus.ACCEPTED:
|
146
|
+
return response.status_code, response.headers['Location']
|
147
|
+
else:
|
148
|
+
return response.status_code, response.json()
|
149
|
+
|
150
|
+
def _delete(access_token=None, resource=None, method='delete', data=None, params=None):
|
151
|
+
if access_token is None:
|
152
|
+
access_token = _get_access_token()
|
153
|
+
session = get_session()
|
154
|
+
|
155
|
+
f = furl(DS_TOOLKIT_URL)
|
156
|
+
f.path = f'api/{resource}'
|
157
|
+
f = _add_params(f, params)
|
158
|
+
|
159
|
+
url = f.url
|
160
|
+
if data:
|
161
|
+
response = session.request(method, url, headers=_get_headers(access_token), data=_process_data(data))
|
162
|
+
else:
|
163
|
+
response = session.request(method, url, headers=_get_headers(access_token))
|
164
|
+
response.raise_for_status()
|
165
|
+
if response.status_code == HTTPStatus.NO_CONTENT:
|
166
|
+
return response.status_code, None
|
167
|
+
elif response.status_code == HTTPStatus.ACCEPTED:
|
168
|
+
return response.status_code, response.headers['Location']
|
169
|
+
else:
|
170
|
+
return response.status_code, response.json()
|
@@ -0,0 +1,10 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
VINZ_URL = os.getenv('VINZ_URL') or 'https://vinz.atlasai.co'
|
4
|
+
DS_TOOLKIT_URL = os.getenv('DS_TOOLKIT_URL') or 'https://dstoolkit.atlasai.co'
|
5
|
+
|
6
|
+
DEFAULT_PAGE_SIZE = 20
|
7
|
+
DISABLE_SSL_VERIFICATION = 'DISABLE_SSL_VERIFICATION'
|
8
|
+
|
9
|
+
TOKEN_ENV_VAR = 'VINZ_ENCRYPTED_TOKEN'
|
10
|
+
TOKEN_TIMESTAMP_ENV_VAR = 'VINZ_ENCRYPTED_TOKEN_TIMESTAMP'
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# Copyright 2025 AtlasAI PBC. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
import uuid
|
16
|
+
import arrow
|
17
|
+
|
18
|
+
from . import api, constants, utils
|
19
|
+
|
20
|
+
|
21
|
+
def search(*args, **kwargs):
|
22
|
+
fs = FabricSearch(*args, **kwargs)
|
23
|
+
utils.show_page(fs.page)
|
24
|
+
return fs
|
25
|
+
|
26
|
+
class FabricSearch:
|
27
|
+
|
28
|
+
def __init__(self, id=None, *args, **kwargs):
|
29
|
+
self.id = id or uuid.uuid4()
|
30
|
+
self._search = None
|
31
|
+
|
32
|
+
def __repr__(self):
|
33
|
+
return f'FabricSearch({self.id})'
|
34
|
+
|
35
|
+
def __str__(self):
|
36
|
+
return f'FabricSearch({self.id})'
|
37
|
+
|
38
|
+
@property
|
39
|
+
def page(self):
|
40
|
+
return f'{constants.DS_TOOLKIT_URL}/fabric/search/{self.id}'
|
41
|
+
|
42
|
+
@property
|
43
|
+
def search(self):
|
44
|
+
return self._search
|
45
|
+
|
46
|
+
def refresh(self):
|
47
|
+
if self._search is None:
|
48
|
+
self._search = self._refresh()
|
49
|
+
else:
|
50
|
+
new_version = self._info()
|
51
|
+
# new updates ? pull them
|
52
|
+
if arrow.get(new_version['update_date']) > arrow.get(self._search['update_date']):
|
53
|
+
self._search = self._refresh()
|
54
|
+
return self._search
|
55
|
+
|
56
|
+
def info(self):
|
57
|
+
return self._info()
|
58
|
+
|
59
|
+
def _info(self):
|
60
|
+
resource = f'/fabric/search/{self.id}/info'
|
61
|
+
_, data = api._get(resource=resource)
|
62
|
+
return data['data']
|
63
|
+
|
64
|
+
def _refresh(self):
|
65
|
+
resource = f'/fabric/search/{self.id}/select'
|
66
|
+
_, data = api._get(resource=resource)
|
67
|
+
return data['data']
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Copyright 2025 AtlasAI PBC. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
import uuid
|
16
|
+
import pandas as pd
|
17
|
+
|
18
|
+
from . import api, constants, utils
|
19
|
+
|
20
|
+
|
21
|
+
def export(*args, **kwargs):
|
22
|
+
fe = FeatureExport(*args, **kwargs)
|
23
|
+
utils.show_page(fe.page)
|
24
|
+
return fe
|
25
|
+
|
26
|
+
class FeatureExport:
|
27
|
+
def __init__(self, search, id=None, *args, **kwargs):
|
28
|
+
self.id = id or uuid.uuid4()
|
29
|
+
self._search = search
|
30
|
+
self._export = None
|
31
|
+
|
32
|
+
def __repr__(self):
|
33
|
+
return f'FeatureExport({self._search.id})'
|
34
|
+
|
35
|
+
def __str__(self):
|
36
|
+
return f'FeatureExport({self._search.id})'
|
37
|
+
|
38
|
+
@property
|
39
|
+
def page(self):
|
40
|
+
return f'{constants.DS_TOOLKIT_URL}/feature/export/{self.id}?feature_search_id={self._search.id}'
|
41
|
+
|
42
|
+
@property
|
43
|
+
def export(self):
|
44
|
+
return self._export
|
45
|
+
|
46
|
+
@property
|
47
|
+
def search(self):
|
48
|
+
return self._search.search
|
49
|
+
|
50
|
+
def details(self):
|
51
|
+
if self.export is None or self.export.status not in ['completed', 'failed']:
|
52
|
+
self._export = self._details()
|
53
|
+
return self.export
|
54
|
+
|
55
|
+
def refresh(self):
|
56
|
+
self._export = self._details()
|
57
|
+
return self.export
|
58
|
+
|
59
|
+
def results(self, limit=None) -> pd.DataFrame:
|
60
|
+
if self.export.status not in ['completed', 'failed']:
|
61
|
+
raise Exception(f'Export state is: {self.export.status}')
|
62
|
+
|
63
|
+
path = getattr(self.export, 'url_path', getattr(self.export, 'output_path'))
|
64
|
+
if not path:
|
65
|
+
raise Exception('Path not found')
|
66
|
+
|
67
|
+
df = pd.read_parquet(path, engine='pyarrow')
|
68
|
+
if limit:
|
69
|
+
df = df.head(limit)
|
70
|
+
return df
|
71
|
+
|
72
|
+
def _details(self):
|
73
|
+
resource = f'/feature/export/{self._search.id}/details'
|
74
|
+
_, data = api._get(resource=resource)
|
75
|
+
return data['data']
|
atlasai/toolkit/init.py
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Copyright 2025 AtlasAI PBC. All Rights Reserved.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
import logging
|
16
|
+
import os
|
17
|
+
|
18
|
+
def configure_logging():
|
19
|
+
handler = logging.StreamHandler()
|
20
|
+
formatter = logging.Formatter(
|
21
|
+
'%(asctime)s %(levelname)-5.5s [%(name)s][pid:%(process)s tid:%(thread)s] %(message)s'
|
22
|
+
)
|
23
|
+
handler.setFormatter(formatter)
|
24
|
+
|
25
|
+
log_level = (os.getenv('DSTOOLKIT_LOG_LEVEL') or 'INFO').upper()
|
26
|
+
log_level = getattr(logging, log_level, logging.INFO)
|
27
|
+
|
28
|
+
logger = logging.getLogger('atlasai.toolkit')
|
29
|
+
logger.setLevel(log_level)
|
30
|
+
logger.addHandler(handler)
|
atlasai/toolkit/login.py
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
import hmac
|
2
|
+
import logging
|
3
|
+
import os
|
4
|
+
from urllib.parse import urlparse
|
5
|
+
import warnings
|
6
|
+
|
7
|
+
import arrow
|
8
|
+
from furl import furl
|
9
|
+
import requests
|
10
|
+
|
11
|
+
from . import constants
|
12
|
+
from .utils import clean_token_env_vars
|
13
|
+
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
def login(env_name='ATLASAI_TOKEN', return_access_token=False):
|
19
|
+
"""
|
20
|
+
Authenticate with Vinz
|
21
|
+
|
22
|
+
Returns an OAuth2 Access Token
|
23
|
+
|
24
|
+
If `env_name` provided, the Access Token will be saved
|
25
|
+
to the named environment variable
|
26
|
+
|
27
|
+
#### Usage
|
28
|
+
|
29
|
+
```python
|
30
|
+
from atlasai.vinz import client
|
31
|
+
|
32
|
+
token = client.authenticate(<OPTIONAL_ENV_VARIABLE_NAME>)
|
33
|
+
```
|
34
|
+
"""
|
35
|
+
os.environ['ATLASAI_TOKEN_NAME'] = env_name
|
36
|
+
f = furl(constants.VINZ_URL)
|
37
|
+
f.path = 'api/token'
|
38
|
+
url = f.url
|
39
|
+
headers = {}
|
40
|
+
include_authorization(url, headers)
|
41
|
+
|
42
|
+
response = requests.get(url, headers=headers)
|
43
|
+
response.raise_for_status()
|
44
|
+
data = response.json()
|
45
|
+
token = data['access_token']
|
46
|
+
|
47
|
+
os.environ[env_name] = token
|
48
|
+
|
49
|
+
user_id = data.get('email') or data.get('sub') or 'AtlasAI Employee'
|
50
|
+
os.environ['LOGNAME'] = user_id
|
51
|
+
|
52
|
+
if return_access_token:
|
53
|
+
return token
|
54
|
+
|
55
|
+
def logout():
|
56
|
+
os.environ.pop(os.getenv('ATLASAI_TOKEN_NAME', ''), None)
|
57
|
+
clean_token_env_vars()
|
58
|
+
|
59
|
+
def load_credentials(access_key=None, secret_key=None):
|
60
|
+
access_key = access_key or os.getenv('ATLASAI_ACCESS_KEY')
|
61
|
+
secret_key = secret_key or os.getenv('ATLASAI_SECRET_KEY')
|
62
|
+
|
63
|
+
return access_key, secret_key
|
64
|
+
|
65
|
+
|
66
|
+
def include_authorization(url, headers, bearer_token=None, access_key=None, secret_key=None):
|
67
|
+
bearer_token = bearer_token or os.getenv('ATLASAI_BEARER_TOKEN')
|
68
|
+
access_key, secret_key = load_credentials(
|
69
|
+
access_key=access_key,
|
70
|
+
secret_key=secret_key,
|
71
|
+
)
|
72
|
+
|
73
|
+
if bearer_token:
|
74
|
+
headers['Authorization'] = f'Bearer {bearer_token}'
|
75
|
+
return
|
76
|
+
|
77
|
+
if not access_key or not secret_key:
|
78
|
+
warnings.warn('No API Keys provided to access Vinz API. Provide the following pair ATLASAI_ACCESS_KEY and ATLASAI_SECRET_KEY')
|
79
|
+
raise ValueError('ATLASAI_ACCESS_KEY and ATLASAI_SECRET_KEY must be provided together')
|
80
|
+
|
81
|
+
product, version = 'atlasai', '1'
|
82
|
+
headers.update({
|
83
|
+
'Host': urlparse(url).netloc,
|
84
|
+
'X-AtlasAI-Date': arrow.utcnow().isoformat(),
|
85
|
+
'X-AtlasAI-Credential': '/'.join([product, version, access_key]),
|
86
|
+
'X-AtlasAI-SignedHeaders': 'x-atlasai-date;x-atlasai-credential;host',
|
87
|
+
})
|
88
|
+
|
89
|
+
sign_request(headers, secret_key)
|
90
|
+
|
91
|
+
|
92
|
+
def sign_request(headers, secret_key):
|
93
|
+
product, version, access_key = headers['X-AtlasAI-Credential'].split('/')
|
94
|
+
key = f'{product}{version}{secret_key}'.encode('utf-8')
|
95
|
+
for msg in (
|
96
|
+
headers['X-AtlasAI-Date'],
|
97
|
+
f'{product}_{version}_request',
|
98
|
+
):
|
99
|
+
obj = hmac.new(key, msg.encode('utf-8'), 'sha256')
|
100
|
+
key = obj.digest()
|
101
|
+
|
102
|
+
msg = '\n'.join([
|
103
|
+
headers['X-AtlasAI-Date'],
|
104
|
+
headers['X-AtlasAI-Credential'],
|
105
|
+
headers['Host']
|
106
|
+
])
|
107
|
+
headers['X-AtlasAI-Signature'] = hmac.new(key, msg.encode('utf-8'), 'sha256').hexdigest()
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
import requests
|
4
|
+
from requests.adapters import HTTPAdapter, Retry
|
5
|
+
from .constants import DISABLE_SSL_VERIFICATION
|
6
|
+
|
7
|
+
|
8
|
+
STATUS_FORCELIST = tuple([429, 500, 502, 503, 504])
|
9
|
+
|
10
|
+
def mount_retry(
|
11
|
+
session,
|
12
|
+
total=10,
|
13
|
+
backoff_factor=0.2,
|
14
|
+
allowed_methods=None,
|
15
|
+
status_forcelist=STATUS_FORCELIST,
|
16
|
+
):
|
17
|
+
"""
|
18
|
+
Attach retry handlers to HTTP and HTTPS endpoints of a Requests Session
|
19
|
+
"""
|
20
|
+
|
21
|
+
retries = Retry(
|
22
|
+
total=total,
|
23
|
+
backoff_factor=backoff_factor,
|
24
|
+
allowed_methods=allowed_methods,
|
25
|
+
status_forcelist=status_forcelist,
|
26
|
+
)
|
27
|
+
|
28
|
+
session.mount('http://', HTTPAdapter(max_retries=retries))
|
29
|
+
session.mount('https://', HTTPAdapter(max_retries=retries))
|
30
|
+
|
31
|
+
def get_session(
|
32
|
+
total=3,
|
33
|
+
backoff_factor=0.2,
|
34
|
+
allowed_methods=None,
|
35
|
+
status_forcelist=STATUS_FORCELIST,
|
36
|
+
):
|
37
|
+
"""
|
38
|
+
Get a Requests Session with retry handlers for HTTP and HTTPS endpoints
|
39
|
+
"""
|
40
|
+
|
41
|
+
sess = requests.Session()
|
42
|
+
if os.getenv(DISABLE_SSL_VERIFICATION):
|
43
|
+
sess.verify = False
|
44
|
+
mount_retry(
|
45
|
+
sess,
|
46
|
+
total=total,
|
47
|
+
backoff_factor=backoff_factor,
|
48
|
+
allowed_methods=allowed_methods,
|
49
|
+
status_forcelist=status_forcelist,
|
50
|
+
)
|
51
|
+
|
52
|
+
return sess
|
atlasai/toolkit/utils.py
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
import arrow
|
2
|
+
import os
|
3
|
+
|
4
|
+
from furl import furl
|
5
|
+
import webbrowser
|
6
|
+
|
7
|
+
from . import api, constants
|
8
|
+
|
9
|
+
def is_notebook() -> bool:
|
10
|
+
try:
|
11
|
+
from IPython import get_ipython
|
12
|
+
shell = get_ipython().__class__.__name__
|
13
|
+
if shell == 'ZMQInteractiveShell':
|
14
|
+
return True
|
15
|
+
elif shell == 'TerminalInteractiveShell':
|
16
|
+
return False
|
17
|
+
else:
|
18
|
+
return False
|
19
|
+
except Exception:
|
20
|
+
return False
|
21
|
+
|
22
|
+
|
23
|
+
def show_page(page):
|
24
|
+
f = furl(page)
|
25
|
+
|
26
|
+
if is_first_page():
|
27
|
+
token = retrieve_one_time_token()
|
28
|
+
set_token_env_vars(token)
|
29
|
+
f.args['token'] = token
|
30
|
+
|
31
|
+
if is_notebook():
|
32
|
+
from IPython.core.display import display
|
33
|
+
from IPython.display import IFrame
|
34
|
+
display(IFrame(f.url, width=800, height=600))
|
35
|
+
else:
|
36
|
+
webbrowser.open(f.url)
|
37
|
+
|
38
|
+
def is_first_page():
|
39
|
+
if os.getenv(constants.TOKEN_ENV_VAR) is None:
|
40
|
+
return True
|
41
|
+
last_set = os.getenv(constants.TOKEN_TIMESTAMP_ENV_VAR)
|
42
|
+
if last_set:
|
43
|
+
last_set = arrow.get(last_set)
|
44
|
+
# if had passed more than 24h since last iframe. pass the token again in case it needs it
|
45
|
+
if arrow.utcnow() >= last_set.shift(hours=+24):
|
46
|
+
return True
|
47
|
+
|
48
|
+
def set_token_env_vars(token):
|
49
|
+
os.environ[constants.TOKEN_ENV_VAR] = token
|
50
|
+
os.environ[constants.TOKEN_TIMESTAMP_ENV_VAR] = arrow.now().isoformat()
|
51
|
+
|
52
|
+
def clean_token_env_vars():
|
53
|
+
os.environ.pop(constants.TOKEN_ENV_VAR, None)
|
54
|
+
os.environ.pop(constants.TOKEN_TIMESTAMP_ENV_VAR, None)
|
55
|
+
|
56
|
+
def retrieve_one_time_token():
|
57
|
+
_, data = api._post(resource='token/wrap', url=constants.VINZ_URL)
|
58
|
+
return data['token']
|
@@ -0,0 +1,14 @@
|
|
1
|
+
atlasai/toolkit/__init__.py,sha256=szu5LHZ41ccWztCI2LvQ3QnZRybosgTbU3yd6tS7cUw,986
|
2
|
+
atlasai/toolkit/api.py,sha256=BvO-gLRmbmkKduwbbADjcLlIkS9blzfM_cbMR4DhQmU,5269
|
3
|
+
atlasai/toolkit/constants.py,sha256=sE0PeFa9_htCPVFADHbkyPIz3QOai0tAIA5IiiZI8wA,329
|
4
|
+
atlasai/toolkit/fabric.py,sha256=vjc8PJ30bUZ9z-ZqovpfqDkOo_OkMH80GMX8YoOPdfI,1923
|
5
|
+
atlasai/toolkit/feature.py,sha256=ijoljwdtlI2djeALY14ctL97K5wbzpJkRMtwq-y-PIg,2276
|
6
|
+
atlasai/toolkit/init.py,sha256=JkdJ6QGdYWrq65jgz2pn5RYXUeUe2Ez88_-eMf5CNi0,1100
|
7
|
+
atlasai/toolkit/login.py,sha256=n4ydfo9qCsmbZq6er1xeljBD76vdTJGjbhYHMmOyDbQ,3061
|
8
|
+
atlasai/toolkit/requests.py,sha256=X86nIo07hAjUlilZcZ1lV8RB7KOsTKbTGtcY_SpFEXY,1223
|
9
|
+
atlasai/toolkit/utils.py,sha256=kEoNz3BbSgKbq6X2dDlM4Odcbw2BfoNyls2RKRAL5wQ,1639
|
10
|
+
atlasai_dstoolkit_client-0.0.2.dist-info/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
11
|
+
atlasai_dstoolkit_client-0.0.2.dist-info/METADATA,sha256=2c-eLkb3z0P2uuQ1E-3J3B4Bi-rQIEYHslmGZ1H3LSU,1301
|
12
|
+
atlasai_dstoolkit_client-0.0.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
13
|
+
atlasai_dstoolkit_client-0.0.2.dist-info/top_level.txt,sha256=HRTbErU8nmHFDaJJ5R_XYbwpt21dqdjDpSva8xyy_0k,8
|
14
|
+
atlasai_dstoolkit_client-0.0.2.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
atlasai
|
@@ -1,5 +0,0 @@
|
|
1
|
-
atlasai_dstoolkit_client-0.0.1.dist-info/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
2
|
-
atlasai_dstoolkit_client-0.0.1.dist-info/METADATA,sha256=Kqg9p64yglqrHsSkqwxYOcZGUDC-2D9QG1RCSS4oa0k,1301
|
3
|
-
atlasai_dstoolkit_client-0.0.1.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
4
|
-
atlasai_dstoolkit_client-0.0.1.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
5
|
-
atlasai_dstoolkit_client-0.0.1.dist-info/RECORD,,
|
@@ -1 +0,0 @@
|
|
1
|
-
|
{atlasai_dstoolkit_client-0.0.1.dist-info → atlasai_dstoolkit_client-0.0.2.dist-info}/LICENSE.txt
RENAMED
File without changes
|
File without changes
|