erioon 0.0.7__py3-none-any.whl → 0.0.9__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/auth.py +1 -1
- erioon/client.py +73 -78
- erioon/collection.py +215 -127
- erioon/create.py +265 -0
- erioon/database.py +50 -19
- erioon/delete.py +257 -0
- erioon/functions.py +350 -0
- erioon/ping.py +37 -0
- erioon/read.py +241 -0
- erioon/update.py +123 -0
- {erioon-0.0.7.dist-info → erioon-0.0.9.dist-info}/METADATA +1 -1
- erioon-0.0.9.dist-info/RECORD +15 -0
- erioon-0.0.7.dist-info/RECORD +0 -9
- {erioon-0.0.7.dist-info → erioon-0.0.9.dist-info}/LICENSE +0 -0
- {erioon-0.0.7.dist-info → erioon-0.0.9.dist-info}/WHEEL +0 -0
- {erioon-0.0.7.dist-info → erioon-0.0.9.dist-info}/top_level.txt +0 -0
erioon/auth.py
CHANGED
@@ -13,7 +13,7 @@ def Auth(credential_string):
|
|
13
13
|
|
14
14
|
Example usage:
|
15
15
|
>>> from erioon.auth import Auth
|
16
|
-
>>> client = Auth("<EMAIL>:<PASSWORD>")
|
16
|
+
>>> client = Auth("<API_KEY>:<EMAIL>:<PASSWORD>")
|
17
17
|
>>> print(client) # prints user_id if successful or error message if not
|
18
18
|
"""
|
19
19
|
api, email, password = credential_string.split(":")
|
erioon/client.py
CHANGED
@@ -1,33 +1,21 @@
|
|
1
1
|
import os
|
2
2
|
import json
|
3
3
|
import requests
|
4
|
-
from
|
4
|
+
from datetime import datetime, timezone
|
5
5
|
from erioon.database import Database
|
6
6
|
|
7
7
|
class ErioonClient:
|
8
8
|
"""
|
9
9
|
Client SDK for interacting with the Erioon API.
|
10
10
|
|
11
|
-
Handles
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
base_url (str): Base URL of the Erioon API.
|
17
|
-
user_id (str | None): Authenticated user ID.
|
18
|
-
error (str | None): Stores error messages if login fails.
|
19
|
-
token_path (str): Local path to cached authentication token.
|
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
|
20
16
|
"""
|
21
17
|
|
22
18
|
def __init__(self, api, email, password, base_url="https://sdk.erioon.com"):
|
23
|
-
"""
|
24
|
-
Initialize ErioonClient instance, attempts to load cached token or perform login.
|
25
|
-
|
26
|
-
Args:
|
27
|
-
email (str): User email for authentication.
|
28
|
-
password (str): User password for authentication.
|
29
|
-
base_url (str, optional): Base API URL. Defaults to "https://sdk.erioon.com".
|
30
|
-
"""
|
31
19
|
self.api = api
|
32
20
|
self.email = email
|
33
21
|
self.password = password
|
@@ -35,34 +23,23 @@ class ErioonClient:
|
|
35
23
|
self.user_id = None
|
36
24
|
self.error = None
|
37
25
|
self.token_path = os.path.expanduser(f"~/.erioon_token_{self._safe_filename(email)}")
|
26
|
+
self.login_metadata = None
|
38
27
|
|
39
28
|
try:
|
40
|
-
|
41
|
-
self.
|
42
|
-
self.database = metadata.get("database")
|
43
|
-
self.cluster = metadata.get("cluster")
|
44
|
-
self.login_metadata = metadata
|
29
|
+
self.login_metadata = self._load_or_login()
|
30
|
+
self._update_metadata_fields()
|
45
31
|
except Exception as e:
|
46
32
|
self.error = str(e)
|
47
33
|
|
48
34
|
def _safe_filename(self, text):
|
49
35
|
"""
|
50
|
-
Converts
|
51
|
-
|
52
|
-
Args:
|
53
|
-
text (str): Input string to convert.
|
54
|
-
|
55
|
-
Returns:
|
56
|
-
str: Sanitized filename-safe string.
|
36
|
+
Converts unsafe filename characters to underscores for cache file naming.
|
57
37
|
"""
|
58
38
|
return "".join(c if c.isalnum() else "_" for c in text)
|
59
39
|
|
60
40
|
def _do_login_and_cache(self):
|
61
41
|
"""
|
62
|
-
|
63
|
-
|
64
|
-
Returns:
|
65
|
-
dict: Login metadata including user_id, database, cluster.
|
42
|
+
Logs in to the API and writes the returned metadata (e.g. SAS token, user ID) to a local file.
|
66
43
|
"""
|
67
44
|
metadata = self._login()
|
68
45
|
with open(self.token_path, "w") as f:
|
@@ -71,68 +48,80 @@ class ErioonClient:
|
|
71
48
|
|
72
49
|
def _load_or_login(self):
|
73
50
|
"""
|
74
|
-
|
75
|
-
|
76
|
-
Returns:
|
77
|
-
dict: Login metadata.
|
51
|
+
Tries to load the cached login metadata.
|
52
|
+
If token is expired or file does not exist, performs a fresh login.
|
78
53
|
"""
|
79
54
|
if os.path.exists(self.token_path):
|
80
55
|
with open(self.token_path, "r") as f:
|
81
56
|
metadata = json.load(f)
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
57
|
+
if self._is_sas_expired(metadata):
|
58
|
+
metadata = self._do_login_and_cache()
|
59
|
+
return metadata
|
60
|
+
else:
|
61
|
+
return self._do_login_and_cache()
|
86
62
|
|
87
63
|
def _login(self):
|
88
64
|
"""
|
89
|
-
|
90
|
-
|
91
|
-
Returns:
|
92
|
-
dict: Metadata with user_id, database, cluster, etc.
|
65
|
+
Sends login request to Erioon API using API key, email, and password.
|
66
|
+
Returns authentication metadata including SAS token.
|
93
67
|
"""
|
94
68
|
url = f"{self.base_url}/login_with_credentials"
|
95
|
-
payload = {"api_key": self.api,"email": self.email, "password": self.password}
|
69
|
+
payload = {"api_key": self.api, "email": self.email, "password": self.password}
|
96
70
|
headers = {"Content-Type": "application/json"}
|
97
71
|
|
98
72
|
response = requests.post(url, json=payload, headers=headers)
|
99
73
|
if response.status_code == 200:
|
100
74
|
data = response.json()
|
101
75
|
self.login_metadata = data
|
76
|
+
self._update_metadata_fields()
|
102
77
|
return data
|
103
78
|
else:
|
104
79
|
raise Exception("Invalid account")
|
105
80
|
|
81
|
+
def _update_metadata_fields(self):
|
82
|
+
"""
|
83
|
+
Updates internal fields like user_id, database name, and cluster info
|
84
|
+
from login metadata.
|
85
|
+
"""
|
86
|
+
if self.login_metadata:
|
87
|
+
self.user_id = self.login_metadata.get("_id")
|
88
|
+
self.database = self.login_metadata.get("database")
|
89
|
+
self.cluster = self.login_metadata.get("cluster")
|
106
90
|
|
107
91
|
def _clear_cached_token(self):
|
108
92
|
"""
|
109
|
-
|
93
|
+
Clears the locally cached authentication token and resets internal state.
|
110
94
|
"""
|
111
95
|
if os.path.exists(self.token_path):
|
112
96
|
os.remove(self.token_path)
|
113
97
|
self.user_id = None
|
98
|
+
self.login_metadata = None
|
114
99
|
|
115
|
-
def
|
100
|
+
def _is_sas_expired(self, metadata):
|
116
101
|
"""
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
102
|
+
Determines whether the SAS token has expired by comparing the 'sas_token_expiry'
|
103
|
+
or 'expiry' field with the current UTC time.
|
104
|
+
"""
|
105
|
+
expiry_str = metadata.get("sas_token_expiry") or metadata.get("expiry")
|
121
106
|
|
122
|
-
|
123
|
-
|
107
|
+
if not expiry_str:
|
108
|
+
return True
|
124
109
|
|
125
|
-
|
126
|
-
|
127
|
-
|
110
|
+
try:
|
111
|
+
expiry_dt = datetime.fromisoformat(expiry_str.replace("Z", "+00:00"))
|
112
|
+
now = datetime.now(timezone.utc)
|
113
|
+
return now >= expiry_dt
|
114
|
+
except Exception:
|
115
|
+
return True
|
128
116
|
|
129
|
-
|
130
|
-
|
131
|
-
|
117
|
+
def __getitem__(self, db_id):
|
118
|
+
"""
|
119
|
+
Allows syntax like `client["my_database_id"]` to access a database.
|
120
|
+
If the token is expired or invalid, it attempts reauthentication.
|
132
121
|
"""
|
133
122
|
if not self.user_id:
|
134
123
|
raise ValueError("Client not authenticated. Cannot access database.")
|
135
|
-
|
124
|
+
|
136
125
|
try:
|
137
126
|
return self._get_database_info(db_id)
|
138
127
|
except Exception as e:
|
@@ -140,29 +129,22 @@ class ErioonClient:
|
|
140
129
|
if f"database with {db_id.lower()}" in err_msg or "database" in err_msg:
|
141
130
|
self._clear_cached_token()
|
142
131
|
try:
|
143
|
-
self.
|
132
|
+
self.login_metadata = self._do_login_and_cache()
|
133
|
+
self._update_metadata_fields()
|
144
134
|
except Exception:
|
145
135
|
return "Login error"
|
146
|
-
|
136
|
+
|
147
137
|
try:
|
148
138
|
return self._get_database_info(db_id)
|
149
139
|
except Exception:
|
150
140
|
return f"❌ Database with _id {db_id} ..."
|
151
141
|
else:
|
152
142
|
raise e
|
153
|
-
|
143
|
+
|
154
144
|
def _get_database_info(self, db_id):
|
155
145
|
"""
|
156
|
-
|
157
|
-
|
158
|
-
Args:
|
159
|
-
db_id (str): The database ID to fetch.
|
160
|
-
|
161
|
-
Returns:
|
162
|
-
Database: Database instance with the fetched info.
|
163
|
-
|
164
|
-
Raises:
|
165
|
-
Exception: If API returns an error.
|
146
|
+
Sends a POST request to fetch metadata for a given database ID.
|
147
|
+
Returns a `Database` instance initialized with SAS URL and metadata.
|
166
148
|
"""
|
167
149
|
payload = {"user_id": self.user_id, "db_id": db_id}
|
168
150
|
headers = {"Content-Type": "application/json"}
|
@@ -171,11 +153,24 @@ class ErioonClient:
|
|
171
153
|
|
172
154
|
if response.status_code == 200:
|
173
155
|
db_info = response.json()
|
156
|
+
|
157
|
+
container_url = self.login_metadata.get("container_url")
|
158
|
+
sas_token = self.login_metadata.get("sas_token")
|
159
|
+
|
160
|
+
if not container_url or not sas_token:
|
161
|
+
raise Exception("Missing SAS URL components for storage access")
|
162
|
+
|
163
|
+
if not sas_token.startswith("?"):
|
164
|
+
sas_token = "?" + sas_token
|
165
|
+
|
166
|
+
sas_url = container_url.split("?")[0] + sas_token
|
167
|
+
|
174
168
|
return Database(
|
175
169
|
user_id=self.user_id,
|
176
170
|
metadata=db_info,
|
177
171
|
database=self.database,
|
178
|
-
cluster=self.cluster
|
172
|
+
cluster=self.cluster,
|
173
|
+
sas_url=sas_url
|
179
174
|
)
|
180
175
|
else:
|
181
176
|
try:
|
@@ -187,12 +182,12 @@ class ErioonClient:
|
|
187
182
|
|
188
183
|
def __str__(self):
|
189
184
|
"""
|
190
|
-
|
185
|
+
Returns user_id or error string when printed.
|
191
186
|
"""
|
192
187
|
return self.user_id if self.user_id else self.error
|
193
188
|
|
194
189
|
def __repr__(self):
|
195
190
|
"""
|
196
|
-
Developer-friendly
|
191
|
+
Developer-friendly representation of the client.
|
197
192
|
"""
|
198
193
|
return f"<ErioonClient user_id={self.user_id}>" if self.user_id else f"<ErioonClient error='{self.error}'>"
|