pybiolib 1.2.876__py3-none-any.whl → 1.2.883__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.
- biolib/_internal/errors.py +5 -0
- biolib/_internal/push_application.py +93 -7
- biolib/cli/push.py +14 -8
- {pybiolib-1.2.876.dist-info → pybiolib-1.2.883.dist-info}/METADATA +1 -1
- {pybiolib-1.2.876.dist-info → pybiolib-1.2.883.dist-info}/RECORD +8 -7
- {pybiolib-1.2.876.dist-info → pybiolib-1.2.883.dist-info}/LICENSE +0 -0
- {pybiolib-1.2.876.dist-info → pybiolib-1.2.883.dist-info}/WHEEL +0 -0
- {pybiolib-1.2.876.dist-info → pybiolib-1.2.883.dist-info}/entry_points.txt +0 -0
@@ -1,5 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
import re
|
3
|
+
import sys
|
4
|
+
import time
|
3
5
|
from pathlib import Path
|
4
6
|
|
5
7
|
import rich.progress
|
@@ -10,6 +12,7 @@ from biolib._internal.data_record.push_data import (
|
|
10
12
|
push_data_path,
|
11
13
|
validate_data_path_and_get_files_and_size_of_directory,
|
12
14
|
)
|
15
|
+
from biolib._internal.errors import AuthenticationError
|
13
16
|
from biolib._internal.file_utils import get_files_and_size_of_directory, get_iterable_zip_stream
|
14
17
|
from biolib._internal.types.push import PushResponseDict
|
15
18
|
from biolib.biolib_api_client import BiolibApiClient
|
@@ -36,6 +39,13 @@ class DockerStatusUpdate(TypedDict, total=False):
|
|
36
39
|
|
37
40
|
|
38
41
|
def process_docker_status_updates(status_updates: Iterable[DockerStatusUpdate], action: str) -> None:
|
42
|
+
if sys.stdout.isatty():
|
43
|
+
_process_docker_status_updates_with_progress_bar(status_updates, action)
|
44
|
+
else:
|
45
|
+
_process_docker_status_updates_with_logging(status_updates, action)
|
46
|
+
|
47
|
+
|
48
|
+
def _process_docker_status_updates_with_progress_bar(status_updates: Iterable[DockerStatusUpdate], action: str) -> None:
|
39
49
|
with rich.progress.Progress() as progress:
|
40
50
|
layer_id_to_task_id = {}
|
41
51
|
overall_task_id = progress.add_task(description=f'[bold blue]{action} Docker image', total=None)
|
@@ -97,6 +107,74 @@ def process_docker_status_updates(status_updates: Iterable[DockerStatusUpdate],
|
|
97
107
|
print(update)
|
98
108
|
|
99
109
|
|
110
|
+
def _process_docker_status_updates_with_logging(status_updates: Iterable[DockerStatusUpdate], action: str) -> None:
|
111
|
+
layer_progress = {}
|
112
|
+
layer_status = {}
|
113
|
+
last_log_time = time.time()
|
114
|
+
|
115
|
+
logger.info(f'{action} Docker image...')
|
116
|
+
|
117
|
+
for update in status_updates:
|
118
|
+
current_time = time.time()
|
119
|
+
|
120
|
+
if 'progressDetail' in update and 'id' in update:
|
121
|
+
layer_id = update['id']
|
122
|
+
progress_detail = update['progressDetail']
|
123
|
+
|
124
|
+
if progress_detail and 'current' in progress_detail and 'total' in progress_detail:
|
125
|
+
current = progress_detail['current']
|
126
|
+
total = progress_detail['total']
|
127
|
+
percentage = (current / total * 100) if total > 0 else 0
|
128
|
+
layer_progress[layer_id] = percentage
|
129
|
+
layer_status[layer_id] = f'{action.lower()}'
|
130
|
+
elif update.get('status') == 'Layer already exists':
|
131
|
+
layer_progress[layer_id] = 100
|
132
|
+
layer_status[layer_id] = 'already exists'
|
133
|
+
|
134
|
+
elif 'status' in update and 'id' in update:
|
135
|
+
layer_id = update['id']
|
136
|
+
status = update['status']
|
137
|
+
layer_status[layer_id] = status.lower()
|
138
|
+
|
139
|
+
if status in ['Pushed', 'Uploaded'] or status == 'Layer already exists':
|
140
|
+
layer_progress[layer_id] = 100
|
141
|
+
|
142
|
+
elif 'status' in update and update['status']:
|
143
|
+
status = update['status']
|
144
|
+
if status not in ['Preparing', 'Pushing', 'Pushed', 'Waiting', 'Layer already exists']:
|
145
|
+
logger.info(f'{action} Docker image - {status}')
|
146
|
+
|
147
|
+
if current_time - last_log_time >= 10.0:
|
148
|
+
_log_progress_summary(action, layer_progress, layer_status)
|
149
|
+
last_log_time = current_time
|
150
|
+
|
151
|
+
_log_progress_summary(action, layer_progress, layer_status)
|
152
|
+
logger.info(f'{action} Docker image completed')
|
153
|
+
|
154
|
+
|
155
|
+
def _log_progress_summary(action: str, layer_progress: dict, layer_status: dict) -> None:
|
156
|
+
if not layer_progress and not layer_status:
|
157
|
+
return
|
158
|
+
|
159
|
+
completed_layers = sum(1 for progress in layer_progress.values() if progress >= 100)
|
160
|
+
total_layers = len(layer_progress) if layer_progress else len(layer_status)
|
161
|
+
|
162
|
+
if total_layers > 0:
|
163
|
+
overall_percentage = completed_layers / total_layers * 100
|
164
|
+
logger.info(
|
165
|
+
f'{action} progress: {completed_layers}/{total_layers} layers completed ({overall_percentage:.1f}%)'
|
166
|
+
)
|
167
|
+
|
168
|
+
active_layers = [
|
169
|
+
layer_id
|
170
|
+
for layer_id, status in layer_status.items()
|
171
|
+
if status in ['preparing', 'waiting', 'pushing', 'uploading'] and layer_progress.get(layer_id, 0) < 100
|
172
|
+
]
|
173
|
+
|
174
|
+
if active_layers:
|
175
|
+
logger.info(f'Active layers: {", ".join(active_layers[:5])}{"..." if len(active_layers) > 5 else ""}')
|
176
|
+
|
177
|
+
|
100
178
|
def set_app_version_as_active(
|
101
179
|
app_version_uuid: str,
|
102
180
|
):
|
@@ -127,13 +205,21 @@ def push_application(
|
|
127
205
|
|
128
206
|
api_client = BiolibApiClient.get()
|
129
207
|
if not api_client.is_signed_in:
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
208
|
+
github_ref = os.getenv('GITHUB_REF')
|
209
|
+
if github_ref and not api_client.resource_deploy_key:
|
210
|
+
raise AuthenticationError(
|
211
|
+
'You must be authenticated to push an application.\n'
|
212
|
+
'Please set the environment variable "BIOLIB_TOKEN=[your_deploy_token]"\n'
|
213
|
+
f'You can get a deploy key at: {api_client.base_url}/{app_uri_to_fetch}/settings/keys/\n'
|
214
|
+
'Then add it to your GitHub repository at: '
|
215
|
+
'Settings -> Secrets and variables -> Actions -> Repository secrets'
|
216
|
+
)
|
217
|
+
else:
|
218
|
+
raise AuthenticationError(
|
219
|
+
'You must be authenticated to push an application.\n'
|
220
|
+
'Please set the environment variable "BIOLIB_TOKEN=[your_deploy_token]"\n'
|
221
|
+
f'You can get a deploy key at: {api_client.base_url}/{app_uri_to_fetch}/settings/keys/'
|
222
|
+
)
|
137
223
|
|
138
224
|
# prepare zip file
|
139
225
|
config_yml_path = app_path_absolute.joinpath('.biolib/config.yml')
|
biolib/cli/push.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
import logging
|
2
|
+
import sys
|
2
3
|
from typing import Optional
|
3
4
|
|
4
5
|
import click
|
5
6
|
|
7
|
+
from biolib._internal.errors import AuthenticationError
|
6
8
|
from biolib._internal.push_application import push_application
|
7
9
|
from biolib.biolib_logging import logger, logger_no_user_data
|
8
10
|
|
@@ -34,11 +36,15 @@ def push(uri, path: str, copy_images_from_version: Optional[str], dev: bool, pre
|
|
34
36
|
elif pre_release:
|
35
37
|
set_as_active = False
|
36
38
|
set_as_published = True
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
39
|
+
try:
|
40
|
+
push_application(
|
41
|
+
app_path=path,
|
42
|
+
app_uri=uri,
|
43
|
+
app_version_to_copy_images_from=copy_images_from_version,
|
44
|
+
set_as_active=set_as_active,
|
45
|
+
set_as_published=set_as_published,
|
46
|
+
dry_run=dry_run,
|
47
|
+
)
|
48
|
+
except AuthenticationError as error:
|
49
|
+
print(error.message, file=sys.stderr)
|
50
|
+
exit(1)
|
@@ -6,6 +6,7 @@ biolib/_internal/data_record/__init__.py,sha256=fGdME6JGRU_2VxpJbYpGXYndjN-feUkm
|
|
6
6
|
biolib/_internal/data_record/data_record.py,sha256=SD3-tKQY2RZv9ZSVNUhd2ISDYV64Fk1Sc642qyf_Vis,4618
|
7
7
|
biolib/_internal/data_record/push_data.py,sha256=-L3a_7zZzDCXabBu3O4lWPMAMeBbeRPTrBlEM-_5SCI,2693
|
8
8
|
biolib/_internal/data_record/remote_storage_endpoint.py,sha256=eCptuZ4DMAPnaNCVDvpWXwXGI6Jac9U1N5dqU8Cj95Q,1732
|
9
|
+
biolib/_internal/errors.py,sha256=AokI6Dvaa22B__LTfSZUVdDsm0ye7lgBFv_aD9O_kbs,163
|
9
10
|
biolib/_internal/file_utils.py,sha256=4jT6j7bB21c0JNn5BfnyWQib_zt0CVtJ_TiOFOStRcE,2604
|
10
11
|
biolib/_internal/fuse_mount/__init__.py,sha256=B_tM6RM2dBw-vbpoHJC4X3tOAaN1H2RDvqYJOw3xFwg,55
|
11
12
|
biolib/_internal/fuse_mount/experiment_fuse_mount.py,sha256=08aUdEq_bvqLBft_gSLjOClKDy5sBnMts1RfJf7AP_U,7012
|
@@ -21,7 +22,7 @@ biolib/_internal/llm_instructions/.github/instructions/style-react-ts.instructio
|
|
21
22
|
biolib/_internal/llm_instructions/.github/prompts/biolib_app_inputs.prompt.md,sha256=SMzXZImdID0yKjhE1fG54VrHdD8IVuwRxRKsMF-KjWs,697
|
22
23
|
biolib/_internal/llm_instructions/.github/prompts/biolib_run_apps.prompt.md,sha256=-t1bmGr3zEFa6lKHaLcI98yq4Sg1TCMW8xbelNSHaOA,696
|
23
24
|
biolib/_internal/llm_instructions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
|
-
biolib/_internal/push_application.py,sha256=
|
25
|
+
biolib/_internal/push_application.py,sha256=OwabiLPK8P_py3GavIzhYqcQL7hZ6XPKDrhSJUSxeRs,18023
|
25
26
|
biolib/_internal/runtime.py,sha256=BiHl4klUHr36MCpqKaUso4idHeBZfPAahLYRQrabFqA,486
|
26
27
|
biolib/_internal/templates/__init__.py,sha256=NVbhLUMC8HITzkLvP88Qu7FHaL-SvQord-DX3gh1Ykk,24
|
27
28
|
biolib/_internal/templates/init_template/.biolib/config.yml,sha256=y4ndTgbFvUE1UiGcIOqogT2Wm8jahGffeyU5rlCEltQ,427
|
@@ -85,7 +86,7 @@ biolib/cli/data_record.py,sha256=t8DfJK2EZ_SNZ9drDA_N5Jqy8DNwf9f5SlFrIaOvtv0,350
|
|
85
86
|
biolib/cli/download_container.py,sha256=HIZVHOPmslGE5M2Dsp9r2cCkAEJx__vcsDz5Wt5LRos,483
|
86
87
|
biolib/cli/init.py,sha256=_dhnKdlRMy2oSNRRsXdjFKVzayy2aiRQkeF948VCCkg,4438
|
87
88
|
biolib/cli/lfs.py,sha256=z2qHUwink85mv9yDgifbVKkVwuyknGhMDTfly_gLKJM,4151
|
88
|
-
biolib/cli/push.py,sha256=
|
89
|
+
biolib/cli/push.py,sha256=J8BswMYVeTacZBHbm4K4a2XbS_I8kvfgRZLoby2wi3I,1695
|
89
90
|
biolib/cli/run.py,sha256=MCo0ZqW2pHBxOoCI3i5gAx5D0auW9fmxHqkAF4TRhms,2134
|
90
91
|
biolib/cli/runtime.py,sha256=Xv-nrma5xX8NidWcvbUKcUvuN5TCarZa4A8mPVmF-z0,361
|
91
92
|
biolib/cli/sdk.py,sha256=XisJwTft4QDB_99eGDlz-WBqqRwIqkVg7HyvxWtOG8w,471
|
@@ -140,8 +141,8 @@ biolib/utils/cache_state.py,sha256=u256F37QSRIVwqKlbnCyzAX4EMI-kl6Dwu6qwj-Qmag,3
|
|
140
141
|
biolib/utils/multipart_uploader.py,sha256=XvGP1I8tQuKhAH-QugPRoEsCi9qvbRk-DVBs5PNwwJo,8452
|
141
142
|
biolib/utils/seq_util.py,sha256=Ozk0blGtPur_D9MwShD02r_mphyQmgZkx-lOHOwnlIM,6730
|
142
143
|
biolib/utils/zip/remote_zip.py,sha256=0wErYlxir5921agfFeV1xVjf29l9VNgGQvNlWOlj2Yc,23232
|
143
|
-
pybiolib-1.2.
|
144
|
-
pybiolib-1.2.
|
145
|
-
pybiolib-1.2.
|
146
|
-
pybiolib-1.2.
|
147
|
-
pybiolib-1.2.
|
144
|
+
pybiolib-1.2.883.dist-info/LICENSE,sha256=F2h7gf8i0agDIeWoBPXDMYScvQOz02pAWkKhTGOHaaw,1067
|
145
|
+
pybiolib-1.2.883.dist-info/METADATA,sha256=SpFwDiscPum6qx9WgKbEzFGSBnMntarbRXNVGXSW0I8,1570
|
146
|
+
pybiolib-1.2.883.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
147
|
+
pybiolib-1.2.883.dist-info/entry_points.txt,sha256=p6DyaP_2kctxegTX23WBznnrDi4mz6gx04O5uKtRDXg,42
|
148
|
+
pybiolib-1.2.883.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|