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,227 +1,227 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING
4
- from uuid import UUID, uuid4
5
-
6
- from lamin_utils import logger
7
- from supabase.client import Client # noqa
8
-
9
-
10
- def select_instance_by_owner_name(
11
- owner: str,
12
- name: str,
13
- client: Client,
14
- ) -> dict | None:
15
- # this won't find an instance without the default storage
16
- data = (
17
- client.table("instance")
18
- .select(
19
- "*, account!inner!instance_account_id_28936e8f_fk_account_id(*),"
20
- " storage!inner!storage_instance_id_359fca71_fk_instance_id(*)"
21
- )
22
- .eq("name", name)
23
- .eq("account.handle", owner)
24
- .eq("storage.is_default", True)
25
- .execute()
26
- .data
27
- )
28
- if len(data) == 0:
29
- return None
30
- result = data[0]
31
- # this is a list
32
- # assume only one default storage
33
- result["storage"] = result["storage"][0]
34
- return result
35
-
36
-
37
- # --------------- ACCOUNT ----------------------
38
- def select_account_by_handle(
39
- handle: str,
40
- client: Client,
41
- ):
42
- data = client.table("account").select("*").eq("handle", handle).execute().data
43
- if len(data) == 0:
44
- return None
45
- return data[0]
46
-
47
-
48
- def select_account_handle_name_by_lnid(lnid: str, client: Client):
49
- data = (
50
- client.table("account").select("handle, name").eq("lnid", lnid).execute().data
51
- )
52
- if not data:
53
- return None
54
- return data[0]
55
-
56
-
57
- # --------------- INSTANCE ----------------------
58
- def select_instance_by_name(
59
- account_id: str,
60
- name: str,
61
- client: Client,
62
- ):
63
- data = (
64
- client.table("instance")
65
- .select("*")
66
- .eq("account_id", account_id)
67
- .eq("name", name)
68
- .execute()
69
- .data
70
- )
71
- if len(data) != 0:
72
- return data[0]
73
-
74
- data = (
75
- client.table("instance_previous_name")
76
- .select(
77
- "instance!instance_previous_name_instance_id_17ac5d61_fk_instance_id(*)"
78
- )
79
- .eq("instance.account_id", account_id)
80
- .eq("previous_name", name)
81
- .execute()
82
- .data
83
- )
84
- if len(data) != 0:
85
- return data[0]["instance"]
86
-
87
- return None
88
-
89
-
90
- def select_instance_by_id(
91
- instance_id: str,
92
- client: Client,
93
- ):
94
- response = client.table("instance").select("*").eq("id", instance_id).execute()
95
- if len(response.data) == 0:
96
- return None
97
- return response.data[0]
98
-
99
-
100
- def select_instance_by_id_with_storage(
101
- instance_id: str,
102
- client: Client,
103
- ):
104
- # this won't find an instance without the default storage
105
- data = (
106
- client.table("instance")
107
- .select("*, storage!inner!storage_instance_id_359fca71_fk_instance_id(*)")
108
- .eq("id", instance_id)
109
- .eq("storage.is_default", True)
110
- .execute()
111
- .data
112
- )
113
- if len(data) == 0:
114
- return None
115
- result = data[0]
116
- # this is a list
117
- # assume only one default storage
118
- result["storage"] = result["storage"][0]
119
- return result
120
-
121
-
122
- def update_instance(instance_id: str, instance_fields: dict, client: Client):
123
- response = (
124
- client.table("instance").update(instance_fields).eq("id", instance_id).execute()
125
- )
126
- if len(response.data) == 0:
127
- raise PermissionError(
128
- f"Update of instance with {instance_id} was not successful. Probably, you"
129
- " don't have sufficient permissions."
130
- )
131
- return response.data[0]
132
-
133
-
134
- # --------------- COLLABORATOR ----------------------
135
-
136
-
137
- def select_collaborator(
138
- instance_id: str,
139
- account_id: str,
140
- client: Client,
141
- ):
142
- data = (
143
- client.table("account_instance")
144
- .select("*")
145
- .eq("instance_id", instance_id)
146
- .eq("account_id", account_id)
147
- .execute()
148
- .data
149
- )
150
- if len(data) == 0:
151
- return None
152
- return data[0]
153
-
154
-
155
- # --------------- STORAGE ----------------------
156
-
157
-
158
- def select_default_storage_by_instance_id(
159
- instance_id: str, client: Client
160
- ) -> dict | None:
161
- data = (
162
- client.table("storage")
163
- .select("*")
164
- .eq("instance_id", instance_id)
165
- .eq("is_default", True)
166
- .execute()
167
- .data
168
- )
169
- if len(data) == 0:
170
- return None
171
- return data[0]
172
-
173
-
174
- # --------------- DBUser ----------------------
175
-
176
-
177
- def insert_db_user(
178
- *,
179
- name: str,
180
- db_user_name: str,
181
- db_user_password: str,
182
- instance_id: UUID,
183
- client: Client,
184
- ) -> None:
185
- fields = (
186
- {
187
- "id": uuid4().hex,
188
- "instance_id": instance_id.hex,
189
- "name": name,
190
- "db_user_name": db_user_name,
191
- "db_user_password": db_user_password,
192
- },
193
- )
194
- data = client.table("db_user").insert(fields).execute().data
195
- return data[0]
196
-
197
-
198
- def select_db_user_by_instance(instance_id: str, client: Client):
199
- """Get db_user for which client has permission."""
200
- data = (
201
- client.table("db_user")
202
- .select("*")
203
- .eq("instance_id", instance_id)
204
- .execute()
205
- .data
206
- )
207
- if len(data) == 0:
208
- return None
209
- elif len(data) > 1:
210
- for item in data:
211
- if item["name"] == "write":
212
- return item
213
- logger.warning("found multiple db credentials, using the first one")
214
- return data[0]
215
-
216
-
217
- def _delete_instance_record(instance_id: UUID, client: Client) -> None:
218
- if not isinstance(instance_id, UUID):
219
- instance_id = UUID(instance_id)
220
- response = client.table("instance").delete().eq("id", instance_id.hex).execute()
221
- if response.data:
222
- logger.important(f"deleted instance record on hub {instance_id.hex}")
223
- else:
224
- raise PermissionError(
225
- f"Deleting of instance with {instance_id.hex} was not successful. Probably, you"
226
- " don't have sufficient permissions."
227
- )
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+ from uuid import UUID, uuid4
5
+
6
+ from lamin_utils import logger
7
+ from supabase.client import Client # noqa
8
+
9
+
10
+ def select_instance_by_owner_name(
11
+ owner: str,
12
+ name: str,
13
+ client: Client,
14
+ ) -> dict | None:
15
+ # this won't find an instance without the default storage
16
+ data = (
17
+ client.table("instance")
18
+ .select(
19
+ "*, account!inner!instance_account_id_28936e8f_fk_account_id(*),"
20
+ " storage!inner!storage_instance_id_359fca71_fk_instance_id(*)"
21
+ )
22
+ .eq("name", name)
23
+ .eq("account.handle", owner)
24
+ .eq("storage.is_default", True)
25
+ .execute()
26
+ .data
27
+ )
28
+ if len(data) == 0:
29
+ return None
30
+ result = data[0]
31
+ # this is a list
32
+ # assume only one default storage
33
+ result["storage"] = result["storage"][0]
34
+ return result
35
+
36
+
37
+ # --------------- ACCOUNT ----------------------
38
+ def select_account_by_handle(
39
+ handle: str,
40
+ client: Client,
41
+ ):
42
+ data = client.table("account").select("*").eq("handle", handle).execute().data
43
+ if len(data) == 0:
44
+ return None
45
+ return data[0]
46
+
47
+
48
+ def select_account_handle_name_by_lnid(lnid: str, client: Client):
49
+ data = (
50
+ client.table("account").select("handle, name").eq("lnid", lnid).execute().data
51
+ )
52
+ if not data:
53
+ return None
54
+ return data[0]
55
+
56
+
57
+ # --------------- INSTANCE ----------------------
58
+ def select_instance_by_name(
59
+ account_id: str,
60
+ name: str,
61
+ client: Client,
62
+ ):
63
+ data = (
64
+ client.table("instance")
65
+ .select("*")
66
+ .eq("account_id", account_id)
67
+ .eq("name", name)
68
+ .execute()
69
+ .data
70
+ )
71
+ if len(data) != 0:
72
+ return data[0]
73
+
74
+ data = (
75
+ client.table("instance_previous_name")
76
+ .select(
77
+ "instance!instance_previous_name_instance_id_17ac5d61_fk_instance_id(*)"
78
+ )
79
+ .eq("instance.account_id", account_id)
80
+ .eq("previous_name", name)
81
+ .execute()
82
+ .data
83
+ )
84
+ if len(data) != 0:
85
+ return data[0]["instance"]
86
+
87
+ return None
88
+
89
+
90
+ def select_instance_by_id(
91
+ instance_id: str,
92
+ client: Client,
93
+ ):
94
+ response = client.table("instance").select("*").eq("id", instance_id).execute()
95
+ if len(response.data) == 0:
96
+ return None
97
+ return response.data[0]
98
+
99
+
100
+ def select_instance_by_id_with_storage(
101
+ instance_id: str,
102
+ client: Client,
103
+ ):
104
+ # this won't find an instance without the default storage
105
+ data = (
106
+ client.table("instance")
107
+ .select("*, storage!inner!storage_instance_id_359fca71_fk_instance_id(*)")
108
+ .eq("id", instance_id)
109
+ .eq("storage.is_default", True)
110
+ .execute()
111
+ .data
112
+ )
113
+ if len(data) == 0:
114
+ return None
115
+ result = data[0]
116
+ # this is a list
117
+ # assume only one default storage
118
+ result["storage"] = result["storage"][0]
119
+ return result
120
+
121
+
122
+ def update_instance(instance_id: str, instance_fields: dict, client: Client):
123
+ response = (
124
+ client.table("instance").update(instance_fields).eq("id", instance_id).execute()
125
+ )
126
+ if len(response.data) == 0:
127
+ raise PermissionError(
128
+ f"Update of instance with {instance_id} was not successful. Probably, you"
129
+ " don't have sufficient permissions."
130
+ )
131
+ return response.data[0]
132
+
133
+
134
+ # --------------- COLLABORATOR ----------------------
135
+
136
+
137
+ def select_collaborator(
138
+ instance_id: str,
139
+ account_id: str,
140
+ client: Client,
141
+ ):
142
+ data = (
143
+ client.table("account_instance")
144
+ .select("*")
145
+ .eq("instance_id", instance_id)
146
+ .eq("account_id", account_id)
147
+ .execute()
148
+ .data
149
+ )
150
+ if len(data) == 0:
151
+ return None
152
+ return data[0]
153
+
154
+
155
+ # --------------- STORAGE ----------------------
156
+
157
+
158
+ def select_default_storage_by_instance_id(
159
+ instance_id: str, client: Client
160
+ ) -> dict | None:
161
+ data = (
162
+ client.table("storage")
163
+ .select("*")
164
+ .eq("instance_id", instance_id)
165
+ .eq("is_default", True)
166
+ .execute()
167
+ .data
168
+ )
169
+ if len(data) == 0:
170
+ return None
171
+ return data[0]
172
+
173
+
174
+ # --------------- DBUser ----------------------
175
+
176
+
177
+ def insert_db_user(
178
+ *,
179
+ name: str,
180
+ db_user_name: str,
181
+ db_user_password: str,
182
+ instance_id: UUID,
183
+ client: Client,
184
+ ) -> None:
185
+ fields = (
186
+ {
187
+ "id": uuid4().hex,
188
+ "instance_id": instance_id.hex,
189
+ "name": name,
190
+ "db_user_name": db_user_name,
191
+ "db_user_password": db_user_password,
192
+ },
193
+ )
194
+ data = client.table("db_user").insert(fields).execute().data
195
+ return data[0]
196
+
197
+
198
+ def select_db_user_by_instance(instance_id: str, client: Client):
199
+ """Get db_user for which client has permission."""
200
+ data = (
201
+ client.table("db_user")
202
+ .select("*")
203
+ .eq("instance_id", instance_id)
204
+ .execute()
205
+ .data
206
+ )
207
+ if len(data) == 0:
208
+ return None
209
+ elif len(data) > 1:
210
+ for item in data:
211
+ if item["name"] == "write":
212
+ return item
213
+ logger.warning("found multiple db credentials, using the first one")
214
+ return data[0]
215
+
216
+
217
+ def _delete_instance_record(instance_id: UUID, client: Client) -> None:
218
+ if not isinstance(instance_id, UUID):
219
+ instance_id = UUID(instance_id)
220
+ response = client.table("instance").delete().eq("id", instance_id.hex).execute()
221
+ if response.data:
222
+ logger.important(f"deleted instance record on hub {instance_id.hex}")
223
+ else:
224
+ raise PermissionError(
225
+ f"Deleting of instance with {instance_id.hex} was not successful. Probably, you"
226
+ " don't have sufficient permissions."
227
+ )
@@ -1,83 +1,83 @@
1
- from __future__ import annotations
2
-
3
- import os
4
- from pathlib import Path
5
-
6
-
7
- def find_vscode_stubs_folder() -> Path | None:
8
- # Possible locations of VSCode extensions
9
- possible_locations = [
10
- Path.home() / ".vscode" / "extensions", # Linux and macOS
11
- Path.home() / ".vscode-server" / "extensions", # Remote development
12
- Path(os.environ.get("APPDATA", "")) / "Code" / "User" / "extensions", # Windows
13
- Path("/usr/share/code/resources/app/extensions"), # Some Linux distributions
14
- ]
15
- for location in possible_locations:
16
- if location.exists():
17
- # Look for Pylance extension folder
18
- pylance_folders = list(location.glob("ms-python.vscode-pylance-*"))
19
- if pylance_folders:
20
- # Sort to get the latest version
21
- latest_pylance = sorted(pylance_folders)[-1]
22
- stubs_folder = (
23
- latest_pylance / "dist" / "bundled" / "stubs" / "django-stubs"
24
- )
25
- if stubs_folder.exists():
26
- return stubs_folder
27
-
28
- return None
29
-
30
-
31
- def private_django_api(reverse=False):
32
- from django import db
33
-
34
- # the order here matters
35
- # changing it might break the tests
36
- attributes = [
37
- "MultipleObjectsReturned",
38
- "add_to_class",
39
- "adelete",
40
- "refresh_from_db",
41
- "asave",
42
- "clean",
43
- "clean_fields",
44
- "date_error_message",
45
- "get_constraints",
46
- "get_deferred_fields",
47
- "prepare_database_save",
48
- "save_base",
49
- "serializable_value",
50
- "unique_error_message",
51
- "validate_constraints",
52
- "validate_unique",
53
- ]
54
- if reverse:
55
- attributes.append("arefresh_from_db")
56
- attributes.append("full_clean")
57
- else:
58
- attributes.append("a_refresh_from_db")
59
- attributes.append("full__clean")
60
-
61
- django_path = Path(db.__file__).parent.parent
62
-
63
- encoding = "utf8" if os.name == "nt" else None
64
-
65
- def prune_file(file_path):
66
- content = file_path.read_text(encoding=encoding)
67
- original_content = content
68
-
69
- for attr in attributes:
70
- old_name = f"_{attr}" if reverse else attr
71
- new_name = attr if reverse else f"_{attr}"
72
- content = content.replace(old_name, new_name)
73
-
74
- if content != original_content:
75
- file_path.write_text(content, encoding=encoding)
76
-
77
- for file_path in django_path.rglob("*.py"):
78
- prune_file(file_path)
79
-
80
- pylance_path = find_vscode_stubs_folder()
81
- if pylance_path is not None:
82
- for file_path in pylance_path.rglob("*.pyi"):
83
- prune_file(file_path)
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from pathlib import Path
5
+
6
+
7
+ def find_vscode_stubs_folder() -> Path | None:
8
+ # Possible locations of VSCode extensions
9
+ possible_locations = [
10
+ Path.home() / ".vscode" / "extensions", # Linux and macOS
11
+ Path.home() / ".vscode-server" / "extensions", # Remote development
12
+ Path(os.environ.get("APPDATA", "")) / "Code" / "User" / "extensions", # Windows
13
+ Path("/usr/share/code/resources/app/extensions"), # Some Linux distributions
14
+ ]
15
+ for location in possible_locations:
16
+ if location.exists():
17
+ # Look for Pylance extension folder
18
+ pylance_folders = list(location.glob("ms-python.vscode-pylance-*"))
19
+ if pylance_folders:
20
+ # Sort to get the latest version
21
+ latest_pylance = sorted(pylance_folders)[-1]
22
+ stubs_folder = (
23
+ latest_pylance / "dist" / "bundled" / "stubs" / "django-stubs"
24
+ )
25
+ if stubs_folder.exists():
26
+ return stubs_folder
27
+
28
+ return None
29
+
30
+
31
+ def private_django_api(reverse=False):
32
+ from django import db
33
+
34
+ # the order here matters
35
+ # changing it might break the tests
36
+ attributes = [
37
+ "MultipleObjectsReturned",
38
+ "add_to_class",
39
+ "adelete",
40
+ "refresh_from_db",
41
+ "asave",
42
+ "clean",
43
+ "clean_fields",
44
+ "date_error_message",
45
+ "get_constraints",
46
+ "get_deferred_fields",
47
+ "prepare_database_save",
48
+ "save_base",
49
+ "serializable_value",
50
+ "unique_error_message",
51
+ "validate_constraints",
52
+ "validate_unique",
53
+ ]
54
+ if reverse:
55
+ attributes.append("arefresh_from_db")
56
+ attributes.append("full_clean")
57
+ else:
58
+ attributes.append("a_refresh_from_db")
59
+ attributes.append("full__clean")
60
+
61
+ django_path = Path(db.__file__).parent.parent
62
+
63
+ encoding = "utf8" if os.name == "nt" else None
64
+
65
+ def prune_file(file_path):
66
+ content = file_path.read_text(encoding=encoding)
67
+ original_content = content
68
+
69
+ for attr in attributes:
70
+ old_name = f"_{attr}" if reverse else attr
71
+ new_name = attr if reverse else f"_{attr}"
72
+ content = content.replace(old_name, new_name)
73
+
74
+ if content != original_content:
75
+ file_path.write_text(content, encoding=encoding)
76
+
77
+ for file_path in django_path.rglob("*.py"):
78
+ prune_file(file_path)
79
+
80
+ pylance_path = find_vscode_stubs_folder()
81
+ if pylance_path is not None:
82
+ for file_path in pylance_path.rglob("*.pyi"):
83
+ prune_file(file_path)