lamindb_setup 1.8.3__py3-none-any.whl → 1.9.1__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.
Files changed (39) hide show
  1. lamindb_setup/__init__.py +107 -107
  2. lamindb_setup/_cache.py +87 -87
  3. lamindb_setup/_check_setup.py +166 -166
  4. lamindb_setup/_connect_instance.py +328 -342
  5. lamindb_setup/_delete.py +141 -141
  6. lamindb_setup/_disconnect.py +32 -32
  7. lamindb_setup/_init_instance.py +440 -440
  8. lamindb_setup/_migrate.py +266 -259
  9. lamindb_setup/_register_instance.py +35 -35
  10. lamindb_setup/_schema_metadata.py +441 -441
  11. lamindb_setup/_set_managed_storage.py +70 -70
  12. lamindb_setup/_setup_user.py +133 -133
  13. lamindb_setup/core/__init__.py +21 -21
  14. lamindb_setup/core/_aws_options.py +223 -211
  15. lamindb_setup/core/_hub_client.py +248 -243
  16. lamindb_setup/core/_hub_core.py +665 -663
  17. lamindb_setup/core/_hub_crud.py +227 -227
  18. lamindb_setup/core/_private_django_api.py +83 -83
  19. lamindb_setup/core/_settings.py +377 -364
  20. lamindb_setup/core/_settings_instance.py +569 -568
  21. lamindb_setup/core/_settings_load.py +141 -141
  22. lamindb_setup/core/_settings_save.py +95 -95
  23. lamindb_setup/core/_settings_storage.py +429 -429
  24. lamindb_setup/core/_settings_store.py +91 -91
  25. lamindb_setup/core/_settings_user.py +55 -55
  26. lamindb_setup/core/_setup_bionty_sources.py +44 -44
  27. lamindb_setup/core/cloud_sqlite_locker.py +240 -240
  28. lamindb_setup/core/django.py +305 -291
  29. lamindb_setup/core/exceptions.py +1 -1
  30. lamindb_setup/core/hashing.py +134 -134
  31. lamindb_setup/core/types.py +1 -1
  32. lamindb_setup/core/upath.py +1013 -1009
  33. lamindb_setup/errors.py +70 -70
  34. lamindb_setup/types.py +20 -20
  35. {lamindb_setup-1.8.3.dist-info → lamindb_setup-1.9.1.dist-info}/METADATA +1 -1
  36. lamindb_setup-1.9.1.dist-info/RECORD +50 -0
  37. lamindb_setup-1.8.3.dist-info/RECORD +0 -50
  38. {lamindb_setup-1.8.3.dist-info → lamindb_setup-1.9.1.dist-info}/LICENSE +0 -0
  39. {lamindb_setup-1.8.3.dist-info → lamindb_setup-1.9.1.dist-info}/WHEEL +0 -0
@@ -1,243 +1,248 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- import os
5
- from typing import Literal
6
- from urllib.request import urlretrieve
7
-
8
- from httpx import HTTPTransport
9
- from lamin_utils import logger
10
- from pydantic_settings import BaseSettings
11
- from supabase import Client, create_client # type: ignore
12
- from supabase.lib.client_options import ClientOptions
13
-
14
- from ._settings_save import save_user_settings
15
-
16
-
17
- class Connector(BaseSettings):
18
- url: str
19
- key: str
20
-
21
-
22
- def load_fallback_connector() -> Connector:
23
- url = "https://lamin-site-assets.s3.amazonaws.com/connector.env"
24
- connector_file, _ = urlretrieve(url)
25
- connector = Connector(_env_file=connector_file)
26
- return connector
27
-
28
-
29
- PROD_URL = "https://hub.lamin.ai"
30
- PROD_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImxhZXNhdW1tZHlkbGxwcGdmY2h1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTY4NDA1NTEsImV4cCI6MTk3MjQxNjU1MX0.WUeCRiun0ExUxKIv5-CtjF6878H8u26t0JmCWx3_2-c"
31
-
32
-
33
- class Environment:
34
- def __init__(self, fallback: bool = False):
35
- lamin_env = os.getenv("LAMIN_ENV")
36
- if lamin_env is None:
37
- lamin_env = "prod"
38
- # set public key
39
- if lamin_env == "prod":
40
- if not fallback:
41
- url = PROD_URL
42
- key = PROD_ANON_KEY
43
- else:
44
- connector = load_fallback_connector()
45
- url = connector.url
46
- key = connector.key
47
- elif lamin_env == "staging":
48
- url = "https://amvrvdwndlqdzgedrqdv.supabase.co"
49
- key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFtdnJ2ZHduZGxxZHpnZWRycWR2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2NzcxNTcxMzMsImV4cCI6MTk5MjczMzEzM30.Gelt3dQEi8tT4j-JA36RbaZuUvxRnczvRr3iyRtzjY0"
50
- elif lamin_env == "staging-test":
51
- url = "https://iugyyajllqftbpidapak.supabase.co"
52
- key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Iml1Z3l5YWpsbHFmdGJwaWRhcGFrIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTQyMjYyODMsImV4cCI6MjAwOTgwMjI4M30.s7B0gMogFhUatMSwlfuPJ95kWhdCZMn1ROhZ3t6Og90"
53
- elif lamin_env == "prod-test":
54
- url = "https://xtdacpwiqwpbxsatoyrv.supabase.co"
55
- key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inh0ZGFjcHdpcXdwYnhzYXRveXJ2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTQyMjYxNDIsImV4cCI6MjAwOTgwMjE0Mn0.Dbi27qujTt8Ei9gfp9KnEWTYptE5KUbZzEK6boL46k4"
56
- else:
57
- url = os.environ["SUPABASE_API_URL"]
58
- key = os.environ["SUPABASE_ANON_KEY"]
59
- self.lamin_env: str = lamin_env
60
- self.supabase_api_url: str = url
61
- self.supabase_anon_key: str = key
62
-
63
-
64
- DEFAULT_TIMEOUT = 20
65
-
66
-
67
- # runs ~0.5s
68
- def connect_hub(
69
- fallback_env: bool = False, client_options: ClientOptions | None = None
70
- ) -> Client:
71
- env = Environment(fallback=fallback_env)
72
- if client_options is None:
73
- client_options = ClientOptions(
74
- auto_refresh_token=False,
75
- function_client_timeout=DEFAULT_TIMEOUT,
76
- postgrest_client_timeout=DEFAULT_TIMEOUT,
77
- )
78
- client = create_client(env.supabase_api_url, env.supabase_anon_key, client_options)
79
- # needed to enable retries for http requests in supabase
80
- # these are separate clients and need separate transports
81
- # retries are done only in case an httpx.ConnectError or an httpx.ConnectTimeout occurs
82
- transport_kwargs = {"verify": True, "http2": True, "retries": 2}
83
- client.auth._http_client._transport = HTTPTransport(**transport_kwargs)
84
- client.functions._client._transport = HTTPTransport(**transport_kwargs)
85
- client.postgrest.session._transport = HTTPTransport(**transport_kwargs)
86
- return client
87
-
88
-
89
- def connect_hub_with_auth(
90
- fallback_env: bool = False,
91
- renew_token: bool = False,
92
- access_token: str | None = None,
93
- ) -> Client:
94
- hub = connect_hub(fallback_env=fallback_env)
95
- if access_token is None:
96
- from lamindb_setup import settings
97
-
98
- if renew_token:
99
- settings.user.access_token = get_access_token(
100
- settings.user.email, settings.user.password, settings.user.api_key
101
- )
102
- access_token = settings.user.access_token
103
- hub.postgrest.auth(access_token)
104
- hub.functions.set_auth(access_token)
105
- return hub
106
-
107
-
108
- # runs ~0.5s
109
- def get_access_token(
110
- email: str | None = None, password: str | None = None, api_key: str | None = None
111
- ):
112
- hub = connect_hub()
113
- try:
114
- if api_key is not None:
115
- auth_response = hub.functions.invoke(
116
- "get-jwt-v1",
117
- invoke_options={"body": {"api_key": api_key}},
118
- )
119
- return json.loads(auth_response)["accessToken"]
120
- auth_response = hub.auth.sign_in_with_password(
121
- {
122
- "email": email,
123
- "password": password,
124
- }
125
- )
126
- return auth_response.session.access_token
127
- finally:
128
- hub.auth.sign_out(options={"scope": "local"})
129
-
130
-
131
- def call_with_fallback_auth(
132
- callable,
133
- **kwargs,
134
- ):
135
- access_token = kwargs.pop("access_token", None)
136
-
137
- if access_token is not None:
138
- try:
139
- client = connect_hub_with_auth(access_token=access_token)
140
- result = callable(**kwargs, client=client)
141
- finally:
142
- try:
143
- client.auth.sign_out(options={"scope": "local"})
144
- except NameError:
145
- pass
146
- return result
147
-
148
- for renew_token, fallback_env in [(False, False), (True, False), (False, True)]:
149
- try:
150
- client = connect_hub_with_auth(
151
- renew_token=renew_token, fallback_env=fallback_env
152
- )
153
- result = callable(**kwargs, client=client)
154
- # we update access_token here
155
- # because at this point the call has been successfully resolved
156
- if renew_token:
157
- from lamindb_setup import settings
158
-
159
- # here settings.user contains an updated access_token
160
- save_user_settings(settings.user)
161
- break
162
- # we use Exception here as the ways in which the client fails upon 401
163
- # are not consistent and keep changing
164
- # because we ultimately raise the error, it's OK I'd say
165
- except Exception as e:
166
- if fallback_env:
167
- raise e
168
- finally:
169
- try:
170
- client.auth.sign_out(options={"scope": "local"})
171
- except NameError:
172
- pass
173
- return result
174
-
175
-
176
- def call_with_fallback(
177
- callable,
178
- **kwargs,
179
- ):
180
- for fallback_env in [False, True]:
181
- try:
182
- client = connect_hub(fallback_env=fallback_env)
183
- result = callable(**kwargs, client=client)
184
- break
185
- except Exception as e:
186
- if fallback_env:
187
- raise e
188
- finally:
189
- try:
190
- # in case there was sign in
191
- client.auth.sign_out(options={"scope": "local"})
192
- except NameError:
193
- pass
194
- return result
195
-
196
-
197
- def requests_client():
198
- # local is used in tests
199
- if os.environ.get("LAMIN_ENV", "prod") == "local":
200
- from fastapi.testclient import TestClient
201
- from laminhub_rest.main import app
202
-
203
- return TestClient(app)
204
-
205
- import requests # type: ignore
206
-
207
- return requests
208
-
209
-
210
- def request_with_auth(
211
- url: str,
212
- method: Literal["get", "post", "put", "delete", "head", "options"],
213
- access_token: str,
214
- renew_token: bool = True,
215
- **kwargs,
216
- ):
217
- requests = requests_client()
218
-
219
- headers = kwargs.pop("headers", {})
220
- headers["Authorization"] = f"Bearer {access_token}"
221
-
222
- make_request = getattr(requests, method)
223
- timeout = kwargs.pop("timeout", DEFAULT_TIMEOUT)
224
-
225
- response = make_request(url, headers=headers, timeout=timeout, **kwargs)
226
- status_code = response.status_code
227
- # update access_token and try again if failed
228
- if not (200 <= status_code < 300) and renew_token:
229
- from lamindb_setup import settings
230
-
231
- logger.debug(f"{method} {url} failed: {status_code} {response.text}")
232
-
233
- access_token = get_access_token(
234
- settings.user.email, settings.user.password, settings.user.api_key
235
- )
236
-
237
- settings.user.access_token = access_token
238
- save_user_settings(settings.user)
239
-
240
- headers["Authorization"] = f"Bearer {access_token}"
241
-
242
- response = make_request(url, headers=headers, timeout=timeout, **kwargs)
243
- return response
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ from typing import Literal
6
+ from urllib.request import urlretrieve
7
+
8
+ from httpx import HTTPTransport
9
+ from lamin_utils import logger
10
+ from pydantic_settings import BaseSettings
11
+ from supabase import Client, create_client # type: ignore
12
+ from supabase.lib.client_options import ClientOptions
13
+
14
+ from ._settings_save import save_user_settings
15
+
16
+
17
+ class Connector(BaseSettings):
18
+ url: str
19
+ key: str
20
+
21
+
22
+ def load_fallback_connector() -> Connector:
23
+ url = "https://lamin-site-assets.s3.amazonaws.com/connector.env"
24
+ connector_file, _ = urlretrieve(url)
25
+ connector = Connector(_env_file=connector_file)
26
+ return connector
27
+
28
+
29
+ PROD_URL = "https://hub.lamin.ai"
30
+ PROD_ANON_KEY = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImxhZXNhdW1tZHlkbGxwcGdmY2h1Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTY4NDA1NTEsImV4cCI6MTk3MjQxNjU1MX0.WUeCRiun0ExUxKIv5-CtjF6878H8u26t0JmCWx3_2-c"
31
+
32
+
33
+ class Environment:
34
+ def __init__(self, fallback: bool = False):
35
+ lamin_env = os.getenv("LAMIN_ENV")
36
+ if lamin_env is None:
37
+ lamin_env = "prod"
38
+ # set public key
39
+ if lamin_env == "prod":
40
+ if not fallback:
41
+ url = PROD_URL
42
+ key = PROD_ANON_KEY
43
+ else:
44
+ connector = load_fallback_connector()
45
+ url = connector.url
46
+ key = connector.key
47
+ elif lamin_env == "staging":
48
+ url = "https://amvrvdwndlqdzgedrqdv.supabase.co"
49
+ key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImFtdnJ2ZHduZGxxZHpnZWRycWR2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2NzcxNTcxMzMsImV4cCI6MTk5MjczMzEzM30.Gelt3dQEi8tT4j-JA36RbaZuUvxRnczvRr3iyRtzjY0"
50
+ elif lamin_env == "staging-test":
51
+ url = "https://iugyyajllqftbpidapak.supabase.co"
52
+ key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Iml1Z3l5YWpsbHFmdGJwaWRhcGFrIiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTQyMjYyODMsImV4cCI6MjAwOTgwMjI4M30.s7B0gMogFhUatMSwlfuPJ95kWhdCZMn1ROhZ3t6Og90"
53
+ elif lamin_env == "prod-test":
54
+ url = "https://xtdacpwiqwpbxsatoyrv.supabase.co"
55
+ key = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inh0ZGFjcHdpcXdwYnhzYXRveXJ2Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2OTQyMjYxNDIsImV4cCI6MjAwOTgwMjE0Mn0.Dbi27qujTt8Ei9gfp9KnEWTYptE5KUbZzEK6boL46k4"
56
+ else:
57
+ url = os.environ["SUPABASE_API_URL"]
58
+ key = os.environ["SUPABASE_ANON_KEY"]
59
+ self.lamin_env: str = lamin_env
60
+ self.supabase_api_url: str = url
61
+ self.supabase_anon_key: str = key
62
+
63
+
64
+ DEFAULT_TIMEOUT = 20
65
+
66
+
67
+ # runs ~0.5s
68
+ def connect_hub(
69
+ fallback_env: bool = False, client_options: ClientOptions | None = None
70
+ ) -> Client:
71
+ env = Environment(fallback=fallback_env)
72
+ if client_options is None:
73
+ client_options = ClientOptions(
74
+ auto_refresh_token=False,
75
+ function_client_timeout=DEFAULT_TIMEOUT,
76
+ postgrest_client_timeout=DEFAULT_TIMEOUT,
77
+ )
78
+ client = create_client(env.supabase_api_url, env.supabase_anon_key, client_options)
79
+ # needed to enable retries for http requests in supabase
80
+ # these are separate clients and need separate transports
81
+ # retries are done only in case an httpx.ConnectError or an httpx.ConnectTimeout occurs
82
+ transport_kwargs = {"verify": True, "http2": True, "retries": 2}
83
+ client.auth._http_client._transport = HTTPTransport(**transport_kwargs)
84
+ client.functions._client._transport = HTTPTransport(**transport_kwargs)
85
+ client.postgrest.session._transport = HTTPTransport(**transport_kwargs)
86
+ return client
87
+
88
+
89
+ def connect_hub_with_auth(
90
+ fallback_env: bool = False,
91
+ renew_token: bool = False,
92
+ access_token: str | None = None,
93
+ ) -> Client:
94
+ hub = connect_hub(fallback_env=fallback_env)
95
+ if access_token is None:
96
+ from lamindb_setup import settings
97
+
98
+ if renew_token:
99
+ settings.user.access_token = get_access_token(
100
+ settings.user.email, settings.user.password, settings.user.api_key
101
+ )
102
+ access_token = settings.user.access_token
103
+ hub.postgrest.auth(access_token)
104
+ hub.functions.set_auth(access_token)
105
+ return hub
106
+
107
+
108
+ # runs ~0.5s
109
+ def get_access_token(
110
+ email: str | None = None, password: str | None = None, api_key: str | None = None
111
+ ):
112
+ hub = connect_hub()
113
+ try:
114
+ if api_key is not None:
115
+ auth_response = hub.functions.invoke(
116
+ "get-jwt-v1",
117
+ invoke_options={"body": {"api_key": api_key}},
118
+ )
119
+ return json.loads(auth_response)["accessToken"]
120
+ auth_response = hub.auth.sign_in_with_password(
121
+ {
122
+ "email": email,
123
+ "password": password,
124
+ }
125
+ )
126
+ return auth_response.session.access_token
127
+ except Exception as e:
128
+ # we need to log the problem here because the exception is usually caught outside
129
+ # in call_with_fallback_auth
130
+ logger.warning(f"failed to update your lamindb access token: {e}")
131
+ raise e
132
+ finally:
133
+ hub.auth.sign_out(options={"scope": "local"})
134
+
135
+
136
+ def call_with_fallback_auth(
137
+ callable,
138
+ **kwargs,
139
+ ):
140
+ access_token = kwargs.pop("access_token", None)
141
+
142
+ if access_token is not None:
143
+ try:
144
+ client = connect_hub_with_auth(access_token=access_token)
145
+ result = callable(**kwargs, client=client)
146
+ finally:
147
+ try:
148
+ client.auth.sign_out(options={"scope": "local"})
149
+ except NameError:
150
+ pass
151
+ return result
152
+
153
+ for renew_token, fallback_env in [(False, False), (True, False), (False, True)]:
154
+ try:
155
+ client = connect_hub_with_auth(
156
+ renew_token=renew_token, fallback_env=fallback_env
157
+ )
158
+ result = callable(**kwargs, client=client)
159
+ # we update access_token here
160
+ # because at this point the call has been successfully resolved
161
+ if renew_token:
162
+ from lamindb_setup import settings
163
+
164
+ # here settings.user contains an updated access_token
165
+ save_user_settings(settings.user)
166
+ break
167
+ # we use Exception here as the ways in which the client fails upon 401
168
+ # are not consistent and keep changing
169
+ # because we ultimately raise the error, it's OK I'd say
170
+ except Exception as e:
171
+ if fallback_env:
172
+ raise e
173
+ finally:
174
+ try:
175
+ client.auth.sign_out(options={"scope": "local"})
176
+ except NameError:
177
+ pass
178
+ return result
179
+
180
+
181
+ def call_with_fallback(
182
+ callable,
183
+ **kwargs,
184
+ ):
185
+ for fallback_env in [False, True]:
186
+ try:
187
+ client = connect_hub(fallback_env=fallback_env)
188
+ result = callable(**kwargs, client=client)
189
+ break
190
+ except Exception as e:
191
+ if fallback_env:
192
+ raise e
193
+ finally:
194
+ try:
195
+ # in case there was sign in
196
+ client.auth.sign_out(options={"scope": "local"})
197
+ except NameError:
198
+ pass
199
+ return result
200
+
201
+
202
+ def requests_client():
203
+ # local is used in tests
204
+ if os.environ.get("LAMIN_ENV", "prod") == "local":
205
+ from fastapi.testclient import TestClient
206
+ from laminhub_rest.main import app
207
+
208
+ return TestClient(app)
209
+
210
+ import requests # type: ignore
211
+
212
+ return requests
213
+
214
+
215
+ def request_with_auth(
216
+ url: str,
217
+ method: Literal["get", "post", "put", "delete", "head", "options"],
218
+ access_token: str,
219
+ renew_token: bool = True,
220
+ **kwargs,
221
+ ):
222
+ requests = requests_client()
223
+
224
+ headers = kwargs.pop("headers", {})
225
+ headers["Authorization"] = f"Bearer {access_token}"
226
+
227
+ make_request = getattr(requests, method)
228
+ timeout = kwargs.pop("timeout", DEFAULT_TIMEOUT)
229
+
230
+ response = make_request(url, headers=headers, timeout=timeout, **kwargs)
231
+ status_code = response.status_code
232
+ # update access_token and try again if failed
233
+ if not (200 <= status_code < 300) and renew_token:
234
+ from lamindb_setup import settings
235
+
236
+ logger.debug(f"{method} {url} failed: {status_code} {response.text}")
237
+
238
+ access_token = get_access_token(
239
+ settings.user.email, settings.user.password, settings.user.api_key
240
+ )
241
+
242
+ settings.user.access_token = access_token
243
+ save_user_settings(settings.user)
244
+
245
+ headers["Authorization"] = f"Bearer {access_token}"
246
+
247
+ response = make_request(url, headers=headers, timeout=timeout, **kwargs)
248
+ return response