lamindb_setup 1.18.2__py3-none-any.whl → 1.19.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.
- lamindb_setup/__init__.py +4 -19
- lamindb_setup/_cache.py +87 -87
- lamindb_setup/_check.py +7 -7
- lamindb_setup/_check_setup.py +131 -131
- lamindb_setup/_connect_instance.py +443 -438
- lamindb_setup/_delete.py +155 -151
- lamindb_setup/_disconnect.py +38 -38
- lamindb_setup/_django.py +39 -39
- lamindb_setup/_entry_points.py +19 -19
- lamindb_setup/_init_instance.py +423 -429
- lamindb_setup/_migrate.py +331 -327
- lamindb_setup/_register_instance.py +32 -32
- lamindb_setup/_schema.py +27 -27
- lamindb_setup/_schema_metadata.py +451 -451
- lamindb_setup/_set_managed_storage.py +81 -80
- lamindb_setup/_setup_user.py +198 -198
- lamindb_setup/_silence_loggers.py +46 -46
- lamindb_setup/core/__init__.py +25 -34
- lamindb_setup/core/_aws_options.py +276 -266
- lamindb_setup/core/_aws_storage.py +57 -55
- lamindb_setup/core/_clone.py +50 -50
- lamindb_setup/core/_deprecated.py +62 -62
- lamindb_setup/core/_docs.py +14 -14
- lamindb_setup/core/_hub_client.py +288 -294
- lamindb_setup/core/_hub_core.py +0 -2
- lamindb_setup/core/_hub_crud.py +247 -247
- lamindb_setup/core/_hub_utils.py +100 -100
- lamindb_setup/core/_private_django_api.py +80 -80
- lamindb_setup/core/_settings.py +440 -434
- lamindb_setup/core/_settings_instance.py +32 -7
- lamindb_setup/core/_settings_load.py +162 -159
- lamindb_setup/core/_settings_save.py +108 -96
- lamindb_setup/core/_settings_storage.py +433 -433
- lamindb_setup/core/_settings_store.py +162 -92
- lamindb_setup/core/_settings_user.py +55 -55
- lamindb_setup/core/_setup_bionty_sources.py +44 -44
- lamindb_setup/core/cloud_sqlite_locker.py +240 -240
- lamindb_setup/core/django.py +414 -413
- lamindb_setup/core/exceptions.py +1 -1
- lamindb_setup/core/hashing.py +134 -134
- lamindb_setup/core/types.py +1 -1
- lamindb_setup/core/upath.py +1031 -1028
- lamindb_setup/errors.py +72 -70
- lamindb_setup/io.py +423 -416
- lamindb_setup/types.py +17 -17
- {lamindb_setup-1.18.2.dist-info → lamindb_setup-1.19.1.dist-info}/METADATA +4 -2
- lamindb_setup-1.19.1.dist-info/RECORD +51 -0
- {lamindb_setup-1.18.2.dist-info → lamindb_setup-1.19.1.dist-info}/WHEEL +1 -1
- {lamindb_setup-1.18.2.dist-info → lamindb_setup-1.19.1.dist-info/licenses}/LICENSE +201 -201
- lamindb_setup-1.18.2.dist-info/RECORD +0 -51
|
@@ -1,92 +1,162 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
try:
|
|
19
|
-
settings_dir.mkdir(parents=True, exist_ok=True)
|
|
20
|
-
except Exception as e:
|
|
21
|
-
logger.warning(f"Failed to create lamin settings directory at {settings_dir}: {e}")
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from dataclasses import MISSING, dataclass, fields
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any, get_args, get_type_hints
|
|
7
|
+
|
|
8
|
+
from dotenv import dotenv_values
|
|
9
|
+
from lamin_utils import logger
|
|
10
|
+
from platformdirs import site_config_dir
|
|
11
|
+
|
|
12
|
+
if "LAMIN_SETTINGS_DIR" in os.environ:
|
|
13
|
+
# Needed for AWS Lambda, as only tmp/ has write access
|
|
14
|
+
settings_dir = Path(f"{os.environ['LAMIN_SETTINGS_DIR']}/.lamin")
|
|
15
|
+
else:
|
|
16
|
+
settings_dir = Path.home() / ".lamin"
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
settings_dir.mkdir(parents=True, exist_ok=True)
|
|
20
|
+
except Exception as e:
|
|
21
|
+
logger.warning(f"Failed to create lamin settings directory at {settings_dir}: {e}")
|
|
22
|
+
|
|
23
|
+
system_settings_dir = Path(site_config_dir(appname="lamindb", appauthor="laminlabs"))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def get_settings_file_name_prefix():
|
|
27
|
+
if "LAMIN_ENV" in os.environ:
|
|
28
|
+
if os.environ["LAMIN_ENV"] != "prod":
|
|
29
|
+
return f"{os.environ['LAMIN_ENV']}--"
|
|
30
|
+
return ""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def current_instance_settings_file():
|
|
34
|
+
return settings_dir / f"{get_settings_file_name_prefix()}current_instance.env"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def current_user_settings_file():
|
|
38
|
+
return settings_dir / f"{get_settings_file_name_prefix()}current_user.env"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def instance_settings_file(name: str, owner: str):
|
|
42
|
+
return (
|
|
43
|
+
settings_dir / f"{get_settings_file_name_prefix()}instance--{owner}--{name}.env"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def user_settings_file_email(email: str):
|
|
48
|
+
return settings_dir / f"{get_settings_file_name_prefix()}user--{email}.env"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def user_settings_file_handle(handle: str):
|
|
52
|
+
return settings_dir / f"{get_settings_file_name_prefix()}user--{handle}.env"
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def platform_user_storage_settings_file():
|
|
56
|
+
return settings_dir / "storage.env"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def system_settings_file():
|
|
60
|
+
return system_settings_dir / "system.env"
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _load_env_to_kwargs(
|
|
64
|
+
cls: type,
|
|
65
|
+
path: Path | str,
|
|
66
|
+
prefix: str,
|
|
67
|
+
) -> dict[str, Any]:
|
|
68
|
+
path = Path(path) if isinstance(path, str) else path
|
|
69
|
+
raw = dotenv_values(path)
|
|
70
|
+
type_hints = get_type_hints(cls)
|
|
71
|
+
flds = {f.name: f for f in fields(cls)}
|
|
72
|
+
optional = {
|
|
73
|
+
n
|
|
74
|
+
for n, f in flds.items()
|
|
75
|
+
if f.default is not MISSING or f.default_factory is not MISSING
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
kwargs: dict[str, Any] = {}
|
|
79
|
+
for store_key in type_hints:
|
|
80
|
+
if store_key.startswith("__"):
|
|
81
|
+
continue
|
|
82
|
+
env_key = f"{prefix}{store_key}"
|
|
83
|
+
has_key = env_key in raw
|
|
84
|
+
raw_val = raw.get(env_key) if has_key else None
|
|
85
|
+
is_opt = store_key in optional
|
|
86
|
+
|
|
87
|
+
if not has_key:
|
|
88
|
+
if not is_opt:
|
|
89
|
+
raise ValueError(f"Missing required key {env_key!r} in env file {path}")
|
|
90
|
+
kwargs[store_key] = None
|
|
91
|
+
continue
|
|
92
|
+
if raw_val is None or raw_val == "" or raw_val == "null":
|
|
93
|
+
kwargs[store_key] = None
|
|
94
|
+
continue
|
|
95
|
+
type_ = type_hints[store_key]
|
|
96
|
+
args = get_args(type_) or ()
|
|
97
|
+
if type_ is bool:
|
|
98
|
+
kwargs[store_key] = raw_val.lower() in ("true", "1", "yes")
|
|
99
|
+
elif type(None) in args:
|
|
100
|
+
non_none = next((a for a in args if a is not type(None)), type_)
|
|
101
|
+
if non_none is bool:
|
|
102
|
+
kwargs[store_key] = raw_val.lower() in ("true", "1", "yes")
|
|
103
|
+
else:
|
|
104
|
+
kwargs[store_key] = raw_val
|
|
105
|
+
else:
|
|
106
|
+
kwargs[store_key] = raw_val
|
|
107
|
+
return kwargs
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
@dataclass
|
|
111
|
+
class InstanceSettingsStore:
|
|
112
|
+
# Required (no default) — must come first
|
|
113
|
+
owner: str
|
|
114
|
+
name: str
|
|
115
|
+
storage_root: str
|
|
116
|
+
storage_region: str | None
|
|
117
|
+
db: str | None
|
|
118
|
+
schema_str: str | None
|
|
119
|
+
id: str
|
|
120
|
+
git_repo: str | None
|
|
121
|
+
keep_artifacts_local: bool | None
|
|
122
|
+
# Optional
|
|
123
|
+
api_url: str | None = None
|
|
124
|
+
schema_id: str | None = None
|
|
125
|
+
fine_grained_access: bool = False
|
|
126
|
+
db_permissions: str | None = None
|
|
127
|
+
is_clone: bool = False
|
|
128
|
+
|
|
129
|
+
@classmethod
|
|
130
|
+
def from_env_file(cls, path: Path | str, prefix: str) -> InstanceSettingsStore:
|
|
131
|
+
kwargs = _load_env_to_kwargs(cls, path, prefix)
|
|
132
|
+
return cls(**kwargs)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@dataclass
|
|
136
|
+
class UserSettingsStore:
|
|
137
|
+
# Required (no default)
|
|
138
|
+
email: str
|
|
139
|
+
password: str
|
|
140
|
+
access_token: str
|
|
141
|
+
uid: str
|
|
142
|
+
uuid: str
|
|
143
|
+
handle: str
|
|
144
|
+
name: str
|
|
145
|
+
# Optional
|
|
146
|
+
api_key: str | None = None
|
|
147
|
+
|
|
148
|
+
@classmethod
|
|
149
|
+
def from_env_file(cls, path: Path | str, prefix: str) -> UserSettingsStore:
|
|
150
|
+
kwargs = _load_env_to_kwargs(cls, path, prefix)
|
|
151
|
+
return cls(**kwargs)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@dataclass
|
|
155
|
+
class Connector:
|
|
156
|
+
url: str
|
|
157
|
+
key: str
|
|
158
|
+
|
|
159
|
+
@classmethod
|
|
160
|
+
def from_env_file(cls, path: Path | str, prefix: str) -> Connector:
|
|
161
|
+
kwargs = _load_env_to_kwargs(cls, path, prefix)
|
|
162
|
+
return cls(**kwargs)
|
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
5
|
-
|
|
6
|
-
if TYPE_CHECKING:
|
|
7
|
-
from uuid import UUID
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class user_description:
|
|
11
|
-
email = """User email."""
|
|
12
|
-
password = """API key or legacy password."""
|
|
13
|
-
uid = """Universal user ID."""
|
|
14
|
-
handle = "Unique handle."
|
|
15
|
-
name = "Full name."
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
@dataclass
|
|
19
|
-
class UserSettings:
|
|
20
|
-
"""User data. All synched from cloud."""
|
|
21
|
-
|
|
22
|
-
handle: str = "anonymous"
|
|
23
|
-
"""Unique handle."""
|
|
24
|
-
email: str | None = None
|
|
25
|
-
"""User email."""
|
|
26
|
-
api_key: str | None = None
|
|
27
|
-
"""API key."""
|
|
28
|
-
password: str | None = None
|
|
29
|
-
"""
|
|
30
|
-
access_token: str | None = None
|
|
31
|
-
"""User access token."""
|
|
32
|
-
uid: str = "null"
|
|
33
|
-
"""Universal user ID."""
|
|
34
|
-
_uuid: UUID | None = None
|
|
35
|
-
"""Lamin's internal user ID."""
|
|
36
|
-
name: str | None = None
|
|
37
|
-
"""Full name."""
|
|
38
|
-
|
|
39
|
-
def __repr__(self) -> str:
|
|
40
|
-
"""Rich string representation."""
|
|
41
|
-
representation = "Current user:"
|
|
42
|
-
attrs = ["handle", "uid"]
|
|
43
|
-
for attr in attrs:
|
|
44
|
-
value = getattr(self, attr)
|
|
45
|
-
representation += f"\n - {attr}: {value}"
|
|
46
|
-
return representation
|
|
47
|
-
|
|
48
|
-
@property
|
|
49
|
-
def id(self):
|
|
50
|
-
"""Integer id valid in current instance."""
|
|
51
|
-
from lamindb.base.users import current_user_id
|
|
52
|
-
|
|
53
|
-
# there is no cache needed here because current_user_id()
|
|
54
|
-
# has its own cache
|
|
55
|
-
return current_user_id()
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from uuid import UUID
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class user_description:
|
|
11
|
+
email = """User email."""
|
|
12
|
+
password = """API key or legacy password."""
|
|
13
|
+
uid = """Universal user ID."""
|
|
14
|
+
handle = "Unique handle."
|
|
15
|
+
name = "Full name."
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class UserSettings:
|
|
20
|
+
"""User data. All synched from cloud."""
|
|
21
|
+
|
|
22
|
+
handle: str = "anonymous"
|
|
23
|
+
"""Unique handle."""
|
|
24
|
+
email: str | None = None
|
|
25
|
+
"""User email."""
|
|
26
|
+
api_key: str | None = None
|
|
27
|
+
"""API key."""
|
|
28
|
+
password: str | None = None
|
|
29
|
+
"""Legacy password."""
|
|
30
|
+
access_token: str | None = None
|
|
31
|
+
"""User access token."""
|
|
32
|
+
uid: str = "null"
|
|
33
|
+
"""Universal user ID."""
|
|
34
|
+
_uuid: UUID | None = None
|
|
35
|
+
"""Lamin's internal user ID."""
|
|
36
|
+
name: str | None = None
|
|
37
|
+
"""Full name."""
|
|
38
|
+
|
|
39
|
+
def __repr__(self) -> str:
|
|
40
|
+
"""Rich string representation."""
|
|
41
|
+
representation = "Current user:"
|
|
42
|
+
attrs = ["handle", "uid"]
|
|
43
|
+
for attr in attrs:
|
|
44
|
+
value = getattr(self, attr)
|
|
45
|
+
representation += f"\n - {attr}: {value}"
|
|
46
|
+
return representation
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def id(self):
|
|
50
|
+
"""Integer id valid in current instance."""
|
|
51
|
+
from lamindb.base.users import current_user_id
|
|
52
|
+
|
|
53
|
+
# there is no cache needed here because current_user_id()
|
|
54
|
+
# has its own cache
|
|
55
|
+
return current_user_id()
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
|
-
|
|
5
|
-
if TYPE_CHECKING:
|
|
6
|
-
from ._settings_instance import InstanceSettings
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
def write_bionty_sources(isettings: InstanceSettings) -> None:
|
|
10
|
-
"""Write public bionty sources to bt.Source table."""
|
|
11
|
-
if "bionty" not in isettings.modules:
|
|
12
|
-
return None
|
|
13
|
-
|
|
14
|
-
import bionty
|
|
15
|
-
import bionty.base as bionty_base
|
|
16
|
-
from bionty._biorecord import list_biorecord_models
|
|
17
|
-
from bionty.base.dev._handle_sources import parse_sources_yaml
|
|
18
|
-
from bionty.models import Source
|
|
19
|
-
|
|
20
|
-
bionty_models = list_biorecord_models(bionty)
|
|
21
|
-
|
|
22
|
-
all_sources = parse_sources_yaml(bionty_base.settings.public_sources)
|
|
23
|
-
all_sources_dict = all_sources.to_dict(orient="records")
|
|
24
|
-
|
|
25
|
-
currently_used = (
|
|
26
|
-
bionty_base.display_currently_used_sources(mute=True)
|
|
27
|
-
.reset_index()
|
|
28
|
-
.set_index(["entity", "organism"])
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
all_records = []
|
|
32
|
-
for kwargs in all_sources_dict:
|
|
33
|
-
act = currently_used.loc[(kwargs["entity"], kwargs["organism"])].to_dict()
|
|
34
|
-
if (act["name"] == kwargs["name"]) and (act["version"] == kwargs["version"]):
|
|
35
|
-
kwargs["currently_used"] = True
|
|
36
|
-
|
|
37
|
-
kwargs["run"] = None # can't yet access tracking information
|
|
38
|
-
kwargs["in_db"] = False
|
|
39
|
-
if kwargs["entity"] in bionty_models:
|
|
40
|
-
kwargs["entity"] = f"bionty.{kwargs['entity']}"
|
|
41
|
-
record = Source(**kwargs)
|
|
42
|
-
all_records.append(record)
|
|
43
|
-
|
|
44
|
-
Source.objects.bulk_create(all_records, ignore_conflicts=True)
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from ._settings_instance import InstanceSettings
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def write_bionty_sources(isettings: InstanceSettings) -> None:
|
|
10
|
+
"""Write public bionty sources to bt.Source table."""
|
|
11
|
+
if "bionty" not in isettings.modules:
|
|
12
|
+
return None
|
|
13
|
+
|
|
14
|
+
import bionty
|
|
15
|
+
import bionty.base as bionty_base
|
|
16
|
+
from bionty._biorecord import list_biorecord_models
|
|
17
|
+
from bionty.base.dev._handle_sources import parse_sources_yaml
|
|
18
|
+
from bionty.models import Source
|
|
19
|
+
|
|
20
|
+
bionty_models = list_biorecord_models(bionty)
|
|
21
|
+
|
|
22
|
+
all_sources = parse_sources_yaml(bionty_base.settings.public_sources)
|
|
23
|
+
all_sources_dict = all_sources.to_dict(orient="records")
|
|
24
|
+
|
|
25
|
+
currently_used = (
|
|
26
|
+
bionty_base.display_currently_used_sources(mute=True)
|
|
27
|
+
.reset_index()
|
|
28
|
+
.set_index(["entity", "organism"])
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
all_records = []
|
|
32
|
+
for kwargs in all_sources_dict:
|
|
33
|
+
act = currently_used.loc[(kwargs["entity"], kwargs["organism"])].to_dict()
|
|
34
|
+
if (act["name"] == kwargs["name"]) and (act["version"] == kwargs["version"]):
|
|
35
|
+
kwargs["currently_used"] = True
|
|
36
|
+
|
|
37
|
+
kwargs["run"] = None # can't yet access tracking information
|
|
38
|
+
kwargs["in_db"] = False
|
|
39
|
+
if kwargs["entity"] in bionty_models:
|
|
40
|
+
kwargs["entity"] = f"bionty.{kwargs['entity']}"
|
|
41
|
+
record = Source(**kwargs)
|
|
42
|
+
all_records.append(record)
|
|
43
|
+
|
|
44
|
+
Source.objects.bulk_create(all_records, ignore_conflicts=True)
|