pybiolib 0.2.951__py3-none-any.whl → 1.2.1890__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/__init__.py +357 -11
- biolib/_data_record/data_record.py +380 -0
- biolib/_index/__init__.py +0 -0
- biolib/_index/index.py +55 -0
- biolib/_index/query_result.py +103 -0
- biolib/_internal/__init__.py +0 -0
- biolib/_internal/add_copilot_prompts.py +58 -0
- biolib/_internal/add_gui_files.py +81 -0
- biolib/_internal/data_record/__init__.py +1 -0
- biolib/_internal/data_record/data_record.py +85 -0
- biolib/_internal/data_record/push_data.py +116 -0
- biolib/_internal/data_record/remote_storage_endpoint.py +43 -0
- biolib/_internal/errors.py +5 -0
- biolib/_internal/file_utils.py +125 -0
- biolib/_internal/fuse_mount/__init__.py +1 -0
- biolib/_internal/fuse_mount/experiment_fuse_mount.py +209 -0
- biolib/_internal/http_client.py +159 -0
- biolib/_internal/lfs/__init__.py +1 -0
- biolib/_internal/lfs/cache.py +51 -0
- biolib/_internal/libs/__init__.py +1 -0
- biolib/_internal/libs/fusepy/__init__.py +1257 -0
- biolib/_internal/push_application.py +488 -0
- biolib/_internal/runtime.py +22 -0
- biolib/_internal/string_utils.py +13 -0
- biolib/_internal/templates/__init__.py +1 -0
- biolib/_internal/templates/copilot_template/.github/instructions/general-app-knowledge.instructions.md +10 -0
- biolib/_internal/templates/copilot_template/.github/instructions/style-general.instructions.md +20 -0
- biolib/_internal/templates/copilot_template/.github/instructions/style-python.instructions.md +16 -0
- biolib/_internal/templates/copilot_template/.github/instructions/style-react-ts.instructions.md +47 -0
- biolib/_internal/templates/copilot_template/.github/prompts/biolib_app_inputs.prompt.md +11 -0
- biolib/_internal/templates/copilot_template/.github/prompts/biolib_onboard_repo.prompt.md +19 -0
- biolib/_internal/templates/copilot_template/.github/prompts/biolib_run_apps.prompt.md +12 -0
- biolib/_internal/templates/dashboard_template/.biolib/config.yml +5 -0
- biolib/_internal/templates/github_workflow_template/.github/workflows/biolib.yml +21 -0
- biolib/_internal/templates/gitignore_template/.gitignore +10 -0
- biolib/_internal/templates/gui_template/.yarnrc.yml +1 -0
- biolib/_internal/templates/gui_template/App.tsx +53 -0
- biolib/_internal/templates/gui_template/Dockerfile +27 -0
- biolib/_internal/templates/gui_template/biolib-sdk.ts +82 -0
- biolib/_internal/templates/gui_template/dev-data/output.json +7 -0
- biolib/_internal/templates/gui_template/index.css +5 -0
- biolib/_internal/templates/gui_template/index.html +13 -0
- biolib/_internal/templates/gui_template/index.tsx +10 -0
- biolib/_internal/templates/gui_template/package.json +27 -0
- biolib/_internal/templates/gui_template/tsconfig.json +24 -0
- biolib/_internal/templates/gui_template/vite-plugin-dev-data.ts +50 -0
- biolib/_internal/templates/gui_template/vite.config.mts +10 -0
- biolib/_internal/templates/init_template/.biolib/config.yml +19 -0
- biolib/_internal/templates/init_template/Dockerfile +14 -0
- biolib/_internal/templates/init_template/requirements.txt +1 -0
- biolib/_internal/templates/init_template/run.py +12 -0
- biolib/_internal/templates/init_template/run.sh +4 -0
- biolib/_internal/templates/templates.py +25 -0
- biolib/_internal/tree_utils.py +106 -0
- biolib/_internal/utils/__init__.py +65 -0
- biolib/_internal/utils/auth.py +46 -0
- biolib/_internal/utils/job_url.py +33 -0
- biolib/_internal/utils/multinode.py +263 -0
- biolib/_runtime/runtime.py +157 -0
- biolib/_session/session.py +44 -0
- biolib/_shared/__init__.py +0 -0
- biolib/_shared/types/__init__.py +74 -0
- biolib/_shared/types/account.py +12 -0
- biolib/_shared/types/account_member.py +8 -0
- biolib/_shared/types/app.py +9 -0
- biolib/_shared/types/data_record.py +40 -0
- biolib/_shared/types/experiment.py +32 -0
- biolib/_shared/types/file_node.py +17 -0
- biolib/_shared/types/push.py +6 -0
- biolib/_shared/types/resource.py +37 -0
- biolib/_shared/types/resource_deploy_key.py +11 -0
- biolib/_shared/types/resource_permission.py +14 -0
- biolib/_shared/types/resource_version.py +19 -0
- biolib/_shared/types/result.py +14 -0
- biolib/_shared/types/typing.py +10 -0
- biolib/_shared/types/user.py +19 -0
- biolib/_shared/utils/__init__.py +7 -0
- biolib/_shared/utils/resource_uri.py +75 -0
- biolib/api/__init__.py +6 -0
- biolib/api/client.py +168 -0
- biolib/app/app.py +252 -49
- biolib/app/search_apps.py +45 -0
- biolib/biolib_api_client/api_client.py +126 -31
- biolib/biolib_api_client/app_types.py +24 -4
- biolib/biolib_api_client/auth.py +31 -8
- biolib/biolib_api_client/biolib_app_api.py +147 -52
- biolib/biolib_api_client/biolib_job_api.py +161 -141
- biolib/biolib_api_client/job_types.py +21 -5
- biolib/biolib_api_client/lfs_types.py +7 -23
- biolib/biolib_api_client/user_state.py +56 -0
- biolib/biolib_binary_format/__init__.py +1 -4
- biolib/biolib_binary_format/file_in_container.py +105 -0
- biolib/biolib_binary_format/module_input.py +24 -7
- biolib/biolib_binary_format/module_output_v2.py +149 -0
- biolib/biolib_binary_format/remote_endpoints.py +34 -0
- biolib/biolib_binary_format/remote_stream_seeker.py +59 -0
- biolib/biolib_binary_format/saved_job.py +3 -2
- biolib/biolib_binary_format/{attestation_document.py → stdout_and_stderr.py} +8 -8
- biolib/biolib_binary_format/system_status_update.py +3 -2
- biolib/biolib_binary_format/utils.py +175 -0
- biolib/biolib_docker_client/__init__.py +11 -2
- biolib/biolib_errors.py +36 -0
- biolib/biolib_logging.py +27 -10
- biolib/cli/__init__.py +38 -0
- biolib/cli/auth.py +46 -0
- biolib/cli/data_record.py +164 -0
- biolib/cli/index.py +32 -0
- biolib/cli/init.py +421 -0
- biolib/cli/lfs.py +101 -0
- biolib/cli/push.py +50 -0
- biolib/cli/run.py +63 -0
- biolib/cli/runtime.py +14 -0
- biolib/cli/sdk.py +16 -0
- biolib/cli/start.py +56 -0
- biolib/compute_node/cloud_utils/cloud_utils.py +110 -161
- biolib/compute_node/job_worker/cache_state.py +66 -88
- biolib/compute_node/job_worker/cache_types.py +1 -6
- biolib/compute_node/job_worker/docker_image_cache.py +112 -37
- biolib/compute_node/job_worker/executors/__init__.py +0 -3
- biolib/compute_node/job_worker/executors/docker_executor.py +532 -199
- biolib/compute_node/job_worker/executors/docker_types.py +9 -1
- biolib/compute_node/job_worker/executors/types.py +19 -9
- biolib/compute_node/job_worker/job_legacy_input_wait_timeout_thread.py +30 -0
- biolib/compute_node/job_worker/job_max_runtime_timer_thread.py +3 -5
- biolib/compute_node/job_worker/job_storage.py +108 -0
- biolib/compute_node/job_worker/job_worker.py +397 -212
- biolib/compute_node/job_worker/large_file_system.py +87 -38
- biolib/compute_node/job_worker/network_alloc.py +99 -0
- biolib/compute_node/job_worker/network_buffer.py +240 -0
- biolib/compute_node/job_worker/utilization_reporter_thread.py +197 -0
- biolib/compute_node/job_worker/utils.py +9 -24
- biolib/compute_node/remote_host_proxy.py +400 -98
- biolib/compute_node/utils.py +31 -9
- biolib/compute_node/webserver/compute_node_results_proxy.py +189 -0
- biolib/compute_node/webserver/proxy_utils.py +28 -0
- biolib/compute_node/webserver/webserver.py +130 -44
- biolib/compute_node/webserver/webserver_types.py +2 -6
- biolib/compute_node/webserver/webserver_utils.py +77 -12
- biolib/compute_node/webserver/worker_thread.py +183 -42
- biolib/experiments/__init__.py +0 -0
- biolib/experiments/experiment.py +356 -0
- biolib/jobs/__init__.py +1 -0
- biolib/jobs/job.py +741 -0
- biolib/jobs/job_result.py +185 -0
- biolib/jobs/types.py +50 -0
- biolib/py.typed +0 -0
- biolib/runtime/__init__.py +14 -0
- biolib/sdk/__init__.py +91 -0
- biolib/tables.py +34 -0
- biolib/typing_utils.py +2 -7
- biolib/user/__init__.py +1 -0
- biolib/user/sign_in.py +54 -0
- biolib/utils/__init__.py +162 -0
- biolib/utils/cache_state.py +94 -0
- biolib/utils/multipart_uploader.py +194 -0
- biolib/utils/seq_util.py +150 -0
- biolib/utils/zip/remote_zip.py +640 -0
- pybiolib-1.2.1890.dist-info/METADATA +41 -0
- pybiolib-1.2.1890.dist-info/RECORD +177 -0
- {pybiolib-0.2.951.dist-info → pybiolib-1.2.1890.dist-info}/WHEEL +1 -1
- pybiolib-1.2.1890.dist-info/entry_points.txt +2 -0
- README.md +0 -17
- biolib/app/app_result.py +0 -68
- biolib/app/utils.py +0 -62
- biolib/biolib-js/0-biolib.worker.js +0 -1
- biolib/biolib-js/1-biolib.worker.js +0 -1
- biolib/biolib-js/2-biolib.worker.js +0 -1
- biolib/biolib-js/3-biolib.worker.js +0 -1
- biolib/biolib-js/4-biolib.worker.js +0 -1
- biolib/biolib-js/5-biolib.worker.js +0 -1
- biolib/biolib-js/6-biolib.worker.js +0 -1
- biolib/biolib-js/index.html +0 -10
- biolib/biolib-js/main-biolib.js +0 -1
- biolib/biolib_api_client/biolib_account_api.py +0 -21
- biolib/biolib_api_client/biolib_large_file_system_api.py +0 -108
- biolib/biolib_binary_format/aes_encrypted_package.py +0 -42
- biolib/biolib_binary_format/module_output.py +0 -58
- biolib/biolib_binary_format/rsa_encrypted_aes_package.py +0 -57
- biolib/biolib_push.py +0 -114
- biolib/cli.py +0 -203
- biolib/cli_utils.py +0 -273
- biolib/compute_node/cloud_utils/enclave_parent_types.py +0 -7
- biolib/compute_node/enclave/__init__.py +0 -2
- biolib/compute_node/enclave/enclave_remote_hosts.py +0 -53
- biolib/compute_node/enclave/nitro_secure_module_utils.py +0 -64
- biolib/compute_node/job_worker/executors/base_executor.py +0 -18
- biolib/compute_node/job_worker/executors/pyppeteer_executor.py +0 -173
- biolib/compute_node/job_worker/executors/remote/__init__.py +0 -1
- biolib/compute_node/job_worker/executors/remote/nitro_enclave_utils.py +0 -81
- biolib/compute_node/job_worker/executors/remote/remote_executor.py +0 -51
- biolib/lfs.py +0 -196
- biolib/pyppeteer/.circleci/config.yml +0 -100
- biolib/pyppeteer/.coveragerc +0 -3
- biolib/pyppeteer/.gitignore +0 -89
- biolib/pyppeteer/.pre-commit-config.yaml +0 -28
- biolib/pyppeteer/CHANGES.md +0 -253
- biolib/pyppeteer/CONTRIBUTING.md +0 -26
- biolib/pyppeteer/LICENSE +0 -12
- biolib/pyppeteer/README.md +0 -137
- biolib/pyppeteer/docs/Makefile +0 -177
- biolib/pyppeteer/docs/_static/custom.css +0 -28
- biolib/pyppeteer/docs/_templates/layout.html +0 -10
- biolib/pyppeteer/docs/changes.md +0 -1
- biolib/pyppeteer/docs/conf.py +0 -299
- biolib/pyppeteer/docs/index.md +0 -21
- biolib/pyppeteer/docs/make.bat +0 -242
- biolib/pyppeteer/docs/reference.md +0 -211
- biolib/pyppeteer/docs/server.py +0 -60
- biolib/pyppeteer/poetry.lock +0 -1699
- biolib/pyppeteer/pyppeteer/__init__.py +0 -135
- biolib/pyppeteer/pyppeteer/accessibility.py +0 -286
- biolib/pyppeteer/pyppeteer/browser.py +0 -401
- biolib/pyppeteer/pyppeteer/browser_fetcher.py +0 -194
- biolib/pyppeteer/pyppeteer/command.py +0 -22
- biolib/pyppeteer/pyppeteer/connection/__init__.py +0 -242
- biolib/pyppeteer/pyppeteer/connection/cdpsession.py +0 -101
- biolib/pyppeteer/pyppeteer/coverage.py +0 -346
- biolib/pyppeteer/pyppeteer/device_descriptors.py +0 -787
- biolib/pyppeteer/pyppeteer/dialog.py +0 -79
- biolib/pyppeteer/pyppeteer/domworld.py +0 -597
- biolib/pyppeteer/pyppeteer/emulation_manager.py +0 -53
- biolib/pyppeteer/pyppeteer/errors.py +0 -48
- biolib/pyppeteer/pyppeteer/events.py +0 -63
- biolib/pyppeteer/pyppeteer/execution_context.py +0 -156
- biolib/pyppeteer/pyppeteer/frame/__init__.py +0 -299
- biolib/pyppeteer/pyppeteer/frame/frame_manager.py +0 -306
- biolib/pyppeteer/pyppeteer/helpers.py +0 -245
- biolib/pyppeteer/pyppeteer/input.py +0 -371
- biolib/pyppeteer/pyppeteer/jshandle.py +0 -598
- biolib/pyppeteer/pyppeteer/launcher.py +0 -683
- biolib/pyppeteer/pyppeteer/lifecycle_watcher.py +0 -169
- biolib/pyppeteer/pyppeteer/models/__init__.py +0 -103
- biolib/pyppeteer/pyppeteer/models/_protocol.py +0 -12460
- biolib/pyppeteer/pyppeteer/multimap.py +0 -82
- biolib/pyppeteer/pyppeteer/network_manager.py +0 -678
- biolib/pyppeteer/pyppeteer/options.py +0 -8
- biolib/pyppeteer/pyppeteer/page.py +0 -1728
- biolib/pyppeteer/pyppeteer/pipe_transport.py +0 -59
- biolib/pyppeteer/pyppeteer/target.py +0 -147
- biolib/pyppeteer/pyppeteer/task_queue.py +0 -24
- biolib/pyppeteer/pyppeteer/timeout_settings.py +0 -36
- biolib/pyppeteer/pyppeteer/tracing.py +0 -93
- biolib/pyppeteer/pyppeteer/us_keyboard_layout.py +0 -305
- biolib/pyppeteer/pyppeteer/util.py +0 -18
- biolib/pyppeteer/pyppeteer/websocket_transport.py +0 -47
- biolib/pyppeteer/pyppeteer/worker.py +0 -101
- biolib/pyppeteer/pyproject.toml +0 -97
- biolib/pyppeteer/spell.txt +0 -137
- biolib/pyppeteer/tox.ini +0 -72
- biolib/pyppeteer/utils/generate_protocol_types.py +0 -603
- biolib/start_cli.py +0 -7
- biolib/utils.py +0 -47
- biolib/validators/validate_app_version.py +0 -183
- biolib/validators/validate_argument.py +0 -134
- biolib/validators/validate_module.py +0 -323
- biolib/validators/validate_zip_file.py +0 -40
- biolib/validators/validator_utils.py +0 -103
- pybiolib-0.2.951.dist-info/LICENSE +0 -21
- pybiolib-0.2.951.dist-info/METADATA +0 -61
- pybiolib-0.2.951.dist-info/RECORD +0 -153
- pybiolib-0.2.951.dist-info/entry_points.txt +0 -3
- /LICENSE → /pybiolib-1.2.1890.dist-info/licenses/LICENSE +0 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import http.client
|
|
2
|
+
import json
|
|
3
|
+
import platform
|
|
4
|
+
import shutil
|
|
5
|
+
import socket
|
|
6
|
+
import ssl
|
|
7
|
+
import subprocess
|
|
8
|
+
import time
|
|
9
|
+
import urllib.error
|
|
10
|
+
import urllib.parse
|
|
11
|
+
import urllib.request
|
|
12
|
+
|
|
13
|
+
from biolib.biolib_logging import logger_no_user_data
|
|
14
|
+
from biolib.typing_utils import Dict, Literal, Optional, Union, cast
|
|
15
|
+
|
|
16
|
+
_HttpMethod = Literal['GET', 'POST', 'PATCH', 'PUT', 'DELETE']
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _create_ssl_context():
|
|
20
|
+
context = ssl.create_default_context()
|
|
21
|
+
try:
|
|
22
|
+
if platform.system() == 'Darwin':
|
|
23
|
+
certificates = subprocess.check_output('security find-certificate -a -p', shell=True).decode('utf-8')
|
|
24
|
+
context.load_verify_locations(cadata=certificates)
|
|
25
|
+
except BaseException:
|
|
26
|
+
pass
|
|
27
|
+
return context
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class HttpError(urllib.error.HTTPError):
|
|
31
|
+
def __init__(self, http_error: urllib.error.HTTPError):
|
|
32
|
+
super().__init__(
|
|
33
|
+
url=http_error.url,
|
|
34
|
+
code=http_error.code,
|
|
35
|
+
msg=http_error.msg, # type: ignore
|
|
36
|
+
hdrs=http_error.hdrs, # type: ignore
|
|
37
|
+
fp=http_error.fp,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def __str__(self):
|
|
41
|
+
response_text = self.read().decode('utf-8')
|
|
42
|
+
return f'{self.code} Error: {response_text} for url: {self.url}'
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class HttpResponse:
|
|
46
|
+
def __init__(self, response, response_path) -> None:
|
|
47
|
+
self.headers: Dict[str, str] = dict(response.headers)
|
|
48
|
+
self.status_code: int = int(response.status)
|
|
49
|
+
self.response_path = response_path
|
|
50
|
+
if self.response_path:
|
|
51
|
+
with open(self.response_path, 'wb') as out_file:
|
|
52
|
+
shutil.copyfileobj(response, out_file)
|
|
53
|
+
else:
|
|
54
|
+
self.content: bytes = response.read()
|
|
55
|
+
self.url: str = response.geturl()
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def text(self) -> str:
|
|
59
|
+
if self.response_path:
|
|
60
|
+
with open(self.response_path, 'rb') as fp:
|
|
61
|
+
return cast(str, fp.read().decode('utf-8'))
|
|
62
|
+
else:
|
|
63
|
+
return cast(str, self.content.decode('utf-8'))
|
|
64
|
+
|
|
65
|
+
def json(self):
|
|
66
|
+
return json.loads(self.text)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class HttpClient:
|
|
70
|
+
ssl_context = None
|
|
71
|
+
|
|
72
|
+
@staticmethod
|
|
73
|
+
def request(
|
|
74
|
+
url: str,
|
|
75
|
+
method: Optional[_HttpMethod] = None,
|
|
76
|
+
data: Optional[Union[Dict, bytes]] = None,
|
|
77
|
+
headers: Optional[Dict[str, str]] = None,
|
|
78
|
+
retries: int = 5,
|
|
79
|
+
timeout_in_seconds: Optional[int] = None,
|
|
80
|
+
response_path: Optional[str] = None,
|
|
81
|
+
retry_on_http_500: Optional[bool] = False,
|
|
82
|
+
max_content_length_in_bytes: Optional[int] = None,
|
|
83
|
+
) -> HttpResponse:
|
|
84
|
+
if not HttpClient.ssl_context:
|
|
85
|
+
HttpClient.ssl_context = _create_ssl_context()
|
|
86
|
+
headers_to_send = headers or {}
|
|
87
|
+
if isinstance(data, dict):
|
|
88
|
+
headers_to_send['Accept'] = 'application/json'
|
|
89
|
+
headers_to_send['Content-Type'] = 'application/json'
|
|
90
|
+
|
|
91
|
+
request = urllib.request.Request(
|
|
92
|
+
url=url,
|
|
93
|
+
data=json.dumps(data).encode() if isinstance(data, dict) else data,
|
|
94
|
+
headers=headers_to_send,
|
|
95
|
+
method=method or 'GET',
|
|
96
|
+
)
|
|
97
|
+
if timeout_in_seconds is None:
|
|
98
|
+
timeout_in_seconds = 60 if isinstance(data, dict) else 180 # TODO: Calculate timeout based on data size
|
|
99
|
+
|
|
100
|
+
last_error: Optional[Exception] = None
|
|
101
|
+
for retry_count in range(retries + 1):
|
|
102
|
+
if retry_count > 0:
|
|
103
|
+
time.sleep(5 * retry_count)
|
|
104
|
+
logger_no_user_data.debug(f'Retrying HTTP {method} request...')
|
|
105
|
+
try:
|
|
106
|
+
with urllib.request.urlopen(
|
|
107
|
+
request,
|
|
108
|
+
context=HttpClient.ssl_context,
|
|
109
|
+
timeout=timeout_in_seconds,
|
|
110
|
+
) as response:
|
|
111
|
+
if max_content_length_in_bytes:
|
|
112
|
+
content_length = response.getheader('Content-Length')
|
|
113
|
+
if not content_length:
|
|
114
|
+
raise ValueError('No Content-Length in response headers')
|
|
115
|
+
|
|
116
|
+
if int(content_length) > max_content_length_in_bytes:
|
|
117
|
+
raise ValueError(f'Content-Length exceeds {max_content_length_in_bytes} bytes')
|
|
118
|
+
|
|
119
|
+
return HttpResponse(response, response_path)
|
|
120
|
+
|
|
121
|
+
except urllib.error.HTTPError as error:
|
|
122
|
+
if error.code == 429:
|
|
123
|
+
logger_no_user_data.warning(f'HTTP {method} request failed with status 429 for "{url}"')
|
|
124
|
+
last_error = error
|
|
125
|
+
elif error.code == 500 and retry_on_http_500:
|
|
126
|
+
logger_no_user_data.warning(f'HTTP {method} request failed with status 500 for "{url}"')
|
|
127
|
+
last_error = error
|
|
128
|
+
elif error.code == 502:
|
|
129
|
+
logger_no_user_data.warning(f'HTTP {method} request failed with status 502 for "{url}"')
|
|
130
|
+
last_error = error
|
|
131
|
+
elif error.code == 503:
|
|
132
|
+
logger_no_user_data.warning(f'HTTP {method} request failed with status 503 for "{url}"')
|
|
133
|
+
last_error = error
|
|
134
|
+
elif error.code == 504:
|
|
135
|
+
logger_no_user_data.warning(f'HTTP {method} request failed with status 504 for "{url}"')
|
|
136
|
+
last_error = error
|
|
137
|
+
else:
|
|
138
|
+
raise HttpError(error) from None
|
|
139
|
+
|
|
140
|
+
except urllib.error.URLError as error:
|
|
141
|
+
if isinstance(error.reason, socket.timeout):
|
|
142
|
+
if retry_count > 0:
|
|
143
|
+
logger_no_user_data.warning(f'HTTP {method} request failed with read timeout for "{url}"')
|
|
144
|
+
last_error = error
|
|
145
|
+
else:
|
|
146
|
+
raise error
|
|
147
|
+
|
|
148
|
+
except socket.timeout as error:
|
|
149
|
+
if retry_count > 0:
|
|
150
|
+
logger_no_user_data.warning(f'HTTP {method} request failed with read timeout for "{url}"')
|
|
151
|
+
last_error = error
|
|
152
|
+
|
|
153
|
+
except http.client.IncompleteRead as error:
|
|
154
|
+
logger_no_user_data.warning(
|
|
155
|
+
f'HTTP {method} request failed with incomplete read for "{url}": {repr(error)}'
|
|
156
|
+
)
|
|
157
|
+
last_error = error
|
|
158
|
+
|
|
159
|
+
raise last_error or Exception(f'HTTP {method} request failed after {retries} retries for "{url}"')
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .cache import prune_lfs_cache
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
from datetime import datetime, timedelta, timezone
|
|
4
|
+
|
|
5
|
+
from biolib.biolib_logging import logger_no_user_data
|
|
6
|
+
from biolib.compute_node.job_worker.cache_state import LfsCacheState
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def prune_lfs_cache(dry_run: bool) -> None:
|
|
10
|
+
logger_no_user_data.info(f'Pruning LFS cache (dry run = {dry_run})...')
|
|
11
|
+
|
|
12
|
+
current_time = datetime.now(timezone.utc)
|
|
13
|
+
paths_to_delete = set()
|
|
14
|
+
|
|
15
|
+
with LfsCacheState() as state:
|
|
16
|
+
lfs_storage_path = f'{LfsCacheState().main_lfs_storage_path}/lfs'
|
|
17
|
+
if os.path.exists(lfs_storage_path):
|
|
18
|
+
for lfs_uuid in os.listdir(lfs_storage_path):
|
|
19
|
+
if lfs_uuid not in state['large_file_systems']:
|
|
20
|
+
path_to_delete = f'{lfs_storage_path}/{lfs_uuid}'
|
|
21
|
+
logger_no_user_data.info(f'Will delete path "{path_to_delete}" as it is not in cache state')
|
|
22
|
+
paths_to_delete.add(path_to_delete)
|
|
23
|
+
|
|
24
|
+
lfs_uuids_to_keep_in_state = set()
|
|
25
|
+
for lfs_uuid, lfs in state['large_file_systems'].items():
|
|
26
|
+
last_used_at = datetime.fromisoformat(lfs['last_used_at'])
|
|
27
|
+
if last_used_at.tzinfo is None:
|
|
28
|
+
last_used_at = last_used_at.replace(tzinfo=timezone.utc)
|
|
29
|
+
lfs_time_to_live_in_days = 60 if lfs['state'] == 'ready' else 7
|
|
30
|
+
|
|
31
|
+
if last_used_at < current_time - timedelta(days=lfs_time_to_live_in_days):
|
|
32
|
+
logger_no_user_data.info(f"Will delete LFS {lfs_uuid} as it was last used at {lfs['last_used_at']}")
|
|
33
|
+
partition = state['storage_partitions'][lfs['storage_partition_uuid']]
|
|
34
|
+
paths_to_delete.add(f"{partition['path']}/lfs/{lfs_uuid}")
|
|
35
|
+
if not dry_run:
|
|
36
|
+
partition['allocated_size_bytes'] -= lfs['size_bytes']
|
|
37
|
+
else:
|
|
38
|
+
logger_no_user_data.info(f'Keeping LFS "{lfs_uuid}"')
|
|
39
|
+
lfs_uuids_to_keep_in_state.add(lfs_uuid)
|
|
40
|
+
|
|
41
|
+
if not dry_run:
|
|
42
|
+
state['large_file_systems'] = {
|
|
43
|
+
key: value for key, value in state['large_file_systems'].items() if key in lfs_uuids_to_keep_in_state
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for path in paths_to_delete:
|
|
47
|
+
logger_no_user_data.info(f'Deleting {path}...')
|
|
48
|
+
if not dry_run:
|
|
49
|
+
subprocess.run(['rm', '-rf', path], check=True)
|
|
50
|
+
|
|
51
|
+
logger_no_user_data.info(f'Successfully deleted {len(paths_to_delete)}')
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Note: this directory is purely for libraries to be directly included instead of as dependencies
|