lamindb_setup 1.9.0__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 -266
  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 -223
  15. lamindb_setup/core/_hub_client.py +248 -248
  16. lamindb_setup/core/_hub_core.py +665 -665
  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 -377
  20. lamindb_setup/core/_settings_instance.py +569 -569
  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 -296
  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 -1013
  33. lamindb_setup/errors.py +70 -70
  34. lamindb_setup/types.py +20 -20
  35. {lamindb_setup-1.9.0.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.9.0.dist-info/RECORD +0 -50
  38. {lamindb_setup-1.9.0.dist-info → lamindb_setup-1.9.1.dist-info}/LICENSE +0 -0
  39. {lamindb_setup-1.9.0.dist-info → lamindb_setup-1.9.1.dist-info}/WHEEL +0 -0
@@ -1,248 +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
- 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
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