lamindb_setup 1.5.0__py3-none-any.whl → 1.5.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.
- lamindb_setup/__init__.py +1 -1
- lamindb_setup/_schema_metadata.py +13 -2
- lamindb_setup/core/_settings_user.py +1 -1
- lamindb_setup/core/django.py +52 -35
- lamindb_setup/core/upath.py +15 -0
- {lamindb_setup-1.5.0.dist-info → lamindb_setup-1.5.2.dist-info}/METADATA +3 -3
- {lamindb_setup-1.5.0.dist-info → lamindb_setup-1.5.2.dist-info}/RECORD +9 -9
- {lamindb_setup-1.5.0.dist-info → lamindb_setup-1.5.2.dist-info}/LICENSE +0 -0
- {lamindb_setup-1.5.0.dist-info → lamindb_setup-1.5.2.dist-info}/WHEEL +0 -0
lamindb_setup/__init__.py
CHANGED
|
@@ -150,6 +150,7 @@ class FieldMetadata(BaseModel):
|
|
|
150
150
|
is_link_table: bool
|
|
151
151
|
is_primary_key: bool
|
|
152
152
|
is_editable: bool
|
|
153
|
+
max_length: int | None = None
|
|
153
154
|
relation_type: RelationType | None = None
|
|
154
155
|
related_field_name: str | None = None
|
|
155
156
|
related_model_name: str | None = None
|
|
@@ -168,6 +169,10 @@ class _ModelHandler:
|
|
|
168
169
|
self.included_modules = included_modules
|
|
169
170
|
self.fields = self._get_fields_metadata(self.model)
|
|
170
171
|
self.is_link_table = issubclass(model, LinkORM)
|
|
172
|
+
self.name_field = model._name_field if hasattr(model, "_name_field") else None
|
|
173
|
+
self.ontology_id_field = (
|
|
174
|
+
model._ontology_id_field if hasattr(model, "_ontology_id_field") else None
|
|
175
|
+
)
|
|
171
176
|
|
|
172
177
|
def to_dict(self, include_django_objects: bool = True):
|
|
173
178
|
_dict = {
|
|
@@ -175,6 +180,8 @@ class _ModelHandler:
|
|
|
175
180
|
"class_name": self.class_name,
|
|
176
181
|
"table_name": self.table_name,
|
|
177
182
|
"is_link_table": self.is_link_table,
|
|
183
|
+
"name_field": self.name_field,
|
|
184
|
+
"ontology_id_field": self.ontology_id_field,
|
|
178
185
|
}
|
|
179
186
|
|
|
180
187
|
for field_name in self.fields.keys():
|
|
@@ -243,18 +250,21 @@ class _ModelHandler:
|
|
|
243
250
|
internal_type = field.get_internal_type()
|
|
244
251
|
model_name = field.model._meta.model_name
|
|
245
252
|
relation_type = self._get_relation_type(model, field)
|
|
253
|
+
|
|
254
|
+
schema_name = field.model.__get_module_name__()
|
|
255
|
+
|
|
246
256
|
if field.related_model is None:
|
|
247
|
-
schema_name = field.model.__get_module_name__()
|
|
248
257
|
related_model_name = None
|
|
249
258
|
related_schema_name = None
|
|
250
259
|
related_field_name = None
|
|
251
260
|
is_editable = field.editable
|
|
261
|
+
max_length = field.max_length
|
|
252
262
|
else:
|
|
253
263
|
related_model_name = field.related_model._meta.model_name
|
|
254
264
|
related_schema_name = field.related_model.__get_module_name__()
|
|
255
|
-
schema_name = field.model.__get_module_name__()
|
|
256
265
|
related_field_name = field.remote_field.name
|
|
257
266
|
is_editable = False
|
|
267
|
+
max_length = None
|
|
258
268
|
|
|
259
269
|
field_name = field.name
|
|
260
270
|
is_primary_key = getattr(field, "primary_key", False)
|
|
@@ -289,6 +299,7 @@ class _ModelHandler:
|
|
|
289
299
|
is_link_table=issubclass(field.model, LinkORM),
|
|
290
300
|
is_primary_key=is_primary_key,
|
|
291
301
|
is_editable=is_editable,
|
|
302
|
+
max_length=max_length,
|
|
292
303
|
column_name=column,
|
|
293
304
|
relation_type=relation_type,
|
|
294
305
|
related_schema_name=related_schema_name
|
lamindb_setup/core/django.py
CHANGED
|
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|
|
3
3
|
# flake8: noqa
|
|
4
4
|
import builtins
|
|
5
5
|
import os
|
|
6
|
+
import jwt
|
|
7
|
+
import time
|
|
6
8
|
from pathlib import Path
|
|
7
9
|
import time
|
|
8
10
|
from ._settings_instance import InstanceSettings
|
|
@@ -14,15 +16,47 @@ IS_MIGRATING = False
|
|
|
14
16
|
CONN_MAX_AGE = 299
|
|
15
17
|
|
|
16
18
|
|
|
19
|
+
# db token that refreshes on access if needed
|
|
20
|
+
class DBToken:
|
|
21
|
+
def __init__(
|
|
22
|
+
self, instance: InstanceSettings | dict, access_token: str | None = None
|
|
23
|
+
):
|
|
24
|
+
self.instance = instance
|
|
25
|
+
self.access_token = access_token
|
|
26
|
+
# initialized in token_query
|
|
27
|
+
self._token: str | None = None
|
|
28
|
+
self._token_query: str | None = None
|
|
29
|
+
self._expiration: float
|
|
30
|
+
|
|
31
|
+
def _refresh_token(self):
|
|
32
|
+
from ._hub_core import access_db
|
|
33
|
+
from psycopg2.extensions import adapt
|
|
34
|
+
|
|
35
|
+
self._token = access_db(self.instance, self.access_token)
|
|
36
|
+
self._token_query = (
|
|
37
|
+
f"SELECT set_token({adapt(self._token).getquoted().decode()}, true);"
|
|
38
|
+
)
|
|
39
|
+
self._expiration = jwt.decode(self._token, options={"verify_signature": False})[
|
|
40
|
+
"exp"
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def token_query(self) -> str:
|
|
45
|
+
# refresh token if needed
|
|
46
|
+
if self._token is None or time.time() >= self._expiration:
|
|
47
|
+
self._refresh_token()
|
|
48
|
+
|
|
49
|
+
return self._token_query # type: ignore
|
|
50
|
+
|
|
51
|
+
|
|
17
52
|
# a class to manage jwt in dbs
|
|
18
53
|
class DBTokenManager:
|
|
19
|
-
def __init__(self
|
|
54
|
+
def __init__(self):
|
|
20
55
|
from django.db.transaction import Atomic
|
|
21
56
|
|
|
22
|
-
self.debug = debug
|
|
23
57
|
self.original_atomic_enter = Atomic.__enter__
|
|
24
58
|
|
|
25
|
-
self.tokens: dict[str,
|
|
59
|
+
self.tokens: dict[str, DBToken] = {}
|
|
26
60
|
|
|
27
61
|
def get_connection(self, connection_name: str):
|
|
28
62
|
from django.db import connections
|
|
@@ -32,19 +66,11 @@ class DBTokenManager:
|
|
|
32
66
|
|
|
33
67
|
return connection
|
|
34
68
|
|
|
35
|
-
def set(self, token:
|
|
69
|
+
def set(self, token: DBToken, connection_name: str = "default"):
|
|
36
70
|
from django.db.transaction import Atomic
|
|
37
71
|
|
|
38
|
-
# no adapt in psycopg3
|
|
39
|
-
from psycopg2.extensions import adapt
|
|
40
|
-
|
|
41
72
|
connection = self.get_connection(connection_name)
|
|
42
73
|
|
|
43
|
-
# escape correctly to avoid wrangling with params
|
|
44
|
-
set_token_query = (
|
|
45
|
-
f"SELECT set_token({adapt(token).getquoted().decode()}, true); "
|
|
46
|
-
)
|
|
47
|
-
|
|
48
74
|
def set_token_wrapper(execute, sql, params, many, context):
|
|
49
75
|
not_in_atomic_block = (
|
|
50
76
|
context is None
|
|
@@ -53,12 +79,7 @@ class DBTokenManager:
|
|
|
53
79
|
)
|
|
54
80
|
# ignore atomic blocks
|
|
55
81
|
if not_in_atomic_block:
|
|
56
|
-
sql =
|
|
57
|
-
elif self.debug:
|
|
58
|
-
print("--in atomic block--")
|
|
59
|
-
|
|
60
|
-
if self.debug:
|
|
61
|
-
print(sql)
|
|
82
|
+
sql = token.token_query + sql
|
|
62
83
|
result = execute(sql, params, many, context)
|
|
63
84
|
# this ensures that psycopg3 in the current env doesn't break this wrapper
|
|
64
85
|
# psycopg3 returns a cursor
|
|
@@ -69,30 +90,29 @@ class DBTokenManager:
|
|
|
69
90
|
and result is not None
|
|
70
91
|
and hasattr(result, "nextset")
|
|
71
92
|
):
|
|
72
|
-
if self.debug:
|
|
73
|
-
print("(shift cursor)")
|
|
74
93
|
result.nextset()
|
|
75
94
|
return result
|
|
76
95
|
|
|
77
96
|
connection.execute_wrappers.append(set_token_wrapper)
|
|
78
97
|
|
|
98
|
+
self.tokens[connection_name] = token
|
|
99
|
+
|
|
79
100
|
# ensure we set the token only once for an outer atomic block
|
|
80
101
|
def __enter__(atomic):
|
|
81
102
|
self.original_atomic_enter(atomic)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
103
|
+
connection_name = "default" if atomic.using is None else atomic.using
|
|
104
|
+
if connection_name in self.tokens:
|
|
105
|
+
# here we don't use the connection from the closure
|
|
106
|
+
# because Atomic is a single class to manage transactions for all connections
|
|
107
|
+
connection = self.get_connection(connection_name)
|
|
108
|
+
if len(connection.atomic_blocks) == 1:
|
|
109
|
+
token = self.tokens[connection_name]
|
|
110
|
+
# use raw psycopg2 connection here
|
|
111
|
+
# atomic block ensures connection
|
|
112
|
+
connection.connection.cursor().execute(token.token_query)
|
|
91
113
|
|
|
92
114
|
Atomic.__enter__ = __enter__
|
|
93
115
|
|
|
94
|
-
self.tokens[connection_name] = token
|
|
95
|
-
|
|
96
116
|
def reset(self, connection_name: str = "default"):
|
|
97
117
|
from django.db.transaction import Atomic
|
|
98
118
|
|
|
@@ -103,7 +123,6 @@ class DBTokenManager:
|
|
|
103
123
|
for w in connection.execute_wrappers
|
|
104
124
|
if getattr(w, "__name__", None) != "set_token_wrapper"
|
|
105
125
|
]
|
|
106
|
-
Atomic.__enter__ = self.original_atomic_enter
|
|
107
126
|
|
|
108
127
|
self.tokens.pop(connection_name, None)
|
|
109
128
|
|
|
@@ -198,9 +217,7 @@ def setup_django(
|
|
|
198
217
|
BaseDatabaseWrapper.close_if_health_check_failed = close_if_health_check_failed
|
|
199
218
|
|
|
200
219
|
if isettings._fine_grained_access and isettings._db_permissions == "jwt":
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
db_token = access_db(isettings)
|
|
220
|
+
db_token = DBToken(isettings)
|
|
204
221
|
db_token_manager.set(db_token) # sets for the default connection
|
|
205
222
|
|
|
206
223
|
if configure_only:
|
lamindb_setup/core/upath.py
CHANGED
|
@@ -51,6 +51,21 @@ VALID_SIMPLE_SUFFIXES = {
|
|
|
51
51
|
".xml",
|
|
52
52
|
".qs", # https://cran.r-project.org/web/packages/qs/vignettes/vignette.html
|
|
53
53
|
".rds",
|
|
54
|
+
".pt",
|
|
55
|
+
".pth",
|
|
56
|
+
".ckpt",
|
|
57
|
+
".state_dict",
|
|
58
|
+
".keras",
|
|
59
|
+
".pb",
|
|
60
|
+
".pbtxt",
|
|
61
|
+
".savedmodel",
|
|
62
|
+
".pkl",
|
|
63
|
+
".pickle",
|
|
64
|
+
".bin",
|
|
65
|
+
".safetensors",
|
|
66
|
+
".model",
|
|
67
|
+
".mlmodel",
|
|
68
|
+
".mar",
|
|
54
69
|
#
|
|
55
70
|
# with readers (see below)
|
|
56
71
|
#
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: lamindb_setup
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.2
|
|
4
4
|
Summary: Setup & configure LaminDB.
|
|
5
5
|
Author-email: Lamin Labs <open-source@lamin.ai>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -13,8 +13,8 @@ Requires-Dist: appdirs<2.0.0
|
|
|
13
13
|
Requires-Dist: requests
|
|
14
14
|
Requires-Dist: universal_pathlib==0.2.6
|
|
15
15
|
Requires-Dist: botocore<2.0.0
|
|
16
|
-
Requires-Dist: supabase>=2.8.1
|
|
17
|
-
Requires-Dist: gotrue
|
|
16
|
+
Requires-Dist: supabase>=2.8.1,<=2.15.0
|
|
17
|
+
Requires-Dist: gotrue<=2.12.0
|
|
18
18
|
Requires-Dist: storage3!=0.11.2; python_version < '3.11'
|
|
19
19
|
Requires-Dist: pyjwt<3.0.0
|
|
20
20
|
Requires-Dist: psutil
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
lamindb_setup/__init__.py,sha256=
|
|
1
|
+
lamindb_setup/__init__.py,sha256=FWTWZQC537S1pBQ8gLeqbyA-GkCqstvtPrSFUKpx7sw,2754
|
|
2
2
|
lamindb_setup/_cache.py,sha256=ixasm_9pUFy-ztbhbqJRVP88uTbFclL60MwUUvZhMFs,1509
|
|
3
3
|
lamindb_setup/_check.py,sha256=28PcG8Kp6OpjSLSi1r2boL2Ryeh6xkaCL87HFbjs6GA,129
|
|
4
4
|
lamindb_setup/_check_setup.py,sha256=uveV6CGiwm9M5OMe3lxfAMDs5SU7j1EogJsQB03ZaRw,5928
|
|
@@ -13,7 +13,7 @@ lamindb_setup/_init_instance.py,sha256=5RBv2X18SfnIrciHljaoVsFF25te2P7KwHx0Ww87H
|
|
|
13
13
|
lamindb_setup/_migrate.py,sha256=ya-15sc91i4JmEWI4j00T2892x8hdy2fSW-qz4IdxLs,9739
|
|
14
14
|
lamindb_setup/_register_instance.py,sha256=X7ZGlCVOZKq4zTpi3bxML4jzo6hgN9UYmdTxxf6JLmc,1205
|
|
15
15
|
lamindb_setup/_schema.py,sha256=b3uzhhWpV5mQtDwhMINc2MabGCnGLESy51ito3yl6Wc,679
|
|
16
|
-
lamindb_setup/_schema_metadata.py,sha256=
|
|
16
|
+
lamindb_setup/_schema_metadata.py,sha256=WGZg2H5h-bwoJ3ypwh98Jc-VDYU9LCSU1i-PoWmn3Sw,14756
|
|
17
17
|
lamindb_setup/_set_managed_storage.py,sha256=qC3ACD_PWG-MrzcS3fQpjDEOuxAaJBgPqCU_bDvqtXo,2043
|
|
18
18
|
lamindb_setup/_setup_user.py,sha256=8BSGsW5jfmB4FlkhMt5osYXBbVCdOQeAVATb-oAYxa0,4495
|
|
19
19
|
lamindb_setup/_silence_loggers.py,sha256=AKF_YcHvX32eGXdsYK8MJlxEaZ-Uo2f6QDRzjKFCtws,1568
|
|
@@ -33,15 +33,15 @@ lamindb_setup/core/_settings_load.py,sha256=adVwwEiwglrNNpZFgoP-EENZkzxZvKOzUr3z
|
|
|
33
33
|
lamindb_setup/core/_settings_save.py,sha256=P04ZnWFSN4Qq_QFWXNvJDs4yxrY9CjQBol_BDku_JEw,3227
|
|
34
34
|
lamindb_setup/core/_settings_storage.py,sha256=op31t12T_fCfTG8OSfnXnIxB9VCQPg8Oo2cnZHVap8Y,14203
|
|
35
35
|
lamindb_setup/core/_settings_store.py,sha256=zyybc6fJXJcFNTjBrgtgbPhriInuhpmQKNoGmy8ScFA,2298
|
|
36
|
-
lamindb_setup/core/_settings_user.py,sha256=
|
|
36
|
+
lamindb_setup/core/_settings_user.py,sha256=5hmnMu6fxrHAcwBEtIL0P9N8V4B0SjhzIdqFQ9o3Tsg,1476
|
|
37
37
|
lamindb_setup/core/_setup_bionty_sources.py,sha256=ox3X-SHiHa2lNPSWjwZhINypbLacX6kGwH6hVVrSFZc,1505
|
|
38
38
|
lamindb_setup/core/cloud_sqlite_locker.py,sha256=i6TrT7HG0lqliPvZTlsZ_uplPaqhPBbabyfeR32SkA8,7107
|
|
39
|
-
lamindb_setup/core/django.py,sha256=
|
|
39
|
+
lamindb_setup/core/django.py,sha256=qOh71aBjBsrksDq4AGEP3LS2V5hKOh6MhCIY1Sudeos,8084
|
|
40
40
|
lamindb_setup/core/exceptions.py,sha256=4NpLUNUIfXYVTFX2FvLZF8RW34exk2Vn2X3G4YhnTRg,276
|
|
41
41
|
lamindb_setup/core/hashing.py,sha256=M3Q1-ywnqh4Uy5zojbQfLju19HU0ySp8Oi7FGIJXfFI,3667
|
|
42
42
|
lamindb_setup/core/types.py,sha256=zJii2le38BJUmsNVvzDrbzGYr0yaeb-9Rw9IKmsBr3k,523
|
|
43
|
-
lamindb_setup/core/upath.py,sha256=
|
|
44
|
-
lamindb_setup-1.5.
|
|
45
|
-
lamindb_setup-1.5.
|
|
46
|
-
lamindb_setup-1.5.
|
|
47
|
-
lamindb_setup-1.5.
|
|
43
|
+
lamindb_setup/core/upath.py,sha256=U5CBiHVoEBEUi-YzYd0G8wMONkO-wcXQQ9htfDWbw-s,33876
|
|
44
|
+
lamindb_setup-1.5.2.dist-info/LICENSE,sha256=UOZ1F5fFDe3XXvG4oNnkL1-Ecun7zpHzRxjp-XsMeAo,11324
|
|
45
|
+
lamindb_setup-1.5.2.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82
|
|
46
|
+
lamindb_setup-1.5.2.dist-info/METADATA,sha256=ezs2jSr-kFuLaNsm2MOGjVJ6768Pvxg6c_46nytI3Kk,1792
|
|
47
|
+
lamindb_setup-1.5.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|