erioon 0.1.1__py3-none-any.whl → 0.1.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.
- erioon/client.py +31 -72
- {erioon-0.1.1.dist-info → erioon-0.1.2.dist-info}/METADATA +1 -1
- {erioon-0.1.1.dist-info → erioon-0.1.2.dist-info}/RECORD +6 -6
- {erioon-0.1.1.dist-info → erioon-0.1.2.dist-info}/LICENSE +0 -0
- {erioon-0.1.1.dist-info → erioon-0.1.2.dist-info}/WHEEL +0 -0
- {erioon-0.1.1.dist-info → erioon-0.1.2.dist-info}/top_level.txt +0 -0
erioon/client.py
CHANGED
@@ -5,23 +5,12 @@ from datetime import datetime, timezone
|
|
5
5
|
from erioon.database import Database
|
6
6
|
|
7
7
|
class ErioonClient:
|
8
|
-
"""
|
9
|
-
Client SDK for interacting with the Erioon API.
|
10
|
-
|
11
|
-
Handles:
|
12
|
-
- User authentication with email/password and API key
|
13
|
-
- Token caching to avoid re-authenticating every time
|
14
|
-
- SAS token expiration detection and auto-renewal
|
15
|
-
- Access to user-specific databases
|
16
|
-
"""
|
17
|
-
|
18
8
|
def __init__(self, api, email, password, base_url="https://sdk.erioon.com"):
|
19
9
|
self.api = api
|
20
10
|
self.email = email
|
21
11
|
self.password = password
|
22
12
|
self.base_url = base_url
|
23
13
|
self.user_id = None
|
24
|
-
self.error = None
|
25
14
|
self.token_path = os.path.expanduser(f"~/.erioon_token_{self._safe_filename(email)}")
|
26
15
|
self.login_metadata = None
|
27
16
|
|
@@ -29,42 +18,28 @@ class ErioonClient:
|
|
29
18
|
self.login_metadata = self._load_or_login()
|
30
19
|
self._update_metadata_fields()
|
31
20
|
except Exception as e:
|
32
|
-
|
21
|
+
print(f"[ErioonClient] Initialization error: {e}")
|
33
22
|
|
34
23
|
def _safe_filename(self, text):
|
35
|
-
"""
|
36
|
-
Converts unsafe filename characters to underscores for cache file naming.
|
37
|
-
"""
|
38
24
|
return "".join(c if c.isalnum() else "_" for c in text)
|
39
25
|
|
40
26
|
def _do_login_and_cache(self):
|
41
|
-
"""
|
42
|
-
Logs in to the API and writes the returned metadata (e.g. SAS token, user ID) to a local file.
|
43
|
-
"""
|
44
27
|
metadata = self._login()
|
45
28
|
with open(self.token_path, "w") as f:
|
46
29
|
json.dump(metadata, f)
|
47
30
|
return metadata
|
48
31
|
|
49
32
|
def _load_or_login(self):
|
50
|
-
"""
|
51
|
-
Tries to load the cached login metadata.
|
52
|
-
If token is expired or file does not exist, performs a fresh login.
|
53
|
-
"""
|
54
33
|
if os.path.exists(self.token_path):
|
55
34
|
with open(self.token_path, "r") as f:
|
56
35
|
metadata = json.load(f)
|
57
36
|
if self._is_sas_expired(metadata):
|
58
|
-
|
37
|
+
return self._do_login_and_cache()
|
59
38
|
return metadata
|
60
39
|
else:
|
61
40
|
return self._do_login_and_cache()
|
62
41
|
|
63
42
|
def _login(self):
|
64
|
-
"""
|
65
|
-
Sends login request to Erioon API using API key, email, and password.
|
66
|
-
Returns authentication metadata including SAS token.
|
67
|
-
"""
|
68
43
|
url = f"{self.base_url}/login_with_credentials"
|
69
44
|
payload = {"api_key": self.api, "email": self.email, "password": self.password}
|
70
45
|
headers = {"Content-Type": "application/json"}
|
@@ -76,7 +51,12 @@ class ErioonClient:
|
|
76
51
|
self._update_metadata_fields()
|
77
52
|
return data
|
78
53
|
else:
|
79
|
-
|
54
|
+
try:
|
55
|
+
msg = response.json().get("error", "Login failed")
|
56
|
+
except Exception:
|
57
|
+
msg = response.text
|
58
|
+
print(f"[ErioonClient] Login failed: {msg}")
|
59
|
+
raise RuntimeError(msg)
|
80
60
|
|
81
61
|
def _update_metadata_fields(self):
|
82
62
|
if self.login_metadata:
|
@@ -85,26 +65,16 @@ class ErioonClient:
|
|
85
65
|
self.database = self.login_metadata.get("database")
|
86
66
|
self.sas_tokens = self.login_metadata.get("sas_tokens", {})
|
87
67
|
|
88
|
-
|
89
68
|
def _clear_cached_token(self):
|
90
|
-
"""
|
91
|
-
Clears the locally cached authentication token and resets internal state.
|
92
|
-
"""
|
93
69
|
if os.path.exists(self.token_path):
|
94
70
|
os.remove(self.token_path)
|
95
71
|
self.user_id = None
|
96
72
|
self.login_metadata = None
|
97
73
|
|
98
74
|
def _is_sas_expired(self, metadata):
|
99
|
-
"""
|
100
|
-
Determines whether the SAS token has expired by comparing the 'sas_token_expiry'
|
101
|
-
or 'expiry' field with the current UTC time.
|
102
|
-
"""
|
103
75
|
expiry_str = metadata.get("sas_token_expiry") or metadata.get("expiry")
|
104
|
-
|
105
76
|
if not expiry_str:
|
106
77
|
return True
|
107
|
-
|
108
78
|
try:
|
109
79
|
expiry_dt = datetime.fromisoformat(expiry_str.replace("Z", "+00:00"))
|
110
80
|
now = datetime.now(timezone.utc)
|
@@ -113,50 +83,45 @@ class ErioonClient:
|
|
113
83
|
return True
|
114
84
|
|
115
85
|
def __getitem__(self, db_id):
|
116
|
-
"""
|
117
|
-
Allows syntax like `client["my_database_id"]` to access a database.
|
118
|
-
If the token is expired or invalid, it attempts reauthentication.
|
119
|
-
"""
|
120
86
|
if not self.user_id:
|
121
|
-
|
87
|
+
print(f"[ErioonClient] Not authenticated. Cannot access database {db_id}.")
|
88
|
+
raise ValueError("Client not authenticated.")
|
122
89
|
|
123
90
|
try:
|
124
91
|
return self._get_database_info(db_id)
|
125
92
|
except Exception as e:
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
raise
|
93
|
+
print(f"[ErioonClient] Access failed for DB {db_id}, retrying login... ({e})")
|
94
|
+
self._clear_cached_token()
|
95
|
+
|
96
|
+
try:
|
97
|
+
self.login_metadata = self._do_login_and_cache()
|
98
|
+
self._update_metadata_fields()
|
99
|
+
except Exception as login_error:
|
100
|
+
print(f"[ErioonClient] Re-login failed: {login_error}")
|
101
|
+
raise RuntimeError(login_error)
|
102
|
+
|
103
|
+
try:
|
104
|
+
return self._get_database_info(db_id)
|
105
|
+
except Exception as second_error:
|
106
|
+
print(f"[ErioonClient] DB fetch after re-auth failed: {second_error}")
|
107
|
+
raise RuntimeError(second_error)
|
141
108
|
|
142
109
|
def _get_database_info(self, db_id):
|
143
110
|
payload = {"user_id": self.user_id, "db_id": db_id}
|
144
111
|
headers = {"Content-Type": "application/json"}
|
145
|
-
|
146
112
|
response = requests.post(f"{self.base_url}/db_info", json=payload, headers=headers)
|
147
113
|
|
148
114
|
if response.status_code == 200:
|
149
115
|
db_info = response.json()
|
150
|
-
|
151
116
|
sas_info = self.sas_tokens.get(db_id)
|
152
117
|
if not sas_info:
|
153
|
-
raise Exception(f"No SAS token info
|
118
|
+
raise Exception(f"No SAS token info for database id {db_id}")
|
154
119
|
|
155
120
|
container_url = sas_info.get("container_url")
|
156
121
|
sas_token = sas_info.get("sas_token")
|
157
122
|
|
158
123
|
if not container_url or not sas_token:
|
159
|
-
raise Exception("Missing SAS URL components
|
124
|
+
raise Exception("Missing SAS URL components")
|
160
125
|
|
161
126
|
if not sas_token.startswith("?"):
|
162
127
|
sas_token = "?" + sas_token
|
@@ -176,16 +141,10 @@ class ErioonClient:
|
|
176
141
|
error_msg = error_json.get("error", response.text)
|
177
142
|
except Exception:
|
178
143
|
error_msg = response.text
|
179
|
-
raise Exception(error_msg)
|
180
|
-
|
144
|
+
raise Exception(f"Failed to fetch database info: {error_msg}")
|
145
|
+
|
181
146
|
def __str__(self):
|
182
|
-
""
|
183
|
-
Returns user_id or error string when printed.
|
184
|
-
"""
|
185
|
-
return self.user_id if self.user_id else self.error
|
147
|
+
return self.user_id if self.user_id else "[ErioonClient] Unauthenticated"
|
186
148
|
|
187
149
|
def __repr__(self):
|
188
|
-
"""
|
189
|
-
Developer-friendly representation of the client.
|
190
|
-
"""
|
191
|
-
return f"<ErioonClient user_id={self.user_id}>" if self.user_id else f"<ErioonClient error='{self.error}'>"
|
150
|
+
return f"<ErioonClient user_id={self.user_id}>" if self.user_id else "<ErioonClient unauthenticated>"
|
@@ -1,5 +1,5 @@
|
|
1
1
|
erioon/auth.py,sha256=McktLrdxsWVyxhiFuk0qFokx63RI1yB8_qP3Mo7uZCI,724
|
2
|
-
erioon/client.py,sha256=
|
2
|
+
erioon/client.py,sha256=5Sd-s95UQokJLByA15ViYCxjAHennnb1vITj-nNtBKE,5714
|
3
3
|
erioon/collection.py,sha256=EyNHpoOEBBMH29gMy51zzR338z2uI79kl0_ZB7laHpM,9700
|
4
4
|
erioon/create.py,sha256=ilx0e3urK0lfYiaM3CSUe3Bf3l7GhHuwZyz0Z6ij0ok,10202
|
5
5
|
erioon/database.py,sha256=hj5sgaEDXmItg4aeZlO3MP6_hV3jeS-d9qycEnw7xHQ,2449
|
@@ -8,8 +8,8 @@ erioon/functions.py,sha256=LWrqslAok-l9QlMEynT-Pvksy5hwkogWoeK5rJf464A,12479
|
|
8
8
|
erioon/ping.py,sha256=BC0vZiane5YgCc07syZA5dKFcqbq1_Z8BUTmvIGRPcs,1829
|
9
9
|
erioon/read.py,sha256=kzzqqRuLtYmlniAnkd2xeWNZm4AwMQ2oAMcpKt6JhcQ,10580
|
10
10
|
erioon/update.py,sha256=E3d-dYJWh12bcAHx_vT9NFTscF__hViY3K9ZssN7At4,6060
|
11
|
-
erioon-0.1.
|
12
|
-
erioon-0.1.
|
13
|
-
erioon-0.1.
|
14
|
-
erioon-0.1.
|
15
|
-
erioon-0.1.
|
11
|
+
erioon-0.1.2.dist-info/LICENSE,sha256=xwnq3DNlZpQyteOK9HvtHRhMdYviXTTaCDljEodFRnQ,569
|
12
|
+
erioon-0.1.2.dist-info/METADATA,sha256=IZzuMRl69uhU0QqDGhwa-iaLPALcwbhBlR7Pke0HlGU,715
|
13
|
+
erioon-0.1.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
14
|
+
erioon-0.1.2.dist-info/top_level.txt,sha256=yjKEg85X5Q5ot46IMML_xukvIGG5YfdrLWcemjalItc,7
|
15
|
+
erioon-0.1.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|