pybiolib 1.2.334.dev1__py3-none-any.whl → 1.2.339__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/utils/multinode.py +0 -2
- biolib/compute_node/job_worker/executors/docker_executor.py +15 -51
- biolib/compute_node/job_worker/executors/types.py +0 -7
- biolib/compute_node/job_worker/job_worker.py +6 -6
- biolib/compute_node/webserver/worker_thread.py +21 -27
- {pybiolib-1.2.334.dev1.dist-info → pybiolib-1.2.339.dist-info}/METADATA +1 -1
- {pybiolib-1.2.334.dev1.dist-info → pybiolib-1.2.339.dist-info}/RECORD +10 -10
- {pybiolib-1.2.334.dev1.dist-info → pybiolib-1.2.339.dist-info}/LICENSE +0 -0
- {pybiolib-1.2.334.dev1.dist-info → pybiolib-1.2.339.dist-info}/WHEEL +0 -0
- {pybiolib-1.2.334.dev1.dist-info → pybiolib-1.2.339.dist-info}/entry_points.txt +0 -0
@@ -84,8 +84,6 @@ def fasta_batch_records(records, work_per_batch_min, work_per_residue=1, verbose
|
|
84
84
|
n_seqs, n_res = batch_dict['records'], batch_dict['residues']
|
85
85
|
print(f'Batch {i+1}: {n_res} residues from {n_seqs} sequences')
|
86
86
|
|
87
|
-
# records = SeqUtil.parse_fasta(fasta_file)
|
88
|
-
|
89
87
|
batches = []
|
90
88
|
batch = []
|
91
89
|
current_work_units = 0
|
@@ -27,7 +27,7 @@ from biolib.compute_node import utils as compute_node_utils
|
|
27
27
|
from biolib.compute_node.cloud_utils import CloudUtils
|
28
28
|
from biolib.compute_node.job_worker.docker_image_cache import DockerImageCache
|
29
29
|
from biolib.compute_node.job_worker.executors.docker_types import DockerDiffKind
|
30
|
-
from biolib.compute_node.job_worker.executors.types import LocalExecutorOptions, StatusUpdate
|
30
|
+
from biolib.compute_node.job_worker.executors.types import LocalExecutorOptions, StatusUpdate
|
31
31
|
from biolib.compute_node.job_worker.mappings import Mappings, path_without_first_folder
|
32
32
|
from biolib.compute_node.job_worker.utilization_reporter_thread import UtilizationReporterThread
|
33
33
|
from biolib.compute_node.job_worker.utils import ComputeProcessException
|
@@ -61,12 +61,9 @@ class DockerExecutor:
|
|
61
61
|
os.makedirs(user_data_tar_dir, exist_ok=True)
|
62
62
|
|
63
63
|
self._docker_container: Optional[Container] = None
|
64
|
-
self._docker_api_client = BiolibDockerClient.get_docker_client().api
|
65
64
|
self._runtime_tar_path = f'{user_data_tar_dir}/runtime_{self._random_docker_id}.tar'
|
66
65
|
self._input_tar_path = f'{user_data_tar_dir}/input_{self._random_docker_id}.tar'
|
67
66
|
|
68
|
-
self._metadata_for_save_output_on_cancel: Optional[MetadataToSaveOutput] = None
|
69
|
-
|
70
67
|
if utils.IS_RUNNING_IN_CLOUD and not utils.BIOLIB_SECRETS_TMPFS_PATH:
|
71
68
|
error_message = 'Running in cloud but no TMPFS path has been set for secrets'
|
72
69
|
logger_no_user_data.error(error_message)
|
@@ -84,12 +81,12 @@ class DockerExecutor:
|
|
84
81
|
raise Exception('Docker container was None')
|
85
82
|
return self._docker_container
|
86
83
|
|
87
|
-
def execute_module(self) -> None:
|
84
|
+
def execute_module(self, module_input_path: str, module_output_path: str) -> None:
|
88
85
|
try:
|
89
86
|
job_uuid = self._options['job']['public_id']
|
90
87
|
send_status_update = self._options['send_status_update']
|
91
88
|
logger_no_user_data.debug(f'Reading module input of {job_uuid}.')
|
92
|
-
with open(
|
89
|
+
with open(module_input_path, 'rb') as fp:
|
93
90
|
module_input_tmp = ModuleInput(fp.read())
|
94
91
|
logger_no_user_data.debug(f'Deserialing module input of {job_uuid}...')
|
95
92
|
module_input = module_input_tmp.deserialize()
|
@@ -103,7 +100,7 @@ class DockerExecutor:
|
|
103
100
|
|
104
101
|
logger_no_user_data.debug(f'Starting execution of {job_uuid}.')
|
105
102
|
try:
|
106
|
-
self._execute_helper(module_input)
|
103
|
+
self._execute_helper(module_input, module_output_path)
|
107
104
|
except docker.errors.NotFound as docker_error:
|
108
105
|
raise DockerContainerNotFoundDuringExecutionException from docker_error
|
109
106
|
except Exception as exception:
|
@@ -164,8 +161,7 @@ class DockerExecutor:
|
|
164
161
|
may_contain_user_data=False,
|
165
162
|
)
|
166
163
|
|
167
|
-
|
168
|
-
def _execute_helper(self, module_input) -> None:
|
164
|
+
def _execute_helper(self, module_input, module_output_path: str) -> None:
|
169
165
|
job_uuid = self._options['job']['public_id']
|
170
166
|
logger_no_user_data.debug(f'Initializing container for {job_uuid}.')
|
171
167
|
self._initialize_docker_container(module_input)
|
@@ -191,9 +187,10 @@ class DockerExecutor:
|
|
191
187
|
logger_no_user_data.debug(f'_map_and_copy_input_files_to_container for {job_uuid}.')
|
192
188
|
self._map_and_copy_input_files_to_container(module_input['files'], module_input['arguments'])
|
193
189
|
|
190
|
+
docker_api_client = BiolibDockerClient.get_docker_client().api
|
194
191
|
logger_no_user_data.debug(f'Attaching Docker container for {job_uuid}')
|
195
192
|
|
196
|
-
stdout_and_stderr_stream =
|
193
|
+
stdout_and_stderr_stream = docker_api_client.attach(
|
197
194
|
container=self._container.id,
|
198
195
|
stderr=True,
|
199
196
|
stdout=True,
|
@@ -214,12 +211,6 @@ class DockerExecutor:
|
|
214
211
|
logger.debug(f'Warning: Job "{job_uuid}" failed to start container. Hit error: {startup_error_string}')
|
215
212
|
# even though the container start failed we should still be able to call logs() and wait() on it, so we pass
|
216
213
|
|
217
|
-
self._metadata_for_save_output_on_cancel = MetadataToSaveOutput(
|
218
|
-
arguments=module_input['arguments'],
|
219
|
-
startup_error_string=startup_error_string,
|
220
|
-
pre_start_diff=pre_start_diff,
|
221
|
-
)
|
222
|
-
|
223
214
|
if self._options['job']['app_version'].get('stdout_render_type') != 'markdown':
|
224
215
|
logger_no_user_data.debug(f'Streaming stdout for {job_uuid}')
|
225
216
|
for stdout_and_stderr in stdout_and_stderr_stream:
|
@@ -229,14 +220,7 @@ class DockerExecutor:
|
|
229
220
|
self._send_stdout_and_stderr(stdout_and_stderr)
|
230
221
|
|
231
222
|
logger_no_user_data.debug(f'Waiting on docker for {job_uuid}')
|
232
|
-
|
233
|
-
docker_result = self._docker_api_client.wait(self._container.id)
|
234
|
-
except docker.errors.NotFound as error:
|
235
|
-
if self._is_cleaning_up:
|
236
|
-
return
|
237
|
-
else:
|
238
|
-
raise error
|
239
|
-
|
223
|
+
docker_result = docker_api_client.wait(self._container.id)
|
240
224
|
logger_no_user_data.debug(f'Got result from docker for {job_uuid}')
|
241
225
|
exit_code = docker_result['StatusCode']
|
242
226
|
# 137 is the error code from linux OOM killer (Should catch 90% of OOM errors)
|
@@ -248,26 +232,22 @@ class DockerExecutor:
|
|
248
232
|
)
|
249
233
|
|
250
234
|
logger_no_user_data.debug(f'Docker container exited with code {exit_code} for {job_uuid}')
|
251
|
-
self._save_module_output_from_container(exit_code, self._metadata_for_save_output_on_cancel)
|
252
|
-
|
253
235
|
|
254
|
-
|
255
|
-
|
256
|
-
full_stderr = self._docker_api_client.logs(self._container.id, stdout=False, stderr=True)
|
236
|
+
full_stdout = docker_api_client.logs(self._container.id, stdout=True, stderr=False)
|
237
|
+
full_stderr = docker_api_client.logs(self._container.id, stdout=False, stderr=True)
|
257
238
|
|
258
|
-
if
|
259
|
-
full_stderr = full_stderr +
|
239
|
+
if startup_error_string:
|
240
|
+
full_stderr = full_stderr + startup_error_string.encode()
|
260
241
|
|
261
242
|
self._write_module_output_to_file(
|
262
|
-
arguments=
|
243
|
+
arguments=module_input['arguments'],
|
263
244
|
exit_code=exit_code,
|
264
|
-
module_output_path=
|
245
|
+
module_output_path=module_output_path,
|
265
246
|
stderr=full_stderr,
|
266
247
|
stdout=full_stdout,
|
267
|
-
pre_start_diff=
|
248
|
+
pre_start_diff=pre_start_diff,
|
268
249
|
)
|
269
250
|
|
270
|
-
|
271
251
|
def cleanup(self):
|
272
252
|
# Don't clean up if already in the process of doing so, or done doing so
|
273
253
|
if self._is_cleaning_up:
|
@@ -275,22 +255,6 @@ class DockerExecutor:
|
|
275
255
|
else:
|
276
256
|
self._is_cleaning_up = True
|
277
257
|
|
278
|
-
if self._metadata_for_save_output_on_cancel is not None:
|
279
|
-
try:
|
280
|
-
logger_no_user_data.debug('Attempting to save results')
|
281
|
-
self._docker_container.stop()
|
282
|
-
self._docker_container.reload()
|
283
|
-
logger_no_user_data.debug(f'Container state {self._docker_container.status}')
|
284
|
-
self._save_module_output_from_container(
|
285
|
-
exit_code=self._docker_container.attrs['State']['ExitCode'],
|
286
|
-
metadata=self._metadata_for_save_output_on_cancel
|
287
|
-
)
|
288
|
-
logger_no_user_data.debug('Saved results')
|
289
|
-
except BaseException as error:
|
290
|
-
logger_no_user_data.error(f'Failed to save results on cancel with error: {error}')
|
291
|
-
else:
|
292
|
-
logger_no_user_data.debug('Missing metadata, cannot save results')
|
293
|
-
|
294
258
|
tar_time = time.time()
|
295
259
|
for path_to_delete in [self._input_tar_path, self._runtime_tar_path]:
|
296
260
|
if os.path.exists(path_to_delete):
|
@@ -34,16 +34,9 @@ class LocalExecutorOptions(TypedDict):
|
|
34
34
|
cloud_job: Optional[CloudJob]
|
35
35
|
large_file_systems: Dict[str, LargeFileSystem]
|
36
36
|
module: Module
|
37
|
-
module_input_path: str
|
38
|
-
module_output_path: str
|
39
37
|
remote_host_proxies: List[RemoteHostProxy]
|
40
38
|
root_job_id: str
|
41
39
|
runtime_zip_bytes: Optional[bytes] # TODO: replace this with a module_source_serialized
|
42
40
|
send_status_update: SendStatusUpdateType
|
43
41
|
send_system_exception: SendSystemExceptionType
|
44
42
|
send_stdout_and_stderr: SendStdoutAndStderrType
|
45
|
-
|
46
|
-
class MetadataToSaveOutput(TypedDict):
|
47
|
-
arguments: List[str]
|
48
|
-
startup_error_string: Optional[str]
|
49
|
-
pre_start_diff: List[Dict]
|
@@ -400,15 +400,15 @@ class JobWorker:
|
|
400
400
|
cloud_job=self._root_job_wrapper['cloud_job'],
|
401
401
|
large_file_systems=lfs_dict,
|
402
402
|
module=main_module,
|
403
|
-
module_input_path=module_input_path,
|
404
|
-
module_output_path=main_module_output_path,
|
405
403
|
remote_host_proxies=self._remote_host_proxies,
|
406
404
|
root_job_id=root_job_id,
|
407
405
|
runtime_zip_bytes=runtime_zip_bytes,
|
408
406
|
send_status_update=self._send_status_update,
|
409
407
|
send_system_exception=self.send_system_exception,
|
410
408
|
send_stdout_and_stderr=self.send_stdout_and_stderr,
|
411
|
-
)
|
409
|
+
),
|
410
|
+
module_input_path,
|
411
|
+
main_module_output_path,
|
412
412
|
)
|
413
413
|
|
414
414
|
if utils.IS_RUNNING_IN_CLOUD:
|
@@ -418,11 +418,11 @@ class JobWorker:
|
|
418
418
|
def _run_module(
|
419
419
|
self,
|
420
420
|
options: LocalExecutorOptions,
|
421
|
+
module_input_path: str,
|
422
|
+
module_output_path: str,
|
421
423
|
) -> None:
|
422
424
|
module = options['module']
|
423
425
|
job_id = options['job']['public_id']
|
424
|
-
module_output_path = options['module_output_path']
|
425
|
-
module_input_path = options['module_input_path']
|
426
426
|
logger_no_user_data.debug(f'Job "{job_id}" running module "{module["name"]}"...')
|
427
427
|
|
428
428
|
executor_instance: DockerExecutor
|
@@ -469,7 +469,7 @@ class JobWorker:
|
|
469
469
|
# Log memory and disk before pulling and executing module
|
470
470
|
log_disk_and_memory_usage_info()
|
471
471
|
|
472
|
-
executor_instance.execute_module()
|
472
|
+
executor_instance.execute_module(module_input_path, module_output_path)
|
473
473
|
|
474
474
|
def _connect_to_parent(self):
|
475
475
|
try:
|
@@ -7,7 +7,6 @@ import sys
|
|
7
7
|
import threading
|
8
8
|
import time
|
9
9
|
from queue import Queue
|
10
|
-
from typing import Optional
|
11
10
|
|
12
11
|
from biolib import api, utils
|
13
12
|
from biolib.biolib_binary_format import ModuleOutputV2, SystemException, SystemStatusUpdate
|
@@ -56,26 +55,6 @@ class WorkerThread(threading.Thread):
|
|
56
55
|
def _job_temporary_dir(self):
|
57
56
|
return self.compute_state['job_temporary_dir']
|
58
57
|
|
59
|
-
def _upload_module_output_and_get_exit_code(self) -> Optional[int]:
|
60
|
-
exit_code = None
|
61
|
-
try:
|
62
|
-
module_output_path = os.path.join(
|
63
|
-
self._job_temporary_dir,
|
64
|
-
JobStorage.module_output_file_name,
|
65
|
-
)
|
66
|
-
if os.path.exists(module_output_path):
|
67
|
-
module_output = ModuleOutputV2(buffer=LocalFileIndexableBuffer(filename=module_output_path))
|
68
|
-
exit_code = module_output.get_exit_code()
|
69
|
-
logger_no_user_data.debug(f'Got exit code: {exit_code}')
|
70
|
-
if utils.IS_RUNNING_IN_CLOUD:
|
71
|
-
JobStorage.upload_module_output(
|
72
|
-
job_temporary_dir=self._job_temporary_dir,
|
73
|
-
job_uuid=self._job_uuid,
|
74
|
-
)
|
75
|
-
except Exception as error:
|
76
|
-
logger_no_user_data.error(f'Could not upload module output or get exit code: {error}')
|
77
|
-
return exit_code
|
78
|
-
|
79
58
|
def run(self):
|
80
59
|
try:
|
81
60
|
while True:
|
@@ -98,7 +77,25 @@ class WorkerThread(threading.Thread):
|
|
98
77
|
|
99
78
|
# If 'Computation Finished'
|
100
79
|
if progress == 94:
|
101
|
-
|
80
|
+
# Get Job exit code
|
81
|
+
try:
|
82
|
+
module_output_path = os.path.join(
|
83
|
+
self._job_temporary_dir,
|
84
|
+
JobStorage.module_output_file_name,
|
85
|
+
)
|
86
|
+
module_output = ModuleOutputV2(buffer=LocalFileIndexableBuffer(filename=module_output_path))
|
87
|
+
self.compute_state['exit_code'] = module_output.get_exit_code()
|
88
|
+
logger_no_user_data.debug(f"Got exit code: {self.compute_state['exit_code']}")
|
89
|
+
|
90
|
+
except Exception as error: # pylint: disable=broad-except
|
91
|
+
logger_no_user_data.error(f'Could not get exit_code from module output due to: {error}')
|
92
|
+
|
93
|
+
if utils.IS_RUNNING_IN_CLOUD:
|
94
|
+
JobStorage.upload_module_output(
|
95
|
+
job_temporary_dir=self._job_temporary_dir,
|
96
|
+
job_uuid=self._job_uuid,
|
97
|
+
)
|
98
|
+
|
102
99
|
self._set_status_update(progress=95, log_message='Result Ready')
|
103
100
|
self.compute_state['is_completed'] = True
|
104
101
|
self.terminate()
|
@@ -177,16 +174,13 @@ class WorkerThread(threading.Thread):
|
|
177
174
|
|
178
175
|
def terminate(self) -> None:
|
179
176
|
cloud_job_uuid = self.compute_state['cloud_job_id']
|
177
|
+
exit_code = self.compute_state.get('exit_code')
|
180
178
|
system_exception_code = self.compute_state['status'].get('error_code')
|
181
|
-
|
182
179
|
if utils.IS_RUNNING_IN_CLOUD:
|
183
|
-
if system_exception_code == SystemExceptionCodes.CANCELLED_BY_USER.value:
|
184
|
-
self.compute_state['exit_code'] = self._upload_module_output_and_get_exit_code()
|
185
|
-
|
186
180
|
CloudUtils.finish_cloud_job(
|
187
181
|
cloud_job_id=cloud_job_uuid,
|
188
182
|
system_exception_code=system_exception_code,
|
189
|
-
exit_code=
|
183
|
+
exit_code=exit_code,
|
190
184
|
)
|
191
185
|
|
192
186
|
deregistered_due_to_error = False
|
@@ -24,7 +24,7 @@ biolib/_internal/types/resource.py,sha256=G-vPkZoe4Um6FPxsQZtRzAlbSW5sDW4NFkbjn2
|
|
24
24
|
biolib/_internal/types/resource_version.py,sha256=sLxViYXloDDUhTDFgjegiQCj097OM1Ih1-uqlC_4ULA,174
|
25
25
|
biolib/_internal/types/typing.py,sha256=D4EKKEe7kDx0K6lJi-H_XLtk-8w6nu2fdqn9bvzI-Xo,288
|
26
26
|
biolib/_internal/utils/__init__.py,sha256=p5vsIFyu-zYqBgdSMfwW9NC_jk7rXvvCbV4Bzd3As7c,630
|
27
|
-
biolib/_internal/utils/multinode.py,sha256
|
27
|
+
biolib/_internal/utils/multinode.py,sha256=-J3PEAK3NaOwCn--5T7vWHkA3yu5w9QhmuhkQcH-2wY,8229
|
28
28
|
biolib/_runtime/runtime.py,sha256=bZQ0m39R9jOBVAtlyvzDnOobKueOAQUCwMUZjDQnO7E,4439
|
29
29
|
biolib/api/__init__.py,sha256=mQ4u8FijqyLzjYMezMUUbbBGNB3iFmkNdjXnWPZ7Jlw,138
|
30
30
|
biolib/api/client.py,sha256=_kmwaGI_-u7kOeWVCYmo-pD2K1imwEv9n2gNZRb5F-I,3790
|
@@ -76,14 +76,14 @@ biolib/compute_node/job_worker/cache_state.py,sha256=MwjSRzcJJ_4jybqvBL4xdgnDYSI
|
|
76
76
|
biolib/compute_node/job_worker/cache_types.py,sha256=ajpLy8i09QeQS9dEqTn3T6NVNMY_YsHQkSD5nvIHccQ,818
|
77
77
|
biolib/compute_node/job_worker/docker_image_cache.py,sha256=ansHIkJIq_EMW1nZNlW-RRLVVeKWTbzNICYaOHpKiRE,7460
|
78
78
|
biolib/compute_node/job_worker/executors/__init__.py,sha256=bW6t1qi3PZTlHM4quaTLa8EI4ALTCk83cqcVJfJfJfE,145
|
79
|
-
biolib/compute_node/job_worker/executors/docker_executor.py,sha256=
|
79
|
+
biolib/compute_node/job_worker/executors/docker_executor.py,sha256=J-wv7FTb_HJnfRdIByiOdtj18Fw5nYvVm-n0D1mrqwA,29377
|
80
80
|
biolib/compute_node/job_worker/executors/docker_types.py,sha256=VhsU1DKtJjx_BbCkVmiPZPH4ROiL1ygW1Y_s1Kbpa2o,216
|
81
81
|
biolib/compute_node/job_worker/executors/tars/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
82
|
-
biolib/compute_node/job_worker/executors/types.py,sha256=
|
82
|
+
biolib/compute_node/job_worker/executors/types.py,sha256=yP5gG39hr-DLnw9bOE--VHi-1arDbIYiGuV1rlTbbHI,1466
|
83
83
|
biolib/compute_node/job_worker/job_legacy_input_wait_timeout_thread.py,sha256=_cvEiZbOwfkv6fYmfrvdi_FVviIEYr_dSClQcOQaUWM,1198
|
84
84
|
biolib/compute_node/job_worker/job_max_runtime_timer_thread.py,sha256=K_xgz7IhiIjpLlXRk8sqaMyLoApcidJkgu29sJX0gb8,1174
|
85
85
|
biolib/compute_node/job_worker/job_storage.py,sha256=lScHI3ubcHKagSEW243tgbIWXUfbWDHDjEOPMvXxJE8,4603
|
86
|
-
biolib/compute_node/job_worker/job_worker.py,sha256=
|
86
|
+
biolib/compute_node/job_worker/job_worker.py,sha256=fuWoYJo9HOqLmWl8yeCXh0mhT4ebbkrWac-BVb58khs,28842
|
87
87
|
biolib/compute_node/job_worker/large_file_system.py,sha256=XXqRlVtYhs-Ji9zQGIk5KQPXFO_Q5jJH0nnlw4GkeMY,10461
|
88
88
|
biolib/compute_node/job_worker/mappings.py,sha256=Z48Kg4nbcOvsT2-9o3RRikBkqflgO4XeaWxTGz-CNvI,2499
|
89
89
|
biolib/compute_node/job_worker/utilization_reporter_thread.py,sha256=7tm5Yk9coqJ9VbEdnO86tSXI0iM0omwIyKENxdxiVXk,8575
|
@@ -97,7 +97,7 @@ biolib/compute_node/webserver/gunicorn_flask_application.py,sha256=jPfR_YvNBekLU
|
|
97
97
|
biolib/compute_node/webserver/webserver.py,sha256=o4kOAStsqThUtKlnRE-U5TP0JIYntuySDjU7PH310xg,6620
|
98
98
|
biolib/compute_node/webserver/webserver_types.py,sha256=2t8EaFKESnves3BA_NBdnS2yAdo1qwamCFHiSt888nE,380
|
99
99
|
biolib/compute_node/webserver/webserver_utils.py,sha256=XWvwYPbWNR3qS0FYbLLp-MDDfVk0QdaAmg3xPrT0H2s,4234
|
100
|
-
biolib/compute_node/webserver/worker_thread.py,sha256=
|
100
|
+
biolib/compute_node/webserver/worker_thread.py,sha256=GRRBUqXdMKvbjyLQhYlqGIbFKeU2iiEXIe5IXi9wgdg,11806
|
101
101
|
biolib/experiments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
102
102
|
biolib/experiments/experiment.py,sha256=m7FB7hot8CMOVrNyWGPB6FTkWQJwI0ytpIvtPxfoPME,7684
|
103
103
|
biolib/jobs/__init__.py,sha256=aIb2H2DHjQbM2Bs-dysFijhwFcL58Blp0Co0gimED3w,32
|
@@ -118,8 +118,8 @@ biolib/utils/cache_state.py,sha256=u256F37QSRIVwqKlbnCyzAX4EMI-kl6Dwu6qwj-Qmag,3
|
|
118
118
|
biolib/utils/multipart_uploader.py,sha256=XvGP1I8tQuKhAH-QugPRoEsCi9qvbRk-DVBs5PNwwJo,8452
|
119
119
|
biolib/utils/seq_util.py,sha256=Ozk0blGtPur_D9MwShD02r_mphyQmgZkx-lOHOwnlIM,6730
|
120
120
|
biolib/utils/zip/remote_zip.py,sha256=0wErYlxir5921agfFeV1xVjf29l9VNgGQvNlWOlj2Yc,23232
|
121
|
-
pybiolib-1.2.
|
122
|
-
pybiolib-1.2.
|
123
|
-
pybiolib-1.2.
|
124
|
-
pybiolib-1.2.
|
125
|
-
pybiolib-1.2.
|
121
|
+
pybiolib-1.2.339.dist-info/LICENSE,sha256=F2h7gf8i0agDIeWoBPXDMYScvQOz02pAWkKhTGOHaaw,1067
|
122
|
+
pybiolib-1.2.339.dist-info/METADATA,sha256=7w5znJtkMyO9KQ_CD0PdX2Hz1pBuTjnEOeSnfaOMrsk,1570
|
123
|
+
pybiolib-1.2.339.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
124
|
+
pybiolib-1.2.339.dist-info/entry_points.txt,sha256=p6DyaP_2kctxegTX23WBznnrDi4mz6gx04O5uKtRDXg,42
|
125
|
+
pybiolib-1.2.339.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|