proximl 0.5.17__tar.gz → 1.0.1__tar.gz
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.
- {proximl-0.5.17/proximl.egg-info → proximl-1.0.1}/PKG-INFO +2 -2
- {proximl-0.5.17 → proximl-1.0.1}/README.md +1 -1
- {proximl-0.5.17 → proximl-1.0.1}/examples/local_storage.py +0 -2
- {proximl-0.5.17 → proximl-1.0.1}/proximl/__init__.py +1 -1
- {proximl-0.5.17 → proximl-1.0.1}/proximl/checkpoints.py +56 -57
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/__init__.py +6 -3
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/checkpoint.py +18 -57
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/dataset.py +17 -57
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/job/__init__.py +89 -67
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/job/create.py +51 -24
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/model.py +14 -56
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/volume.py +18 -57
- {proximl-0.5.17 → proximl-1.0.1}/proximl/datasets.py +50 -55
- {proximl-0.5.17 → proximl-1.0.1}/proximl/jobs.py +269 -69
- {proximl-0.5.17 → proximl-1.0.1}/proximl/models.py +51 -55
- proximl-1.0.1/proximl/proximl.py +346 -0
- proximl-1.0.1/proximl/utils/__init__.py +1 -0
- {proximl-0.5.17/proximl → proximl-1.0.1/proximl/utils}/auth.py +4 -3
- proximl-1.0.1/proximl/utils/transfer.py +647 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/volumes.py +48 -53
- {proximl-0.5.17 → proximl-1.0.1/proximl.egg-info}/PKG-INFO +2 -2
- {proximl-0.5.17 → proximl-1.0.1}/proximl.egg-info/SOURCES.txt +7 -5
- {proximl-0.5.17 → proximl-1.0.1}/proximl.egg-info/requires.txt +1 -1
- {proximl-0.5.17 → proximl-1.0.1}/pyproject.toml +1 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/test_checkpoints_integration.py +4 -3
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/test_datasets_integration.py +5 -3
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/test_jobs_integration.py +33 -27
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/test_models_integration.py +7 -3
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/test_volumes_integration.py +2 -2
- proximl-1.0.1/tests/unit/cli/test_cli_checkpoint_unit.py +333 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cloudbender/test_nodes_unit.py +112 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cloudbender/test_providers_unit.py +96 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cloudbender/test_regions_unit.py +106 -0
- proximl-1.0.1/tests/unit/cloudbender/test_services_unit.py +308 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/conftest.py +23 -10
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/projects/test_project_data_connectors_unit.py +39 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/projects/test_project_datastores_unit.py +37 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/projects/test_project_members_unit.py +46 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/projects/test_project_services_unit.py +65 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/projects/test_projects_unit.py +16 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/test_auth_unit.py +17 -2
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/test_checkpoints_unit.py +256 -71
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/test_datasets_unit.py +218 -68
- proximl-1.0.1/tests/unit/test_exceptions.py +164 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/test_gpu_types_unit.py +11 -1
- proximl-1.0.1/tests/unit/test_jobs_unit.py +1749 -0
- proximl-1.0.1/tests/unit/test_main_unit.py +20 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/test_models_unit.py +218 -70
- proximl-1.0.1/tests/unit/test_proximl_unit.py +678 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/test_volumes_unit.py +211 -70
- proximl-1.0.1/tests/unit/utils/__init__.py +1 -0
- proximl-1.0.1/tests/unit/utils/test_transfer_unit.py +4260 -0
- proximl-0.5.17/proximl/cli/connection.py +0 -61
- proximl-0.5.17/proximl/connections.py +0 -621
- proximl-0.5.17/proximl/proximl.py +0 -301
- proximl-0.5.17/tests/unit/cli/test_cli_checkpoint_unit.py +0 -22
- proximl-0.5.17/tests/unit/cloudbender/test_services_unit.py +0 -167
- proximl-0.5.17/tests/unit/test_connections_unit.py +0 -182
- proximl-0.5.17/tests/unit/test_exceptions.py +0 -31
- proximl-0.5.17/tests/unit/test_jobs_unit.py +0 -830
- proximl-0.5.17/tests/unit/test_proximl_unit.py +0 -54
- {proximl-0.5.17 → proximl-1.0.1}/LICENSE +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/examples/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/examples/create_dataset_and_training_job.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/examples/training_inference_pipeline.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/__main__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/cloudbender/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/cloudbender/data_connector.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/cloudbender/datastore.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/cloudbender/device.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/cloudbender/node.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/cloudbender/provider.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/cloudbender/region.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/cloudbender/service.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/environment.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/gpu.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/project/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/project/credential.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/project/data_connector.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/project/datastore.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/project/secret.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cli/project/service.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cloudbender/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cloudbender/cloudbender.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cloudbender/data_connectors.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cloudbender/datastores.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cloudbender/device_configs.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cloudbender/devices.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cloudbender/nodes.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cloudbender/providers.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cloudbender/regions.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/cloudbender/services.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/environments.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/exceptions.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/gpu_types.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/projects/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/projects/credentials.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/projects/data_connectors.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/projects/datastores.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/projects/members.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/projects/projects.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/projects/secrets.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl/projects/services.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl.egg-info/dependency_links.txt +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl.egg-info/entry_points.txt +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/proximl.egg-info/top_level.txt +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/setup.cfg +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/setup.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/cloudbender/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/cloudbender/conftest.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/cloudbender/test_providers_integration.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/cloudbender/test_regions_integration.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/cloudbender/test_services_integration.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/conftest.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/projects/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/projects/conftest.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/projects/test_projects_credentials_integration.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/projects/test_projects_data_connectors_integration.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/projects/test_projects_datastores_integration.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/projects/test_projects_integration.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/projects/test_projects_members_integration.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/projects/test_projects_secrets_integration.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/projects/test_projects_services_integration.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/test_environments_integration.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/integration/test_gpu_types_integration.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/cloudbender/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/cloudbender/test_cli_datastore_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/cloudbender/test_cli_device_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/cloudbender/test_cli_node_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/cloudbender/test_cli_provider_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/cloudbender/test_cli_region_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/cloudbender/test_cli_service_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/conftest.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/projects/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/projects/test_cli_project_credential_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/projects/test_cli_project_data_connector_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/projects/test_cli_project_datastore_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/projects/test_cli_project_secret_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/projects/test_cli_project_service_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/projects/test_cli_project_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/test_cli_datasets_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/test_cli_environment_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/test_cli_gpu_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/test_cli_job_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/test_cli_model_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cli/test_cli_volume_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cloudbender/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cloudbender/test_data_connectors_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cloudbender/test_datastores_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cloudbender/test_device_configs_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/cloudbender/test_devices_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/projects/__init__.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/projects/test_project_credentials_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/projects/test_project_secrets_unit.py +0 -0
- {proximl-0.5.17 → proximl-1.0.1}/tests/unit/test_environments_unit.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: proximl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: proxiML client SDK and command line utilities
|
|
5
5
|
Home-page: https://github.com/proxiML/python-sdk
|
|
6
6
|
Author: proxiML
|
|
@@ -177,7 +177,7 @@ Description: <div align="center">
|
|
|
177
177
|
proximl dataset list
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
-
To connect to a job that
|
|
180
|
+
To connect to a job that uses the "local" file transfer method:
|
|
181
181
|
|
|
182
182
|
```
|
|
183
183
|
proximl job connect <job ID or name>
|
|
@@ -169,7 +169,7 @@ To list all datasets:
|
|
|
169
169
|
proximl dataset list
|
|
170
170
|
```
|
|
171
171
|
|
|
172
|
-
To connect to a job that
|
|
172
|
+
To connect to a job that uses the "local" file transfer method:
|
|
173
173
|
|
|
174
174
|
```
|
|
175
175
|
proximl job connect <job ID or name>
|
|
@@ -19,7 +19,6 @@ async def create_dataset():
|
|
|
19
19
|
attach_task = asyncio.create_task(dataset.attach())
|
|
20
20
|
connect_task = asyncio.create_task(dataset.connect())
|
|
21
21
|
await asyncio.gather(attach_task, connect_task)
|
|
22
|
-
await dataset.disconnect()
|
|
23
22
|
return dataset
|
|
24
23
|
|
|
25
24
|
|
|
@@ -55,7 +54,6 @@ async def run_job(dataset):
|
|
|
55
54
|
await asyncio.gather(attach_task, connect_task)
|
|
56
55
|
|
|
57
56
|
# Cleanup job
|
|
58
|
-
await job.disconnect()
|
|
59
57
|
await job.remove()
|
|
60
58
|
|
|
61
59
|
|
|
@@ -10,7 +10,7 @@ from .exceptions import (
|
|
|
10
10
|
SpecificationError,
|
|
11
11
|
ProxiMLException,
|
|
12
12
|
)
|
|
13
|
-
from .
|
|
13
|
+
from proximl.utils.transfer import upload, download
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class Checkpoints(object):
|
|
@@ -23,7 +23,9 @@ class Checkpoints(object):
|
|
|
23
23
|
|
|
24
24
|
async def list(self, **kwargs):
|
|
25
25
|
resp = await self.proximl._query(f"/checkpoint", "GET", kwargs)
|
|
26
|
-
checkpoints = [
|
|
26
|
+
checkpoints = [
|
|
27
|
+
Checkpoint(self.proximl, **checkpoint) for checkpoint in resp
|
|
28
|
+
]
|
|
27
29
|
return checkpoints
|
|
28
30
|
|
|
29
31
|
async def list_public(self, **kwargs):
|
|
@@ -68,13 +70,17 @@ class Checkpoint:
|
|
|
68
70
|
def __init__(self, proximl, **kwargs):
|
|
69
71
|
self.proximl = proximl
|
|
70
72
|
self._checkpoint = kwargs
|
|
71
|
-
self._id = self._checkpoint.get(
|
|
73
|
+
self._id = self._checkpoint.get(
|
|
74
|
+
"id", self._checkpoint.get("checkpoint_uuid")
|
|
75
|
+
)
|
|
72
76
|
self._status = self._checkpoint.get("status")
|
|
73
77
|
self._name = self._checkpoint.get("name")
|
|
74
|
-
self._size = self._checkpoint.get("size") or self._checkpoint.get(
|
|
75
|
-
|
|
76
|
-
"size"
|
|
78
|
+
self._size = self._checkpoint.get("size") or self._checkpoint.get(
|
|
79
|
+
"used_size"
|
|
77
80
|
)
|
|
81
|
+
self._billed_size = self._checkpoint.get(
|
|
82
|
+
"billed_size"
|
|
83
|
+
) or self._checkpoint.get("size")
|
|
78
84
|
self._project_uuid = self._checkpoint.get("project_uuid")
|
|
79
85
|
|
|
80
86
|
@property
|
|
@@ -122,56 +128,45 @@ class Checkpoint:
|
|
|
122
128
|
)
|
|
123
129
|
return resp
|
|
124
130
|
|
|
125
|
-
async def get_connection_utility_url(self):
|
|
126
|
-
resp = await self.proximl._query(
|
|
127
|
-
f"/checkpoint/{self._id}/download",
|
|
128
|
-
"GET",
|
|
129
|
-
dict(project_uuid=self._project_uuid),
|
|
130
|
-
)
|
|
131
|
-
return resp
|
|
132
|
-
|
|
133
|
-
def get_connection_details(self):
|
|
134
|
-
if self._checkpoint.get("vpn"):
|
|
135
|
-
details = dict(
|
|
136
|
-
entity_type="checkpoint",
|
|
137
|
-
project_uuid=self._checkpoint.get("project_uuid"),
|
|
138
|
-
cidr=self._checkpoint.get("vpn").get("cidr"),
|
|
139
|
-
ssh_port=self._checkpoint.get("vpn").get("client").get("ssh_port"),
|
|
140
|
-
input_path=(
|
|
141
|
-
self._checkpoint.get("source_uri")
|
|
142
|
-
if self.status in ["new", "downloading"]
|
|
143
|
-
else None
|
|
144
|
-
),
|
|
145
|
-
output_path=(
|
|
146
|
-
self._checkpoint.get("output_uri")
|
|
147
|
-
if self.status == "exporting"
|
|
148
|
-
else None
|
|
149
|
-
),
|
|
150
|
-
)
|
|
151
|
-
else:
|
|
152
|
-
details = dict()
|
|
153
|
-
return details
|
|
154
|
-
|
|
155
131
|
async def connect(self):
|
|
156
|
-
if self.status in ["
|
|
157
|
-
|
|
158
|
-
"
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
self.proximl, entity_type="checkpoint", id=self.id, entity=self
|
|
165
|
-
)
|
|
166
|
-
await connection.start()
|
|
167
|
-
return connection.status
|
|
132
|
+
if self.status not in ["downloading", "exporting"]:
|
|
133
|
+
if self.status == "new":
|
|
134
|
+
await self.wait_for("downloading")
|
|
135
|
+
else:
|
|
136
|
+
raise SpecificationError(
|
|
137
|
+
"status",
|
|
138
|
+
f"You can only connect to downloading or exporting checkpoints.",
|
|
139
|
+
)
|
|
168
140
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
141
|
+
# Refresh to get latest entity data
|
|
142
|
+
await self.refresh()
|
|
143
|
+
|
|
144
|
+
if self.status == "downloading":
|
|
145
|
+
# Upload task - get auth_token, hostname, and source_uri from checkpoint
|
|
146
|
+
auth_token = self._checkpoint.get("auth_token")
|
|
147
|
+
hostname = self._checkpoint.get("hostname")
|
|
148
|
+
source_uri = self._checkpoint.get("source_uri")
|
|
149
|
+
|
|
150
|
+
if not auth_token or not hostname or not source_uri:
|
|
151
|
+
raise SpecificationError(
|
|
152
|
+
"status",
|
|
153
|
+
f"Checkpoint in downloading status missing required connection properties (auth_token, hostname, source_uri).",
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
await upload(hostname, auth_token, source_uri)
|
|
157
|
+
elif self.status == "exporting":
|
|
158
|
+
# Download task - get auth_token, hostname, and output_uri from checkpoint
|
|
159
|
+
auth_token = self._checkpoint.get("auth_token")
|
|
160
|
+
hostname = self._checkpoint.get("hostname")
|
|
161
|
+
output_uri = self._checkpoint.get("output_uri")
|
|
162
|
+
|
|
163
|
+
if not auth_token or not hostname or not output_uri:
|
|
164
|
+
raise SpecificationError(
|
|
165
|
+
"status",
|
|
166
|
+
f"Checkpoint in exporting status missing required connection properties (auth_token, hostname, output_uri).",
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
await download(hostname, auth_token, output_uri)
|
|
175
170
|
|
|
176
171
|
async def remove(self, force=False):
|
|
177
172
|
await self.proximl._query(
|
|
@@ -210,7 +205,9 @@ class Checkpoint:
|
|
|
210
205
|
if msg_handler:
|
|
211
206
|
msg_handler(data)
|
|
212
207
|
else:
|
|
213
|
-
timestamp = datetime.fromtimestamp(
|
|
208
|
+
timestamp = datetime.fromtimestamp(
|
|
209
|
+
int(data.get("time")) / 1000
|
|
210
|
+
)
|
|
214
211
|
print(
|
|
215
212
|
f"{timestamp.strftime('%m/%d/%Y, %H:%M:%S')}: {data.get('msg').rstrip()}"
|
|
216
213
|
)
|
|
@@ -239,7 +236,7 @@ class Checkpoint:
|
|
|
239
236
|
async def wait_for(self, status, timeout=300):
|
|
240
237
|
if self.status == status:
|
|
241
238
|
return
|
|
242
|
-
valid_statuses = ["downloading", "ready", "archived"]
|
|
239
|
+
valid_statuses = ["downloading", "ready", "exporting", "archived"]
|
|
243
240
|
if not status in valid_statuses:
|
|
244
241
|
raise SpecificationError(
|
|
245
242
|
"status",
|
|
@@ -254,7 +251,9 @@ class Checkpoint:
|
|
|
254
251
|
)
|
|
255
252
|
POLL_INTERVAL_MIN = 5
|
|
256
253
|
POLL_INTERVAL_MAX = 60
|
|
257
|
-
POLL_INTERVAL = max(
|
|
254
|
+
POLL_INTERVAL = max(
|
|
255
|
+
min(timeout / 60, POLL_INTERVAL_MAX), POLL_INTERVAL_MIN
|
|
256
|
+
)
|
|
258
257
|
retry_count = math.ceil(timeout / POLL_INTERVAL)
|
|
259
258
|
count = 0
|
|
260
259
|
while count < retry_count:
|
|
@@ -142,7 +142,9 @@ def configure(config):
|
|
|
142
142
|
project for project in projects if project.id == active_project_id
|
|
143
143
|
]
|
|
144
144
|
|
|
145
|
-
active_project_name =
|
|
145
|
+
active_project_name = (
|
|
146
|
+
active_project[0].name if len(active_project) else "UNSET"
|
|
147
|
+
)
|
|
146
148
|
|
|
147
149
|
click.echo(f"Current Active Project: {active_project_name}")
|
|
148
150
|
|
|
@@ -152,11 +154,12 @@ def configure(config):
|
|
|
152
154
|
show_choices=True,
|
|
153
155
|
default=active_project_name,
|
|
154
156
|
)
|
|
155
|
-
selected_project = [
|
|
157
|
+
selected_project = [
|
|
158
|
+
project for project in projects if project.name == name
|
|
159
|
+
]
|
|
156
160
|
config.proximl.client.set_active_project(selected_project[0].id)
|
|
157
161
|
|
|
158
162
|
|
|
159
|
-
from proximl.cli.connection import connection
|
|
160
163
|
from proximl.cli.dataset import dataset
|
|
161
164
|
from proximl.cli.model import model
|
|
162
165
|
from proximl.cli.checkpoint import checkpoint
|
|
@@ -35,15 +35,7 @@ def attach(config, checkpoint):
|
|
|
35
35
|
if None is found:
|
|
36
36
|
raise click.UsageError("Cannot find specified checkpoint.")
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
config.proximl.run(found.attach())
|
|
40
|
-
return config.proximl.run(found.disconnect())
|
|
41
|
-
except:
|
|
42
|
-
try:
|
|
43
|
-
config.proximl.run(found.disconnect())
|
|
44
|
-
except:
|
|
45
|
-
pass
|
|
46
|
-
raise
|
|
38
|
+
config.proximl.run(found.attach())
|
|
47
39
|
|
|
48
40
|
|
|
49
41
|
@checkpoint.command()
|
|
@@ -67,18 +59,10 @@ def connect(config, checkpoint, attach):
|
|
|
67
59
|
if None is found:
|
|
68
60
|
raise click.UsageError("Cannot find specified checkpoint.")
|
|
69
61
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
else:
|
|
75
|
-
return config.proximl.run(found.connect())
|
|
76
|
-
except:
|
|
77
|
-
try:
|
|
78
|
-
config.proximl.run(found.disconnect())
|
|
79
|
-
except:
|
|
80
|
-
pass
|
|
81
|
-
raise
|
|
62
|
+
if attach:
|
|
63
|
+
config.proximl.run(found.connect(), found.attach())
|
|
64
|
+
else:
|
|
65
|
+
config.proximl.run(found.connect())
|
|
82
66
|
|
|
83
67
|
|
|
84
68
|
@checkpoint.command()
|
|
@@ -123,41 +107,15 @@ def create(config, attach, connect, source, name, path):
|
|
|
123
107
|
)
|
|
124
108
|
)
|
|
125
109
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
"No logs to show for local sourced checkpoint without connect."
|
|
136
|
-
)
|
|
137
|
-
except:
|
|
138
|
-
try:
|
|
139
|
-
config.proximl.run(checkpoint.disconnect())
|
|
140
|
-
except:
|
|
141
|
-
pass
|
|
142
|
-
raise
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
@checkpoint.command()
|
|
146
|
-
@click.argument("checkpoint", type=click.STRING)
|
|
147
|
-
@pass_config
|
|
148
|
-
def disconnect(config, checkpoint):
|
|
149
|
-
"""
|
|
150
|
-
Disconnect and clean-up checkpoint upload.
|
|
151
|
-
|
|
152
|
-
CHECKPOINT may be specified by name or ID, but ID is preferred.
|
|
153
|
-
"""
|
|
154
|
-
checkpoints = config.proximl.run(config.proximl.client.checkpoints.list())
|
|
155
|
-
|
|
156
|
-
found = search_by_id_name(checkpoint, checkpoints)
|
|
157
|
-
if None is found:
|
|
158
|
-
raise click.UsageError("Cannot find specified checkpoint.")
|
|
159
|
-
|
|
160
|
-
return config.proximl.run(found.disconnect())
|
|
110
|
+
if connect and attach:
|
|
111
|
+
config.proximl.run(checkpoint.attach(), checkpoint.connect())
|
|
112
|
+
elif connect:
|
|
113
|
+
config.proximl.run(checkpoint.connect())
|
|
114
|
+
else:
|
|
115
|
+
raise click.UsageError(
|
|
116
|
+
"Abort!\n"
|
|
117
|
+
"No logs to show for local sourced checkpoint without connect."
|
|
118
|
+
)
|
|
161
119
|
|
|
162
120
|
|
|
163
121
|
@checkpoint.command()
|
|
@@ -236,7 +194,10 @@ def remove(config, checkpoint, force):
|
|
|
236
194
|
found = search_by_id_name(checkpoint, checkpoints)
|
|
237
195
|
if None is found:
|
|
238
196
|
if force:
|
|
239
|
-
config.proximl.run(
|
|
197
|
+
config.proximl.run(
|
|
198
|
+
config.proximl.client.checkpoints.remove(checkpoint)
|
|
199
|
+
)
|
|
200
|
+
return
|
|
240
201
|
else:
|
|
241
202
|
raise click.UsageError("Cannot find specified checkpoint.")
|
|
242
203
|
|
|
@@ -35,15 +35,7 @@ def attach(config, dataset):
|
|
|
35
35
|
if None is found:
|
|
36
36
|
raise click.UsageError("Cannot find specified dataset.")
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
config.proximl.run(found.attach())
|
|
40
|
-
return config.proximl.run(found.disconnect())
|
|
41
|
-
except:
|
|
42
|
-
try:
|
|
43
|
-
config.proximl.run(found.disconnect())
|
|
44
|
-
except:
|
|
45
|
-
pass
|
|
46
|
-
raise
|
|
38
|
+
config.proximl.run(found.attach())
|
|
47
39
|
|
|
48
40
|
|
|
49
41
|
@dataset.command()
|
|
@@ -67,18 +59,10 @@ def connect(config, dataset, attach):
|
|
|
67
59
|
if None is found:
|
|
68
60
|
raise click.UsageError("Cannot find specified dataset.")
|
|
69
61
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
else:
|
|
75
|
-
return config.proximl.run(found.connect())
|
|
76
|
-
except:
|
|
77
|
-
try:
|
|
78
|
-
config.proximl.run(found.disconnect())
|
|
79
|
-
except:
|
|
80
|
-
pass
|
|
81
|
-
raise
|
|
62
|
+
if attach:
|
|
63
|
+
config.proximl.run(found.connect(), found.attach())
|
|
64
|
+
else:
|
|
65
|
+
config.proximl.run(found.connect())
|
|
82
66
|
|
|
83
67
|
|
|
84
68
|
@dataset.command()
|
|
@@ -123,41 +107,15 @@ def create(config, attach, connect, source, name, path):
|
|
|
123
107
|
)
|
|
124
108
|
)
|
|
125
109
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
"No logs to show for local sourced dataset without connect."
|
|
136
|
-
)
|
|
137
|
-
except:
|
|
138
|
-
try:
|
|
139
|
-
config.proximl.run(dataset.disconnect())
|
|
140
|
-
except:
|
|
141
|
-
pass
|
|
142
|
-
raise
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
@dataset.command()
|
|
146
|
-
@click.argument("dataset", type=click.STRING)
|
|
147
|
-
@pass_config
|
|
148
|
-
def disconnect(config, dataset):
|
|
149
|
-
"""
|
|
150
|
-
Disconnect and clean-up dataset upload.
|
|
151
|
-
|
|
152
|
-
DATASET may be specified by name or ID, but ID is preferred.
|
|
153
|
-
"""
|
|
154
|
-
datasets = config.proximl.run(config.proximl.client.datasets.list())
|
|
155
|
-
|
|
156
|
-
found = search_by_id_name(dataset, datasets)
|
|
157
|
-
if None is found:
|
|
158
|
-
raise click.UsageError("Cannot find specified dataset.")
|
|
159
|
-
|
|
160
|
-
return config.proximl.run(found.disconnect())
|
|
110
|
+
if connect and attach:
|
|
111
|
+
config.proximl.run(dataset.attach(), dataset.connect())
|
|
112
|
+
elif connect:
|
|
113
|
+
config.proximl.run(dataset.connect())
|
|
114
|
+
else:
|
|
115
|
+
raise click.UsageError(
|
|
116
|
+
"Abort!\n"
|
|
117
|
+
"No logs to show for local sourced dataset without connect."
|
|
118
|
+
)
|
|
161
119
|
|
|
162
120
|
|
|
163
121
|
@dataset.command()
|
|
@@ -252,7 +210,9 @@ def rename(config, dataset, name):
|
|
|
252
210
|
DATASET may be specified by name or ID, but ID is preferred.
|
|
253
211
|
"""
|
|
254
212
|
try:
|
|
255
|
-
dataset = config.proximl.run(
|
|
213
|
+
dataset = config.proximl.run(
|
|
214
|
+
config.proximl.client.datasets.get(dataset)
|
|
215
|
+
)
|
|
256
216
|
if dataset is None:
|
|
257
217
|
raise click.UsageError("Cannot find specified dataset.")
|
|
258
218
|
except:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
import click
|
|
2
3
|
from webbrowser import open as browse
|
|
3
4
|
from proximl.cli import cli, pass_config, search_by_id_name
|
|
@@ -25,90 +26,111 @@ def attach(config, job):
|
|
|
25
26
|
if None is found:
|
|
26
27
|
raise click.UsageError("Cannot find specified job.")
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
config.proximl.run(found.attach())
|
|
30
|
-
return config.proximl.run(found.disconnect())
|
|
31
|
-
except:
|
|
32
|
-
try:
|
|
33
|
-
config.proximl.run(found.disconnect())
|
|
34
|
-
except:
|
|
35
|
-
pass
|
|
36
|
-
raise
|
|
29
|
+
config.proximl.run(found.attach())
|
|
37
30
|
|
|
38
31
|
|
|
39
|
-
|
|
40
|
-
@click.option(
|
|
41
|
-
"--attach/--no-attach",
|
|
42
|
-
default=True,
|
|
43
|
-
show_default=True,
|
|
44
|
-
help="Auto attach to job.",
|
|
45
|
-
)
|
|
46
|
-
@click.argument("job", type=click.STRING)
|
|
47
|
-
@pass_config
|
|
48
|
-
def connect(config, job, attach):
|
|
32
|
+
async def _connect_job(job, attach, config):
|
|
49
33
|
"""
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
JOB may be specified by name or ID, but ID is preferred.
|
|
34
|
+
Async helper function to handle job connection with proper
|
|
35
|
+
handling of local input/output types and attach task management.
|
|
53
36
|
"""
|
|
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
|
-
|
|
93
|
-
|
|
37
|
+
# Get job properties
|
|
38
|
+
model = job._job.get("model", {})
|
|
39
|
+
data = job._job.get("data", {})
|
|
40
|
+
model_local = model.get("source_type") == "local"
|
|
41
|
+
data_local = data.get("input_type") == "local"
|
|
42
|
+
output_local = data.get("output_type") == "local"
|
|
43
|
+
early_statuses = [
|
|
44
|
+
"new",
|
|
45
|
+
"waiting for data/model download",
|
|
46
|
+
"waiting for GPUs",
|
|
47
|
+
"waiting for resources",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
# Check if we need to wait for data/model download
|
|
51
|
+
# Only wait if status is early AND (data or model is local)
|
|
52
|
+
needs_upload_wait = job.status in early_statuses and (
|
|
53
|
+
model_local or data_local
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
if needs_upload_wait:
|
|
57
|
+
# Wait for job to reach data/model download status
|
|
58
|
+
await job.wait_for("waiting for data/model download", 3600)
|
|
59
|
+
await job.refresh()
|
|
60
|
+
|
|
61
|
+
# Start attach task early if requested
|
|
62
|
+
attach_task = None
|
|
63
|
+
if attach:
|
|
64
|
+
attach_task = asyncio.create_task(job.attach())
|
|
65
|
+
|
|
66
|
+
# Run first connect (upload if needed)
|
|
67
|
+
await job.connect()
|
|
68
|
+
|
|
69
|
+
# For notebook jobs, handle opening
|
|
70
|
+
if job.type == "notebook":
|
|
71
|
+
# Refresh to get latest status after connect
|
|
72
|
+
await job.refresh()
|
|
73
|
+
|
|
74
|
+
if job.status in early_statuses:
|
|
75
|
+
if attach_task:
|
|
76
|
+
await attach_task
|
|
77
|
+
click.echo("Launching...", file=config.stdout)
|
|
78
|
+
browse(job.notebook_url)
|
|
79
|
+
return
|
|
80
|
+
elif job.status not in [
|
|
94
81
|
"starting",
|
|
95
82
|
"running",
|
|
96
83
|
"reinitializing",
|
|
97
84
|
"copying",
|
|
98
85
|
]:
|
|
86
|
+
if attach_task:
|
|
87
|
+
attach_task.cancel()
|
|
99
88
|
raise click.UsageError("Notebook job not running.")
|
|
100
89
|
else:
|
|
101
|
-
|
|
90
|
+
await job.wait_for("running")
|
|
91
|
+
if attach_task:
|
|
92
|
+
await attach_task
|
|
102
93
|
click.echo("Launching...", file=config.stdout)
|
|
103
|
-
browse(
|
|
94
|
+
browse(job.notebook_url)
|
|
95
|
+
return
|
|
96
|
+
|
|
97
|
+
# For non-notebook jobs, check if we need second connect (download)
|
|
98
|
+
# Refresh to get latest status after first connect
|
|
99
|
+
await job.refresh()
|
|
100
|
+
|
|
101
|
+
# Run second connect if output_type is local
|
|
102
|
+
# (as per user's requirement: "if the output_type is 'local'")
|
|
103
|
+
if output_local:
|
|
104
|
+
# Always wait for running status before second connect
|
|
105
|
+
# (as shown in user's example)
|
|
106
|
+
await job.wait_for("running", 3600)
|
|
107
|
+
await job.refresh()
|
|
108
|
+
|
|
109
|
+
# Create second connect task (download)
|
|
110
|
+
connect_task = asyncio.create_task(job.connect())
|
|
111
|
+
|
|
112
|
+
# Gather both attach and second connect tasks
|
|
113
|
+
if attach_task:
|
|
114
|
+
await asyncio.gather(attach_task, connect_task)
|
|
115
|
+
else:
|
|
116
|
+
await connect_task
|
|
117
|
+
elif attach_task:
|
|
118
|
+
# Just wait for attach if no second connect needed
|
|
119
|
+
await attach_task
|
|
104
120
|
|
|
105
121
|
|
|
106
122
|
@job.command()
|
|
123
|
+
@click.option(
|
|
124
|
+
"--attach/--no-attach",
|
|
125
|
+
default=True,
|
|
126
|
+
show_default=True,
|
|
127
|
+
help="Auto attach to job.",
|
|
128
|
+
)
|
|
107
129
|
@click.argument("job", type=click.STRING)
|
|
108
130
|
@pass_config
|
|
109
|
-
def
|
|
131
|
+
def connect(config, job, attach):
|
|
110
132
|
"""
|
|
111
|
-
|
|
133
|
+
Connect to job.
|
|
112
134
|
|
|
113
135
|
JOB may be specified by name or ID, but ID is preferred.
|
|
114
136
|
"""
|
|
@@ -118,7 +140,7 @@ def disconnect(config, job):
|
|
|
118
140
|
if None is found:
|
|
119
141
|
raise click.UsageError("Cannot find specified job.")
|
|
120
142
|
|
|
121
|
-
|
|
143
|
+
config.proximl.run(_connect_job(found, attach, config))
|
|
122
144
|
|
|
123
145
|
|
|
124
146
|
@job.command()
|