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,80 +1,81 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING
|
|
4
|
-
|
|
5
|
-
from lamin_utils import logger
|
|
6
|
-
|
|
7
|
-
from ._init_instance import register_storage_in_instance
|
|
8
|
-
from .core.
|
|
9
|
-
from .core.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
""
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
# we
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
#
|
|
62
|
-
# if
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
settings.
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
from lamin_utils import logger
|
|
6
|
+
|
|
7
|
+
from ._init_instance import register_storage_in_instance
|
|
8
|
+
from .core._settings import settings
|
|
9
|
+
from .core._settings_storage import StorageSettings, init_storage
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from lamindb_setup.types import UPathStr
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def set_managed_storage(root: UPathStr, host: str | None = None, **fs_kwargs):
|
|
16
|
+
"""Add or switch to another managed storage location.
|
|
17
|
+
|
|
18
|
+
Note: This function should be called `set_writeable_storage_location` instead. But likely it will disappear
|
|
19
|
+
in refactoring that consolidates with the `ln.Storage()` path.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
root: `UPathStr` - The new storage root, e.g., an S3 bucket.
|
|
23
|
+
host: `str | None = None` For a shared local storage location, pass a globally unique host identifier, e.g. `"my-institute-cluster-1"`, `"my-server-abcd"`, ...
|
|
24
|
+
Discuss the naming convention with an admin.
|
|
25
|
+
**fs_kwargs: Additional fsspec arguments for cloud root, e.g., profile.
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
if settings.instance.dialect == "sqlite":
|
|
29
|
+
raise ValueError(
|
|
30
|
+
"Can't add additional managed storage locations for sqlite instances."
|
|
31
|
+
)
|
|
32
|
+
if not settings.instance.is_on_hub:
|
|
33
|
+
raise ValueError(
|
|
34
|
+
"Can't add additional managed storage locations for instances that aren't managed through the hub."
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# we do not just query the instance storage table because
|
|
38
|
+
# we might need some information from the hub
|
|
39
|
+
if not StorageSettings(root).type_is_cloud and host is None:
|
|
40
|
+
host = "unspecified-host"
|
|
41
|
+
logger.warning(
|
|
42
|
+
"setting local storage locations with a single path is deprecated, "
|
|
43
|
+
"use a tuple of (local_root, host) instead"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# here the storage location is registered in the hub
|
|
47
|
+
# hub_record_status="hub-record-created" if a new record is created
|
|
48
|
+
# "hub-record-retrieved" if the storage is in the hub already
|
|
49
|
+
ssettings, hub_record_status = init_storage(
|
|
50
|
+
root=root,
|
|
51
|
+
instance_id=settings.instance._id,
|
|
52
|
+
instance_slug=settings.instance.slug,
|
|
53
|
+
register_hub=settings.instance.is_on_hub,
|
|
54
|
+
region=host,
|
|
55
|
+
)
|
|
56
|
+
if ssettings._instance_id is None:
|
|
57
|
+
raise ValueError(
|
|
58
|
+
f"Cannot manage storage without write access: {ssettings.root}"
|
|
59
|
+
)
|
|
60
|
+
# here the storage is saved in the instance
|
|
61
|
+
# if any error happens the record in the hub is deleted
|
|
62
|
+
# if it was created earlier and not retrieved
|
|
63
|
+
try:
|
|
64
|
+
register_storage_in_instance(ssettings)
|
|
65
|
+
except Exception as e:
|
|
66
|
+
if hub_record_status == "hub-record-created" and ssettings._uuid is not None:
|
|
67
|
+
from .core._hub_core import delete_storage_record
|
|
68
|
+
|
|
69
|
+
delete_storage_record(ssettings)
|
|
70
|
+
raise e
|
|
71
|
+
|
|
72
|
+
if ssettings._instance_id != settings.instance._id:
|
|
73
|
+
logger.warning(
|
|
74
|
+
f"registered storage location {root} as read-only for this instance (it's written by instance with uid: {ssettings.instance_uid})"
|
|
75
|
+
)
|
|
76
|
+
logger.warning(
|
|
77
|
+
f"did *not* switch default storage location, it's still: {settings.storage.root_as_str}"
|
|
78
|
+
)
|
|
79
|
+
else:
|
|
80
|
+
settings.instance._storage = ssettings
|
|
81
|
+
settings.storage._set_fs_kwargs(**fs_kwargs)
|
lamindb_setup/_setup_user.py
CHANGED
|
@@ -1,198 +1,198 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
from time import sleep
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
6
|
-
|
|
7
|
-
from lamin_utils import logger
|
|
8
|
-
|
|
9
|
-
from ._check_setup import _check_instance_setup
|
|
10
|
-
from ._init_instance import register_user
|
|
11
|
-
from .core._aws_options import reset_aws_options_cache
|
|
12
|
-
from .core._settings import settings
|
|
13
|
-
from .core._settings_load import load_user_settings
|
|
14
|
-
from .core._settings_save import save_user_settings
|
|
15
|
-
from .core._settings_store import (
|
|
16
|
-
current_user_settings_file,
|
|
17
|
-
user_settings_file_email,
|
|
18
|
-
user_settings_file_handle,
|
|
19
|
-
)
|
|
20
|
-
from .core._settings_user import UserSettings
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def load_user(email: str | None = None, handle: str | None = None) -> UserSettings:
|
|
24
|
-
if email is not None:
|
|
25
|
-
settings_file = user_settings_file_email(email)
|
|
26
|
-
if handle is not None:
|
|
27
|
-
settings_file = user_settings_file_handle(handle)
|
|
28
|
-
if settings_file.exists():
|
|
29
|
-
user_settings = load_user_settings(settings_file)
|
|
30
|
-
save_user_settings(user_settings) # needed to save to current_user.env
|
|
31
|
-
assert user_settings.email is not None or user_settings.api_key is not None
|
|
32
|
-
else:
|
|
33
|
-
if email is None:
|
|
34
|
-
raise SystemExit(
|
|
35
|
-
"✗ Use your email for your first login in a compute environment. "
|
|
36
|
-
"After that, you can use your handle."
|
|
37
|
-
)
|
|
38
|
-
user_settings = UserSettings(handle=handle, email=email, uid="null") # type: ignore
|
|
39
|
-
|
|
40
|
-
from .core._settings import settings
|
|
41
|
-
|
|
42
|
-
settings._user_settings = None # this is to refresh a settings instance
|
|
43
|
-
|
|
44
|
-
return user_settings
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def current_user_uid() -> str:
|
|
48
|
-
current_user_settings = current_user_settings_file()
|
|
49
|
-
if current_user_settings.exists():
|
|
50
|
-
return load_user_settings(current_user_settings).uid
|
|
51
|
-
|
|
52
|
-
return "00000000" # anonymous
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def login(
|
|
56
|
-
user: str | None = None, *, api_key: str | None = None, **kwargs
|
|
57
|
-
) -> UserSettings:
|
|
58
|
-
# note that the docstring needs to be synced with lamin login
|
|
59
|
-
"""Log into LaminHub.
|
|
60
|
-
|
|
61
|
-
`login()` prompts for your API key unless you set it via the `LAMIN_API_KEY` environment variable or pass it as an argument.
|
|
62
|
-
|
|
63
|
-
You can create your API key in your account settings on LaminHub at `lamin.ai/settings <https://lamin.ai/settings>`__.
|
|
64
|
-
|
|
65
|
-
Note that the preferred method is to use the CLI command `lamin login`: `docs.lamin.ai/cli#login <https://docs.lamin.ai/cli#login>`__.
|
|
66
|
-
|
|
67
|
-
Args:
|
|
68
|
-
user: User handle.
|
|
69
|
-
api_key: API key.
|
|
70
|
-
|
|
71
|
-
Examples:
|
|
72
|
-
|
|
73
|
-
Logging in the first time::
|
|
74
|
-
|
|
75
|
-
import lamindb as ln
|
|
76
|
-
|
|
77
|
-
ln.setup.login() # prompts for API key
|
|
78
|
-
|
|
79
|
-
After authenticating multiple users, you can switch between user profiles::
|
|
80
|
-
|
|
81
|
-
ln.setup.login("myhandle") # pass your user handle
|
|
82
|
-
"""
|
|
83
|
-
from getpass import getpass
|
|
84
|
-
|
|
85
|
-
if user is None:
|
|
86
|
-
if api_key is None:
|
|
87
|
-
if "LAMIN_API_KEY" in os.environ:
|
|
88
|
-
api_key = os.environ["LAMIN_API_KEY"]
|
|
89
|
-
else:
|
|
90
|
-
print("Copy your API key. To create one: https://lamin.ai/settings")
|
|
91
|
-
api_key = getpass("Paste it: ")
|
|
92
|
-
elif api_key is not None:
|
|
93
|
-
raise ValueError("Please provide either 'user' or 'api_key', not both.")
|
|
94
|
-
|
|
95
|
-
for kwarg in kwargs:
|
|
96
|
-
if kwarg != "key":
|
|
97
|
-
raise TypeError(f"login() got unexpected keyword argument '{kwarg}'")
|
|
98
|
-
key: str | None = kwargs.get("key", None) # legacy API key aka password
|
|
99
|
-
if key is not None:
|
|
100
|
-
logger.warning(
|
|
101
|
-
"the legacy API key is deprecated and will likely be removed in a future version"
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
# do this here because load_user overwrites current_user_settings_file
|
|
105
|
-
previous_user_uid = current_user_uid()
|
|
106
|
-
|
|
107
|
-
if api_key is None:
|
|
108
|
-
if "@" in user: # type: ignore
|
|
109
|
-
email, handle = user, None
|
|
110
|
-
else:
|
|
111
|
-
email, handle = None, user
|
|
112
|
-
user_settings = load_user(email, handle)
|
|
113
|
-
|
|
114
|
-
if key is not None:
|
|
115
|
-
user_settings.password = key
|
|
116
|
-
|
|
117
|
-
if user_settings.password is None:
|
|
118
|
-
api_key = user_settings.api_key
|
|
119
|
-
if api_key is None:
|
|
120
|
-
raise SystemExit(
|
|
121
|
-
"✗ No stored API key, please call: "
|
|
122
|
-
"`lamin login` or `lamin login <your-email> --key <API-key>`"
|
|
123
|
-
)
|
|
124
|
-
elif user_settings.email is None:
|
|
125
|
-
raise SystemExit(f"✗ No stored user email, please call: lamin login {user}")
|
|
126
|
-
else:
|
|
127
|
-
user_settings = UserSettings(handle="temporary", uid="null")
|
|
128
|
-
|
|
129
|
-
from .core._hub_core import sign_in_hub, sign_in_hub_api_key
|
|
130
|
-
|
|
131
|
-
if api_key is None:
|
|
132
|
-
response = sign_in_hub(
|
|
133
|
-
user_settings.email, # type: ignore
|
|
134
|
-
user_settings.password, # type: ignore
|
|
135
|
-
user_settings.handle,
|
|
136
|
-
)
|
|
137
|
-
else:
|
|
138
|
-
response = sign_in_hub_api_key(api_key)
|
|
139
|
-
user_settings.password = None
|
|
140
|
-
|
|
141
|
-
if isinstance(response, Exception):
|
|
142
|
-
raise response
|
|
143
|
-
elif isinstance(response, str):
|
|
144
|
-
raise SystemExit(f"✗ Unsuccessful login: {response}.")
|
|
145
|
-
else:
|
|
146
|
-
user_uuid, user_id, user_handle, user_name, access_token = response
|
|
147
|
-
|
|
148
|
-
if api_key is not None:
|
|
149
|
-
logger.success(f"logged in {user_handle}")
|
|
150
|
-
else: # legacy flow
|
|
151
|
-
logger.success(f"logged in with email {user_settings.email}")
|
|
152
|
-
|
|
153
|
-
user_settings.uid = user_id
|
|
154
|
-
user_settings.handle = user_handle
|
|
155
|
-
user_settings.name = user_name
|
|
156
|
-
user_settings._uuid = user_uuid
|
|
157
|
-
user_settings.access_token = access_token
|
|
158
|
-
user_settings.api_key = api_key
|
|
159
|
-
save_user_settings(user_settings)
|
|
160
|
-
|
|
161
|
-
if settings._instance_exists:
|
|
162
|
-
if (
|
|
163
|
-
isettings := settings.instance
|
|
164
|
-
).is_on_hub and previous_user_uid != user_settings.uid:
|
|
165
|
-
logger.important_hint(
|
|
166
|
-
f"consider re-connecting to update permissions: lamin connect {isettings.slug}"
|
|
167
|
-
)
|
|
168
|
-
if _check_instance_setup():
|
|
169
|
-
register_user(user_settings)
|
|
170
|
-
|
|
171
|
-
settings._user_settings = None
|
|
172
|
-
# aws s3 credentials are scoped to the user
|
|
173
|
-
reset_aws_options_cache()
|
|
174
|
-
return user_settings
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def logout():
|
|
178
|
-
"""Log out the current user.
|
|
179
|
-
|
|
180
|
-
This deletes the `~/.lamin/current_user.env` so that you'll no longer be automatically authenticated in the environment.
|
|
181
|
-
|
|
182
|
-
It keeps a copy as `~/.lamin/user--<user_handle>.env` so you can easily switch between user profiles.
|
|
183
|
-
|
|
184
|
-
See Also:
|
|
185
|
-
Logout via the CLI command `lamin logout`, see `here <https://docs.lamin.ai/cli#logout>`__.
|
|
186
|
-
"""
|
|
187
|
-
if current_user_settings_file().exists():
|
|
188
|
-
current_user_settings_file().unlink()
|
|
189
|
-
settings._user_settings = None
|
|
190
|
-
# aws s3 credentials are scoped to the user
|
|
191
|
-
reset_aws_options_cache()
|
|
192
|
-
logger.success("logged out")
|
|
193
|
-
else:
|
|
194
|
-
logger.important("already logged out")
|
|
195
|
-
if os.environ.get("LAMIN_API_KEY") is not None:
|
|
196
|
-
logger.warning(
|
|
197
|
-
"LAMIN_API_KEY is still set in your environment and will automatically log you in"
|
|
198
|
-
)
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from time import sleep
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from lamin_utils import logger
|
|
8
|
+
|
|
9
|
+
from ._check_setup import _check_instance_setup
|
|
10
|
+
from ._init_instance import register_user
|
|
11
|
+
from .core._aws_options import reset_aws_options_cache
|
|
12
|
+
from .core._settings import settings
|
|
13
|
+
from .core._settings_load import load_user_settings
|
|
14
|
+
from .core._settings_save import save_user_settings
|
|
15
|
+
from .core._settings_store import (
|
|
16
|
+
current_user_settings_file,
|
|
17
|
+
user_settings_file_email,
|
|
18
|
+
user_settings_file_handle,
|
|
19
|
+
)
|
|
20
|
+
from .core._settings_user import UserSettings
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def load_user(email: str | None = None, handle: str | None = None) -> UserSettings:
|
|
24
|
+
if email is not None:
|
|
25
|
+
settings_file = user_settings_file_email(email)
|
|
26
|
+
if handle is not None:
|
|
27
|
+
settings_file = user_settings_file_handle(handle)
|
|
28
|
+
if settings_file.exists():
|
|
29
|
+
user_settings = load_user_settings(settings_file)
|
|
30
|
+
save_user_settings(user_settings) # needed to save to current_user.env
|
|
31
|
+
assert user_settings.email is not None or user_settings.api_key is not None
|
|
32
|
+
else:
|
|
33
|
+
if email is None:
|
|
34
|
+
raise SystemExit(
|
|
35
|
+
"✗ Use your email for your first login in a compute environment. "
|
|
36
|
+
"After that, you can use your handle."
|
|
37
|
+
)
|
|
38
|
+
user_settings = UserSettings(handle=handle, email=email, uid="null") # type: ignore
|
|
39
|
+
|
|
40
|
+
from .core._settings import settings
|
|
41
|
+
|
|
42
|
+
settings._user_settings = None # this is to refresh a settings instance
|
|
43
|
+
|
|
44
|
+
return user_settings
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def current_user_uid() -> str:
|
|
48
|
+
current_user_settings = current_user_settings_file()
|
|
49
|
+
if current_user_settings.exists():
|
|
50
|
+
return load_user_settings(current_user_settings).uid
|
|
51
|
+
|
|
52
|
+
return "00000000" # anonymous
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def login(
|
|
56
|
+
user: str | None = None, *, api_key: str | None = None, **kwargs
|
|
57
|
+
) -> UserSettings:
|
|
58
|
+
# note that the docstring needs to be synced with lamin login
|
|
59
|
+
"""Log into LaminHub.
|
|
60
|
+
|
|
61
|
+
`login()` prompts for your API key unless you set it via the `LAMIN_API_KEY` environment variable or pass it as an argument.
|
|
62
|
+
|
|
63
|
+
You can create your API key in your account settings on LaminHub at `lamin.ai/settings <https://lamin.ai/settings>`__.
|
|
64
|
+
|
|
65
|
+
Note that the preferred method is to use the CLI command `lamin login`: `docs.lamin.ai/cli#login <https://docs.lamin.ai/cli#login>`__.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
user: User handle.
|
|
69
|
+
api_key: API key.
|
|
70
|
+
|
|
71
|
+
Examples:
|
|
72
|
+
|
|
73
|
+
Logging in the first time::
|
|
74
|
+
|
|
75
|
+
import lamindb as ln
|
|
76
|
+
|
|
77
|
+
ln.setup.login() # prompts for API key
|
|
78
|
+
|
|
79
|
+
After authenticating multiple users, you can switch between user profiles::
|
|
80
|
+
|
|
81
|
+
ln.setup.login("myhandle") # pass your user handle
|
|
82
|
+
"""
|
|
83
|
+
from getpass import getpass
|
|
84
|
+
|
|
85
|
+
if user is None:
|
|
86
|
+
if api_key is None:
|
|
87
|
+
if "LAMIN_API_KEY" in os.environ:
|
|
88
|
+
api_key = os.environ["LAMIN_API_KEY"]
|
|
89
|
+
else:
|
|
90
|
+
print("Copy your API key. To create one: https://lamin.ai/settings")
|
|
91
|
+
api_key = getpass("Paste it: ")
|
|
92
|
+
elif api_key is not None:
|
|
93
|
+
raise ValueError("Please provide either 'user' or 'api_key', not both.")
|
|
94
|
+
|
|
95
|
+
for kwarg in kwargs:
|
|
96
|
+
if kwarg != "key":
|
|
97
|
+
raise TypeError(f"login() got unexpected keyword argument '{kwarg}'")
|
|
98
|
+
key: str | None = kwargs.get("key", None) # legacy API key aka password
|
|
99
|
+
if key is not None:
|
|
100
|
+
logger.warning(
|
|
101
|
+
"the legacy API key is deprecated and will likely be removed in a future version"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# do this here because load_user overwrites current_user_settings_file
|
|
105
|
+
previous_user_uid = current_user_uid()
|
|
106
|
+
|
|
107
|
+
if api_key is None:
|
|
108
|
+
if "@" in user: # type: ignore
|
|
109
|
+
email, handle = user, None
|
|
110
|
+
else:
|
|
111
|
+
email, handle = None, user
|
|
112
|
+
user_settings = load_user(email, handle)
|
|
113
|
+
|
|
114
|
+
if key is not None:
|
|
115
|
+
user_settings.password = key
|
|
116
|
+
|
|
117
|
+
if user_settings.password is None:
|
|
118
|
+
api_key = user_settings.api_key
|
|
119
|
+
if api_key is None:
|
|
120
|
+
raise SystemExit(
|
|
121
|
+
"✗ No stored API key, please call: "
|
|
122
|
+
"`lamin login` or `lamin login <your-email> --key <API-key>`"
|
|
123
|
+
)
|
|
124
|
+
elif user_settings.email is None:
|
|
125
|
+
raise SystemExit(f"✗ No stored user email, please call: lamin login {user}")
|
|
126
|
+
else:
|
|
127
|
+
user_settings = UserSettings(handle="temporary", uid="null")
|
|
128
|
+
|
|
129
|
+
from .core._hub_core import sign_in_hub, sign_in_hub_api_key
|
|
130
|
+
|
|
131
|
+
if api_key is None:
|
|
132
|
+
response = sign_in_hub(
|
|
133
|
+
user_settings.email, # type: ignore
|
|
134
|
+
user_settings.password, # type: ignore
|
|
135
|
+
user_settings.handle,
|
|
136
|
+
)
|
|
137
|
+
else:
|
|
138
|
+
response = sign_in_hub_api_key(api_key)
|
|
139
|
+
user_settings.password = None
|
|
140
|
+
|
|
141
|
+
if isinstance(response, Exception):
|
|
142
|
+
raise response
|
|
143
|
+
elif isinstance(response, str):
|
|
144
|
+
raise SystemExit(f"✗ Unsuccessful login: {response}.")
|
|
145
|
+
else:
|
|
146
|
+
user_uuid, user_id, user_handle, user_name, access_token = response
|
|
147
|
+
|
|
148
|
+
if api_key is not None:
|
|
149
|
+
logger.success(f"logged in {user_handle}")
|
|
150
|
+
else: # legacy flow
|
|
151
|
+
logger.success(f"logged in with email {user_settings.email}")
|
|
152
|
+
|
|
153
|
+
user_settings.uid = user_id
|
|
154
|
+
user_settings.handle = user_handle
|
|
155
|
+
user_settings.name = user_name
|
|
156
|
+
user_settings._uuid = user_uuid
|
|
157
|
+
user_settings.access_token = access_token
|
|
158
|
+
user_settings.api_key = api_key
|
|
159
|
+
save_user_settings(user_settings)
|
|
160
|
+
|
|
161
|
+
if settings._instance_exists:
|
|
162
|
+
if (
|
|
163
|
+
isettings := settings.instance
|
|
164
|
+
).is_on_hub and previous_user_uid != user_settings.uid:
|
|
165
|
+
logger.important_hint(
|
|
166
|
+
f"consider re-connecting to update permissions: lamin connect {isettings.slug}"
|
|
167
|
+
)
|
|
168
|
+
if _check_instance_setup():
|
|
169
|
+
register_user(user_settings)
|
|
170
|
+
|
|
171
|
+
settings._user_settings = None
|
|
172
|
+
# aws s3 credentials are scoped to the user
|
|
173
|
+
reset_aws_options_cache()
|
|
174
|
+
return user_settings
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def logout():
|
|
178
|
+
"""Log out the current user.
|
|
179
|
+
|
|
180
|
+
This deletes the `~/.lamin/current_user.env` so that you'll no longer be automatically authenticated in the environment.
|
|
181
|
+
|
|
182
|
+
It keeps a copy as `~/.lamin/user--<user_handle>.env` so you can easily switch between user profiles.
|
|
183
|
+
|
|
184
|
+
See Also:
|
|
185
|
+
Logout via the CLI command `lamin logout`, see `here <https://docs.lamin.ai/cli#logout>`__.
|
|
186
|
+
"""
|
|
187
|
+
if current_user_settings_file().exists():
|
|
188
|
+
current_user_settings_file().unlink()
|
|
189
|
+
settings._user_settings = None
|
|
190
|
+
# aws s3 credentials are scoped to the user
|
|
191
|
+
reset_aws_options_cache()
|
|
192
|
+
logger.success("logged out")
|
|
193
|
+
else:
|
|
194
|
+
logger.important("already logged out")
|
|
195
|
+
if os.environ.get("LAMIN_API_KEY") is not None:
|
|
196
|
+
logger.warning(
|
|
197
|
+
"LAMIN_API_KEY is still set in your environment and will automatically log you in"
|
|
198
|
+
)
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import logging
|
|
4
|
-
|
|
5
|
-
silenced = False
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
# from https://github.com/boto/boto3/blob/8c6e641bed8130a9d8cb4d97b4acbe7aa0d0657a/boto3/__init__.py#L37
|
|
9
|
-
def set_stream_logger(name, level):
|
|
10
|
-
logger = logging.getLogger(name)
|
|
11
|
-
logger.setLevel(level)
|
|
12
|
-
handler = logging.StreamHandler()
|
|
13
|
-
handler.setLevel(level)
|
|
14
|
-
logger.addHandler(handler)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def silence_loggers():
|
|
18
|
-
global silenced
|
|
19
|
-
|
|
20
|
-
if not silenced:
|
|
21
|
-
# this gets logged 6 times
|
|
22
|
-
set_stream_logger(name="botocore.credentials", level=logging.WARNING)
|
|
23
|
-
set_stream_logger(name="botocore.hooks", level=logging.WARNING)
|
|
24
|
-
set_stream_logger(name="botocore.utils", level=logging.WARNING)
|
|
25
|
-
set_stream_logger(name="botocore.auth", level=logging.WARNING)
|
|
26
|
-
set_stream_logger(name="botocore.endpoint", level=logging.WARNING)
|
|
27
|
-
set_stream_logger(name="httpx", level=logging.WARNING)
|
|
28
|
-
set_stream_logger(name="httpcore", level=logging.WARNING)
|
|
29
|
-
set_stream_logger(name="hpack", level=logging.WARNING)
|
|
30
|
-
try:
|
|
31
|
-
import aiobotocore
|
|
32
|
-
|
|
33
|
-
# the 7th logging message of credentials came from aiobotocore
|
|
34
|
-
set_stream_logger(name="aiobotocore.credentials", level=logging.WARNING)
|
|
35
|
-
except ImportError:
|
|
36
|
-
pass
|
|
37
|
-
try:
|
|
38
|
-
# google also aggressively logs authentication related warnings
|
|
39
|
-
# in cases where users access public data
|
|
40
|
-
set_stream_logger(name="google.auth._default", level=logging.ERROR)
|
|
41
|
-
set_stream_logger(
|
|
42
|
-
name="google.auth.compute_engine._metadata", level=logging.ERROR
|
|
43
|
-
)
|
|
44
|
-
except Exception:
|
|
45
|
-
pass
|
|
46
|
-
silenced = True
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
silenced = False
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# from https://github.com/boto/boto3/blob/8c6e641bed8130a9d8cb4d97b4acbe7aa0d0657a/boto3/__init__.py#L37
|
|
9
|
+
def set_stream_logger(name, level):
|
|
10
|
+
logger = logging.getLogger(name)
|
|
11
|
+
logger.setLevel(level)
|
|
12
|
+
handler = logging.StreamHandler()
|
|
13
|
+
handler.setLevel(level)
|
|
14
|
+
logger.addHandler(handler)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def silence_loggers():
|
|
18
|
+
global silenced
|
|
19
|
+
|
|
20
|
+
if not silenced:
|
|
21
|
+
# this gets logged 6 times
|
|
22
|
+
set_stream_logger(name="botocore.credentials", level=logging.WARNING)
|
|
23
|
+
set_stream_logger(name="botocore.hooks", level=logging.WARNING)
|
|
24
|
+
set_stream_logger(name="botocore.utils", level=logging.WARNING)
|
|
25
|
+
set_stream_logger(name="botocore.auth", level=logging.WARNING)
|
|
26
|
+
set_stream_logger(name="botocore.endpoint", level=logging.WARNING)
|
|
27
|
+
set_stream_logger(name="httpx", level=logging.WARNING)
|
|
28
|
+
set_stream_logger(name="httpcore", level=logging.WARNING)
|
|
29
|
+
set_stream_logger(name="hpack", level=logging.WARNING)
|
|
30
|
+
try:
|
|
31
|
+
import aiobotocore
|
|
32
|
+
|
|
33
|
+
# the 7th logging message of credentials came from aiobotocore
|
|
34
|
+
set_stream_logger(name="aiobotocore.credentials", level=logging.WARNING)
|
|
35
|
+
except ImportError:
|
|
36
|
+
pass
|
|
37
|
+
try:
|
|
38
|
+
# google also aggressively logs authentication related warnings
|
|
39
|
+
# in cases where users access public data
|
|
40
|
+
set_stream_logger(name="google.auth._default", level=logging.ERROR)
|
|
41
|
+
set_stream_logger(
|
|
42
|
+
name="google.auth.compute_engine._metadata", level=logging.ERROR
|
|
43
|
+
)
|
|
44
|
+
except Exception:
|
|
45
|
+
pass
|
|
46
|
+
silenced = True
|