lightning-sdk 2025.12.9__py3-none-any.whl → 2025.12.17__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.
- lightning_sdk/__version__.py +1 -1
- lightning_sdk/api/job_api.py +16 -0
- lightning_sdk/api/org_api.py +7 -0
- lightning_sdk/api/studio_api.py +28 -3
- lightning_sdk/api/teamspace_api.py +42 -5
- lightning_sdk/api/user_api.py +5 -0
- lightning_sdk/cli/legacy/download.py +2 -1
- lightning_sdk/cli/legacy/studios_menu.py +8 -1
- lightning_sdk/job/base.py +26 -4
- lightning_sdk/job/job.py +16 -5
- lightning_sdk/job/v1.py +7 -2
- lightning_sdk/job/v2.py +41 -1
- lightning_sdk/lightning_cloud/openapi/__init__.py +26 -1
- lightning_sdk/lightning_cloud/openapi/api/__init__.py +1 -0
- lightning_sdk/lightning_cloud/openapi/api/cloud_space_service_api.py +5 -1
- lightning_sdk/lightning_cloud/openapi/api/cluster_service_api.py +517 -0
- lightning_sdk/lightning_cloud/openapi/api/data_connection_service_api.py +5 -1
- lightning_sdk/lightning_cloud/openapi/api/file_system_service_api.py +11 -11
- lightning_sdk/lightning_cloud/openapi/api/kubernetes_virtual_machine_service_api.py +557 -0
- lightning_sdk/lightning_cloud/openapi/api/storage_service_api.py +5 -1
- lightning_sdk/lightning_cloud/openapi/models/__init__.py +25 -1
- lightning_sdk/lightning_cloud/openapi/models/cloud_space_environment_template_service_update_cloud_space_environment_template_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/cluster_service_add_container_registry_body.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/cluster_service_create_machine_body.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/cluster_service_refresh_container_registry_credentials_body.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/cluster_service_validate_container_registry_body.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/kubernetes_virtual_machine_service_create_kubernetes_virtual_machine_body.py +513 -0
- lightning_sdk/lightning_cloud/openapi/models/kubernetes_virtual_machine_service_update_kubernetes_virtual_machine_body.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_add_container_registry_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_environment_template_config.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_cloud_space_specialized_view.py +1 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_container_registry.py +253 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_container_registry_info.py +281 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_container_registry_integration.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_container_registry_status.py +105 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_create_cloud_space_environment_template_request.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_delete_container_registry_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_delete_kubernetes_virtual_machine_response.py +97 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_ecr_registry_config.py +175 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_ecr_registry_config_input.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_ecr_registry_details.py +201 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_get_artifacts_page_response.py +29 -3
- lightning_sdk/lightning_cloud/openapi/models/v1_get_user_response.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_direct_v1.py +53 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_kubernetes_virtual_machine.py +383 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_kubevirt_config.py +305 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_kubevirt_provider_configuration.py +227 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_kubevirt_vm_configuration.py +149 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_kubevirt_vm_resources.py +201 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_container_registries_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_list_kubernetes_virtual_machines_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_machine.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_node_metrics.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_refresh_container_registry_credentials_response.py +123 -0
- lightning_sdk/lightning_cloud/openapi/models/v1_search_user.py +27 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +79 -1
- lightning_sdk/lightning_cloud/openapi/models/v1_validate_container_registry_response.py +149 -0
- lightning_sdk/lightning_cloud/openapi/rest.py +2 -2
- lightning_sdk/machine.py +1 -0
- lightning_sdk/mmt/base.py +26 -7
- lightning_sdk/mmt/mmt.py +11 -6
- lightning_sdk/mmt/v1.py +5 -2
- lightning_sdk/mmt/v2.py +5 -2
- lightning_sdk/organization.py +10 -1
- lightning_sdk/owner.py +4 -0
- lightning_sdk/pipeline/steps.py +3 -0
- lightning_sdk/plugin.py +2 -2
- lightning_sdk/studio.py +33 -2
- lightning_sdk/teamspace.py +44 -4
- lightning_sdk/user.py +22 -2
- lightning_sdk/utils/resolve.py +9 -7
- {lightning_sdk-2025.12.9.dist-info → lightning_sdk-2025.12.17.dist-info}/METADATA +1 -1
- {lightning_sdk-2025.12.9.dist-info → lightning_sdk-2025.12.17.dist-info}/RECORD +78 -53
- /lightning_sdk/lightning_cloud/openapi/models/{v1_list_filesystem_mm_ts_response.py → v1_list_filesystem_mmts_response.py} +0 -0
- {lightning_sdk-2025.12.9.dist-info → lightning_sdk-2025.12.17.dist-info}/LICENSE +0 -0
- {lightning_sdk-2025.12.9.dist-info → lightning_sdk-2025.12.17.dist-info}/WHEEL +0 -0
- {lightning_sdk-2025.12.9.dist-info → lightning_sdk-2025.12.17.dist-info}/entry_points.txt +0 -0
- {lightning_sdk-2025.12.9.dist-info → lightning_sdk-2025.12.17.dist-info}/top_level.txt +0 -0
lightning_sdk/organization.py
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
from typing import Optional
|
|
1
|
+
from typing import TYPE_CHECKING, Optional
|
|
2
2
|
|
|
3
3
|
from lightning_sdk.api import OrgApi
|
|
4
4
|
from lightning_sdk.owner import Owner
|
|
5
5
|
from lightning_sdk.utils.resolve import _resolve_org_name
|
|
6
6
|
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from lightning_sdk.teamspace import Teamspace
|
|
9
|
+
|
|
7
10
|
|
|
8
11
|
class Organization(Owner):
|
|
9
12
|
"""Represents an organization owner of teamspaces and studios.
|
|
@@ -44,6 +47,12 @@ class Organization(Owner):
|
|
|
44
47
|
def default_cloud_account(self) -> Optional[str]:
|
|
45
48
|
return self._org.preferred_cluster or None
|
|
46
49
|
|
|
50
|
+
def create_teamspace(self, name: str) -> "Teamspace":
|
|
51
|
+
from lightning_sdk.teamspace import Teamspace
|
|
52
|
+
|
|
53
|
+
self._org_api.create_teamspace(name, self.id)
|
|
54
|
+
return Teamspace(name=name, org=self)
|
|
55
|
+
|
|
47
56
|
def __repr__(self) -> str:
|
|
48
57
|
"""Returns reader friendly representation."""
|
|
49
58
|
return f"Organization(name={self.name})"
|
lightning_sdk/owner.py
CHANGED
|
@@ -24,6 +24,10 @@ class Owner(ABC, metaclass=TrackCallsABCMeta):
|
|
|
24
24
|
def id(self) -> str:
|
|
25
25
|
"""The owner's ID."""
|
|
26
26
|
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def create_teamspace(self, name: str) -> "Teamspace":
|
|
29
|
+
"""Creates a new teamspace."""
|
|
30
|
+
|
|
27
31
|
@property
|
|
28
32
|
def teamspaces(self) -> List["Teamspace"]:
|
|
29
33
|
"""All teamspaces by this owner."""
|
lightning_sdk/pipeline/steps.py
CHANGED
|
@@ -176,6 +176,7 @@ class JobStep:
|
|
|
176
176
|
max_runtime: Optional[int] = None,
|
|
177
177
|
wait_for: Union[str, List[str], None] = DEFAULT,
|
|
178
178
|
reuse_snapshot: bool = True,
|
|
179
|
+
scratch_disks: Optional[Dict[str, int]] = None,
|
|
179
180
|
) -> None:
|
|
180
181
|
self.name = name
|
|
181
182
|
self.machine = machine or Machine.CPU
|
|
@@ -203,6 +204,7 @@ class JobStep:
|
|
|
203
204
|
self.max_runtime = max_runtime
|
|
204
205
|
self.wait_for = wait_for
|
|
205
206
|
self.reuse_snapshot = reuse_snapshot
|
|
207
|
+
self.scratch_disks = scratch_disks
|
|
206
208
|
|
|
207
209
|
def to_proto(
|
|
208
210
|
self, teamspace: "Teamspace", cloud_account: str, shared_filesystem: Union[bool, V1SharedFilesystem]
|
|
@@ -242,6 +244,7 @@ class JobStep:
|
|
|
242
244
|
max_runtime=self.max_runtime,
|
|
243
245
|
machine_image_version=machine_image_version,
|
|
244
246
|
reuse_snapshot=self.reuse_snapshot,
|
|
247
|
+
scratch_disks=self.scratch_disks,
|
|
245
248
|
)
|
|
246
249
|
|
|
247
250
|
return V1PipelineStep(
|
lightning_sdk/plugin.py
CHANGED
|
@@ -411,12 +411,12 @@ class CustomPortPlugin(_Plugin):
|
|
|
411
411
|
if name is None:
|
|
412
412
|
name = _run_name("port")
|
|
413
413
|
|
|
414
|
-
return self._studio._studio_api.
|
|
414
|
+
return self._studio._studio_api.add_port(
|
|
415
415
|
teamspace_id=self._studio._teamspace.id,
|
|
416
416
|
studio_id=self._studio._studio.id,
|
|
417
417
|
name=name,
|
|
418
418
|
port=port,
|
|
419
|
-
)
|
|
419
|
+
).urls[0]
|
|
420
420
|
|
|
421
421
|
|
|
422
422
|
@runtime_checkable
|
lightning_sdk/studio.py
CHANGED
|
@@ -2,7 +2,7 @@ import glob
|
|
|
2
2
|
import os
|
|
3
3
|
import threading
|
|
4
4
|
import warnings
|
|
5
|
-
from typing import TYPE_CHECKING, Any, Dict, Mapping, Optional, Tuple, Union
|
|
5
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Mapping, Optional, Tuple, Union
|
|
6
6
|
|
|
7
7
|
from tqdm.auto import tqdm
|
|
8
8
|
|
|
@@ -12,7 +12,7 @@ from lightning_sdk.api.utils import AccessibleResource, raise_access_error_if_no
|
|
|
12
12
|
from lightning_sdk.base_studio import BaseStudio
|
|
13
13
|
from lightning_sdk.constants import _LIGHTNING_DEBUG
|
|
14
14
|
from lightning_sdk.exceptions import OutOfCapacityError
|
|
15
|
-
from lightning_sdk.lightning_cloud.openapi import V1ClusterType
|
|
15
|
+
from lightning_sdk.lightning_cloud.openapi import V1ClusterType, V1Endpoint
|
|
16
16
|
from lightning_sdk.machine import DEFAULT_MACHINE, CloudProvider, Machine
|
|
17
17
|
from lightning_sdk.organization import Organization
|
|
18
18
|
from lightning_sdk.owner import Owner
|
|
@@ -707,6 +707,37 @@ class Studio(metaclass=TrackCallsMeta):
|
|
|
707
707
|
interruptible=interruptible,
|
|
708
708
|
)
|
|
709
709
|
|
|
710
|
+
def add_ports(self, ports: Union[int, List[int], Dict[str, int]]) -> List[V1Endpoint]:
|
|
711
|
+
"""Add one or more ports to the studio and return their endpoints.
|
|
712
|
+
|
|
713
|
+
Args:
|
|
714
|
+
ports: Port to add. Can be:
|
|
715
|
+
- int: Single port (e.g., 8080)
|
|
716
|
+
- List[int]: Multiple ports ()
|
|
717
|
+
- dict[str, int]: Named ports (e.g., {"web": 8080})
|
|
718
|
+
|
|
719
|
+
Returns:
|
|
720
|
+
List of V1Endpoint objects. Access endpoint properties like:
|
|
721
|
+
- endpoint.name: Port name (None for unnamed ports)
|
|
722
|
+
- endpoint.ports: List of port numbers
|
|
723
|
+
- endpoint.urls: List of accessible URLs
|
|
724
|
+
"""
|
|
725
|
+
if isinstance(ports, dict):
|
|
726
|
+
port_items = ports.items()
|
|
727
|
+
elif isinstance(ports, list):
|
|
728
|
+
port_items = ((None, port) for port in ports)
|
|
729
|
+
else:
|
|
730
|
+
port_items = [(None, ports)]
|
|
731
|
+
|
|
732
|
+
return [
|
|
733
|
+
self._studio_api.add_port(self._teamspace.id, self._studio.id, name=name, port=port)
|
|
734
|
+
for name, port in port_items
|
|
735
|
+
]
|
|
736
|
+
|
|
737
|
+
def list_ports(self) -> List[V1Endpoint]:
|
|
738
|
+
"""List ports that are exposed in the Studio."""
|
|
739
|
+
return self._studio_api.list_ports(self._teamspace.id, self._studio.id)
|
|
740
|
+
|
|
710
741
|
def create_assistant(self, name: str, port: int) -> None:
|
|
711
742
|
assistant = self._studio_api.create_assistant(
|
|
712
743
|
studio_id=self._studio.id, teamspace_id=self._teamspace.id, port=port, assistant_name=name
|
lightning_sdk/teamspace.py
CHANGED
|
@@ -11,7 +11,12 @@ import lightning_sdk
|
|
|
11
11
|
from lightning_sdk.agents import Agent
|
|
12
12
|
from lightning_sdk.api import CloudAccountApi, TeamspaceApi
|
|
13
13
|
from lightning_sdk.api.utils import AccessibleResource, raise_access_error_if_not_allowed
|
|
14
|
-
from lightning_sdk.lightning_cloud.openapi import
|
|
14
|
+
from lightning_sdk.lightning_cloud.openapi import (
|
|
15
|
+
V1ClusterType,
|
|
16
|
+
V1Model,
|
|
17
|
+
V1ModelVersionArchive,
|
|
18
|
+
V1ProjectClusterBinding,
|
|
19
|
+
)
|
|
15
20
|
from lightning_sdk.machine import CloudProvider, Machine
|
|
16
21
|
from lightning_sdk.models import UploadedModelInfo
|
|
17
22
|
from lightning_sdk.organization import Organization
|
|
@@ -275,14 +280,48 @@ class Teamspace(metaclass=TrackCallsMeta):
|
|
|
275
280
|
|
|
276
281
|
self._teamspace_api.set_secret(self.id, key, value)
|
|
277
282
|
|
|
278
|
-
def list_machines(self, cloud_account: Optional[str] = None) -> List[Machine]:
|
|
283
|
+
def list_machines(self, cloud_account: Optional[str] = None, machine: Optional[str] = None) -> List[Machine]:
|
|
284
|
+
"""List available machines across cloud accounts.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
cloud_account: The cloud account from which to list available machines. If None, uses LIGHTNING_CLUSTER_ID
|
|
288
|
+
environment variable. If that's also None, queries all global cloud accounts.
|
|
289
|
+
machine: Specific machine name to filter by. If provided, only returns that
|
|
290
|
+
machine type. Must be a valid Machine enum value.
|
|
291
|
+
|
|
292
|
+
Returns:
|
|
293
|
+
List of available machines, excluding out-of-capacity machines.
|
|
294
|
+
"""
|
|
279
295
|
if cloud_account is None:
|
|
280
|
-
cloud_account = os.getenv("LIGHTNING_CLUSTER_ID")
|
|
296
|
+
cloud_account = os.getenv("LIGHTNING_CLUSTER_ID", None)
|
|
281
297
|
|
|
298
|
+
# if cloud_account is not given as a paramter and as a env var, use global cloud_accounts
|
|
282
299
|
if cloud_account is None:
|
|
300
|
+
global_cloud_accounts = self._cloud_account_api.list_global_cloud_accounts(teamspace_id=self.id)
|
|
301
|
+
cloud_accounts = [cm.id for cm in global_cloud_accounts]
|
|
302
|
+
else:
|
|
303
|
+
cloud_accounts = [cloud_account]
|
|
304
|
+
|
|
305
|
+
if cloud_accounts is None:
|
|
283
306
|
raise RuntimeError("Could not resolve cloud account")
|
|
284
307
|
|
|
285
|
-
|
|
308
|
+
if machine:
|
|
309
|
+
_machine_values = tuple(
|
|
310
|
+
[
|
|
311
|
+
machine.name
|
|
312
|
+
for machine in Machine.__dict__.values()
|
|
313
|
+
if isinstance(machine, Machine) and machine._include_in_cli
|
|
314
|
+
]
|
|
315
|
+
)
|
|
316
|
+
if machine not in _machine_values:
|
|
317
|
+
raise ValueError(f"Machine '{machine}' is not valid. Valid machines are: {_machine_values}")
|
|
318
|
+
machine = getattr(Machine, machine.upper(), Machine(machine, machine))
|
|
319
|
+
|
|
320
|
+
cloud_machines = self._teamspace_api.list_machines(
|
|
321
|
+
self.id, cloud_accounts=cloud_accounts, machine=machine, org_id=self._org.id
|
|
322
|
+
)
|
|
323
|
+
# filter out of capacity machines
|
|
324
|
+
cloud_machines = [cm for cm in cloud_machines if not cm.out_of_capacity]
|
|
286
325
|
return [
|
|
287
326
|
Machine(
|
|
288
327
|
name=cluster_machine.instance_id,
|
|
@@ -292,6 +331,7 @@ class Teamspace(metaclass=TrackCallsMeta):
|
|
|
292
331
|
accelerator_count=cluster_machine.resources.gpu or cluster_machine.resources.cpu,
|
|
293
332
|
cost=cluster_machine.cost,
|
|
294
333
|
interruptible_cost=cluster_machine.spot_price,
|
|
334
|
+
provider=cluster_machine.provider,
|
|
295
335
|
wait_time=float(cluster_machine.available_in_seconds) if cluster_machine.available_in_seconds else None,
|
|
296
336
|
interruptible_wait_time=float(cluster_machine.available_in_seconds_spot)
|
|
297
337
|
if cluster_machine.available_in_seconds_spot
|
lightning_sdk/user.py
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
from typing import Dict, Optional
|
|
1
|
+
from typing import TYPE_CHECKING, Dict, List, Optional
|
|
2
2
|
|
|
3
3
|
from lightning_sdk.api import UserApi
|
|
4
4
|
from lightning_sdk.owner import Owner
|
|
5
|
-
from lightning_sdk.utils.resolve import _resolve_user_name
|
|
5
|
+
from lightning_sdk.utils.resolve import _get_authed_user, _get_organizations_for_authed_user, _resolve_user_name
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from lightning_sdk.organization import Organization
|
|
9
|
+
from lightning_sdk.teamspace import Teamspace
|
|
6
10
|
|
|
7
11
|
|
|
8
12
|
class User(Owner):
|
|
@@ -55,6 +59,22 @@ class User(Owner):
|
|
|
55
59
|
|
|
56
60
|
self._user_api.set_secret(key, value)
|
|
57
61
|
|
|
62
|
+
def create_teamspace(self, name: str) -> "Teamspace":
|
|
63
|
+
from lightning_sdk.teamspace import Teamspace
|
|
64
|
+
|
|
65
|
+
if not _get_authed_user().id == self.id:
|
|
66
|
+
raise ValueError("Can only create teamspaces for currently authenticated user")
|
|
67
|
+
|
|
68
|
+
self._user_api.create_teamspace(name)
|
|
69
|
+
return Teamspace(name=name, user=self)
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def organizations(self) -> List["Organization"]:
|
|
73
|
+
if not _get_authed_user().id == self.id:
|
|
74
|
+
raise ValueError("Can only list organizations for currently authenticated user")
|
|
75
|
+
|
|
76
|
+
return _get_organizations_for_authed_user(user_api=self._user_api)
|
|
77
|
+
|
|
58
78
|
def __repr__(self) -> str:
|
|
59
79
|
"""Returns reader friendly representation."""
|
|
60
80
|
return f"User(name={self.name})"
|
lightning_sdk/utils/resolve.py
CHANGED
|
@@ -2,6 +2,7 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
import warnings
|
|
4
4
|
from contextlib import contextmanager
|
|
5
|
+
from functools import lru_cache
|
|
5
6
|
from typing import TYPE_CHECKING, Generator, List, Optional, Tuple, Union
|
|
6
7
|
|
|
7
8
|
from lightning_sdk.api import TeamspaceApi, UserApi
|
|
@@ -222,25 +223,26 @@ def _resolve_teamspace(
|
|
|
222
223
|
raise RuntimeError("Neither user nor org provided, but one of them needs to be provided")
|
|
223
224
|
|
|
224
225
|
|
|
225
|
-
def _get_organizations_for_authed_user() -> List["Organization"]:
|
|
226
|
+
def _get_organizations_for_authed_user(user_api: Optional[UserApi] = None) -> List["Organization"]:
|
|
226
227
|
"""Returns Organizations the current Authed user is a member of."""
|
|
227
228
|
from lightning_sdk.organization import Organization
|
|
228
229
|
|
|
229
|
-
_orgs = UserApi()._get_organizations_for_authed_user()
|
|
230
|
+
_orgs = (user_api or UserApi())._get_organizations_for_authed_user()
|
|
230
231
|
return [Organization(_org.name) for _org in _orgs]
|
|
231
232
|
|
|
232
233
|
|
|
233
|
-
def _get_teamspace_names_for_authed_user() -> List[str]:
|
|
234
|
+
def _get_teamspace_names_for_authed_user(user_api: Optional[UserApi] = None) -> List[str]:
|
|
234
235
|
"""Returns Teamspace's names the current Authed user is a member of."""
|
|
235
|
-
teamspaces = UserApi()._get_all_teamspace_memberships("")
|
|
236
|
+
teamspaces = (user_api or UserApi())._get_all_teamspace_memberships("")
|
|
236
237
|
return sorted([ts.name for ts in teamspaces])
|
|
237
238
|
|
|
238
239
|
|
|
239
|
-
|
|
240
|
+
@lru_cache(maxsize=1)
|
|
241
|
+
def _get_authed_user(user_api: Optional[UserApi] = None, teamspace_api: Optional[TeamspaceApi] = None) -> "User":
|
|
240
242
|
from lightning_sdk.user import User
|
|
241
243
|
|
|
242
|
-
user_id = TeamspaceApi()._get_authed_user_id()
|
|
243
|
-
_user = UserApi()._get_user_by_id(user_id)
|
|
244
|
+
user_id = (teamspace_api or TeamspaceApi())._get_authed_user_id()
|
|
245
|
+
_user = (user_api or UserApi())._get_user_by_id(user_id)
|
|
244
246
|
return User(name=_user.username)
|
|
245
247
|
|
|
246
248
|
|