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.
Files changed (262) hide show
  1. biolib/__init__.py +357 -11
  2. biolib/_data_record/data_record.py +380 -0
  3. biolib/_index/__init__.py +0 -0
  4. biolib/_index/index.py +55 -0
  5. biolib/_index/query_result.py +103 -0
  6. biolib/_internal/__init__.py +0 -0
  7. biolib/_internal/add_copilot_prompts.py +58 -0
  8. biolib/_internal/add_gui_files.py +81 -0
  9. biolib/_internal/data_record/__init__.py +1 -0
  10. biolib/_internal/data_record/data_record.py +85 -0
  11. biolib/_internal/data_record/push_data.py +116 -0
  12. biolib/_internal/data_record/remote_storage_endpoint.py +43 -0
  13. biolib/_internal/errors.py +5 -0
  14. biolib/_internal/file_utils.py +125 -0
  15. biolib/_internal/fuse_mount/__init__.py +1 -0
  16. biolib/_internal/fuse_mount/experiment_fuse_mount.py +209 -0
  17. biolib/_internal/http_client.py +159 -0
  18. biolib/_internal/lfs/__init__.py +1 -0
  19. biolib/_internal/lfs/cache.py +51 -0
  20. biolib/_internal/libs/__init__.py +1 -0
  21. biolib/_internal/libs/fusepy/__init__.py +1257 -0
  22. biolib/_internal/push_application.py +488 -0
  23. biolib/_internal/runtime.py +22 -0
  24. biolib/_internal/string_utils.py +13 -0
  25. biolib/_internal/templates/__init__.py +1 -0
  26. biolib/_internal/templates/copilot_template/.github/instructions/general-app-knowledge.instructions.md +10 -0
  27. biolib/_internal/templates/copilot_template/.github/instructions/style-general.instructions.md +20 -0
  28. biolib/_internal/templates/copilot_template/.github/instructions/style-python.instructions.md +16 -0
  29. biolib/_internal/templates/copilot_template/.github/instructions/style-react-ts.instructions.md +47 -0
  30. biolib/_internal/templates/copilot_template/.github/prompts/biolib_app_inputs.prompt.md +11 -0
  31. biolib/_internal/templates/copilot_template/.github/prompts/biolib_onboard_repo.prompt.md +19 -0
  32. biolib/_internal/templates/copilot_template/.github/prompts/biolib_run_apps.prompt.md +12 -0
  33. biolib/_internal/templates/dashboard_template/.biolib/config.yml +5 -0
  34. biolib/_internal/templates/github_workflow_template/.github/workflows/biolib.yml +21 -0
  35. biolib/_internal/templates/gitignore_template/.gitignore +10 -0
  36. biolib/_internal/templates/gui_template/.yarnrc.yml +1 -0
  37. biolib/_internal/templates/gui_template/App.tsx +53 -0
  38. biolib/_internal/templates/gui_template/Dockerfile +27 -0
  39. biolib/_internal/templates/gui_template/biolib-sdk.ts +82 -0
  40. biolib/_internal/templates/gui_template/dev-data/output.json +7 -0
  41. biolib/_internal/templates/gui_template/index.css +5 -0
  42. biolib/_internal/templates/gui_template/index.html +13 -0
  43. biolib/_internal/templates/gui_template/index.tsx +10 -0
  44. biolib/_internal/templates/gui_template/package.json +27 -0
  45. biolib/_internal/templates/gui_template/tsconfig.json +24 -0
  46. biolib/_internal/templates/gui_template/vite-plugin-dev-data.ts +50 -0
  47. biolib/_internal/templates/gui_template/vite.config.mts +10 -0
  48. biolib/_internal/templates/init_template/.biolib/config.yml +19 -0
  49. biolib/_internal/templates/init_template/Dockerfile +14 -0
  50. biolib/_internal/templates/init_template/requirements.txt +1 -0
  51. biolib/_internal/templates/init_template/run.py +12 -0
  52. biolib/_internal/templates/init_template/run.sh +4 -0
  53. biolib/_internal/templates/templates.py +25 -0
  54. biolib/_internal/tree_utils.py +106 -0
  55. biolib/_internal/utils/__init__.py +65 -0
  56. biolib/_internal/utils/auth.py +46 -0
  57. biolib/_internal/utils/job_url.py +33 -0
  58. biolib/_internal/utils/multinode.py +263 -0
  59. biolib/_runtime/runtime.py +157 -0
  60. biolib/_session/session.py +44 -0
  61. biolib/_shared/__init__.py +0 -0
  62. biolib/_shared/types/__init__.py +74 -0
  63. biolib/_shared/types/account.py +12 -0
  64. biolib/_shared/types/account_member.py +8 -0
  65. biolib/_shared/types/app.py +9 -0
  66. biolib/_shared/types/data_record.py +40 -0
  67. biolib/_shared/types/experiment.py +32 -0
  68. biolib/_shared/types/file_node.py +17 -0
  69. biolib/_shared/types/push.py +6 -0
  70. biolib/_shared/types/resource.py +37 -0
  71. biolib/_shared/types/resource_deploy_key.py +11 -0
  72. biolib/_shared/types/resource_permission.py +14 -0
  73. biolib/_shared/types/resource_version.py +19 -0
  74. biolib/_shared/types/result.py +14 -0
  75. biolib/_shared/types/typing.py +10 -0
  76. biolib/_shared/types/user.py +19 -0
  77. biolib/_shared/utils/__init__.py +7 -0
  78. biolib/_shared/utils/resource_uri.py +75 -0
  79. biolib/api/__init__.py +6 -0
  80. biolib/api/client.py +168 -0
  81. biolib/app/app.py +252 -49
  82. biolib/app/search_apps.py +45 -0
  83. biolib/biolib_api_client/api_client.py +126 -31
  84. biolib/biolib_api_client/app_types.py +24 -4
  85. biolib/biolib_api_client/auth.py +31 -8
  86. biolib/biolib_api_client/biolib_app_api.py +147 -52
  87. biolib/biolib_api_client/biolib_job_api.py +161 -141
  88. biolib/biolib_api_client/job_types.py +21 -5
  89. biolib/biolib_api_client/lfs_types.py +7 -23
  90. biolib/biolib_api_client/user_state.py +56 -0
  91. biolib/biolib_binary_format/__init__.py +1 -4
  92. biolib/biolib_binary_format/file_in_container.py +105 -0
  93. biolib/biolib_binary_format/module_input.py +24 -7
  94. biolib/biolib_binary_format/module_output_v2.py +149 -0
  95. biolib/biolib_binary_format/remote_endpoints.py +34 -0
  96. biolib/biolib_binary_format/remote_stream_seeker.py +59 -0
  97. biolib/biolib_binary_format/saved_job.py +3 -2
  98. biolib/biolib_binary_format/{attestation_document.py → stdout_and_stderr.py} +8 -8
  99. biolib/biolib_binary_format/system_status_update.py +3 -2
  100. biolib/biolib_binary_format/utils.py +175 -0
  101. biolib/biolib_docker_client/__init__.py +11 -2
  102. biolib/biolib_errors.py +36 -0
  103. biolib/biolib_logging.py +27 -10
  104. biolib/cli/__init__.py +38 -0
  105. biolib/cli/auth.py +46 -0
  106. biolib/cli/data_record.py +164 -0
  107. biolib/cli/index.py +32 -0
  108. biolib/cli/init.py +421 -0
  109. biolib/cli/lfs.py +101 -0
  110. biolib/cli/push.py +50 -0
  111. biolib/cli/run.py +63 -0
  112. biolib/cli/runtime.py +14 -0
  113. biolib/cli/sdk.py +16 -0
  114. biolib/cli/start.py +56 -0
  115. biolib/compute_node/cloud_utils/cloud_utils.py +110 -161
  116. biolib/compute_node/job_worker/cache_state.py +66 -88
  117. biolib/compute_node/job_worker/cache_types.py +1 -6
  118. biolib/compute_node/job_worker/docker_image_cache.py +112 -37
  119. biolib/compute_node/job_worker/executors/__init__.py +0 -3
  120. biolib/compute_node/job_worker/executors/docker_executor.py +532 -199
  121. biolib/compute_node/job_worker/executors/docker_types.py +9 -1
  122. biolib/compute_node/job_worker/executors/types.py +19 -9
  123. biolib/compute_node/job_worker/job_legacy_input_wait_timeout_thread.py +30 -0
  124. biolib/compute_node/job_worker/job_max_runtime_timer_thread.py +3 -5
  125. biolib/compute_node/job_worker/job_storage.py +108 -0
  126. biolib/compute_node/job_worker/job_worker.py +397 -212
  127. biolib/compute_node/job_worker/large_file_system.py +87 -38
  128. biolib/compute_node/job_worker/network_alloc.py +99 -0
  129. biolib/compute_node/job_worker/network_buffer.py +240 -0
  130. biolib/compute_node/job_worker/utilization_reporter_thread.py +197 -0
  131. biolib/compute_node/job_worker/utils.py +9 -24
  132. biolib/compute_node/remote_host_proxy.py +400 -98
  133. biolib/compute_node/utils.py +31 -9
  134. biolib/compute_node/webserver/compute_node_results_proxy.py +189 -0
  135. biolib/compute_node/webserver/proxy_utils.py +28 -0
  136. biolib/compute_node/webserver/webserver.py +130 -44
  137. biolib/compute_node/webserver/webserver_types.py +2 -6
  138. biolib/compute_node/webserver/webserver_utils.py +77 -12
  139. biolib/compute_node/webserver/worker_thread.py +183 -42
  140. biolib/experiments/__init__.py +0 -0
  141. biolib/experiments/experiment.py +356 -0
  142. biolib/jobs/__init__.py +1 -0
  143. biolib/jobs/job.py +741 -0
  144. biolib/jobs/job_result.py +185 -0
  145. biolib/jobs/types.py +50 -0
  146. biolib/py.typed +0 -0
  147. biolib/runtime/__init__.py +14 -0
  148. biolib/sdk/__init__.py +91 -0
  149. biolib/tables.py +34 -0
  150. biolib/typing_utils.py +2 -7
  151. biolib/user/__init__.py +1 -0
  152. biolib/user/sign_in.py +54 -0
  153. biolib/utils/__init__.py +162 -0
  154. biolib/utils/cache_state.py +94 -0
  155. biolib/utils/multipart_uploader.py +194 -0
  156. biolib/utils/seq_util.py +150 -0
  157. biolib/utils/zip/remote_zip.py +640 -0
  158. pybiolib-1.2.1890.dist-info/METADATA +41 -0
  159. pybiolib-1.2.1890.dist-info/RECORD +177 -0
  160. {pybiolib-0.2.951.dist-info → pybiolib-1.2.1890.dist-info}/WHEEL +1 -1
  161. pybiolib-1.2.1890.dist-info/entry_points.txt +2 -0
  162. README.md +0 -17
  163. biolib/app/app_result.py +0 -68
  164. biolib/app/utils.py +0 -62
  165. biolib/biolib-js/0-biolib.worker.js +0 -1
  166. biolib/biolib-js/1-biolib.worker.js +0 -1
  167. biolib/biolib-js/2-biolib.worker.js +0 -1
  168. biolib/biolib-js/3-biolib.worker.js +0 -1
  169. biolib/biolib-js/4-biolib.worker.js +0 -1
  170. biolib/biolib-js/5-biolib.worker.js +0 -1
  171. biolib/biolib-js/6-biolib.worker.js +0 -1
  172. biolib/biolib-js/index.html +0 -10
  173. biolib/biolib-js/main-biolib.js +0 -1
  174. biolib/biolib_api_client/biolib_account_api.py +0 -21
  175. biolib/biolib_api_client/biolib_large_file_system_api.py +0 -108
  176. biolib/biolib_binary_format/aes_encrypted_package.py +0 -42
  177. biolib/biolib_binary_format/module_output.py +0 -58
  178. biolib/biolib_binary_format/rsa_encrypted_aes_package.py +0 -57
  179. biolib/biolib_push.py +0 -114
  180. biolib/cli.py +0 -203
  181. biolib/cli_utils.py +0 -273
  182. biolib/compute_node/cloud_utils/enclave_parent_types.py +0 -7
  183. biolib/compute_node/enclave/__init__.py +0 -2
  184. biolib/compute_node/enclave/enclave_remote_hosts.py +0 -53
  185. biolib/compute_node/enclave/nitro_secure_module_utils.py +0 -64
  186. biolib/compute_node/job_worker/executors/base_executor.py +0 -18
  187. biolib/compute_node/job_worker/executors/pyppeteer_executor.py +0 -173
  188. biolib/compute_node/job_worker/executors/remote/__init__.py +0 -1
  189. biolib/compute_node/job_worker/executors/remote/nitro_enclave_utils.py +0 -81
  190. biolib/compute_node/job_worker/executors/remote/remote_executor.py +0 -51
  191. biolib/lfs.py +0 -196
  192. biolib/pyppeteer/.circleci/config.yml +0 -100
  193. biolib/pyppeteer/.coveragerc +0 -3
  194. biolib/pyppeteer/.gitignore +0 -89
  195. biolib/pyppeteer/.pre-commit-config.yaml +0 -28
  196. biolib/pyppeteer/CHANGES.md +0 -253
  197. biolib/pyppeteer/CONTRIBUTING.md +0 -26
  198. biolib/pyppeteer/LICENSE +0 -12
  199. biolib/pyppeteer/README.md +0 -137
  200. biolib/pyppeteer/docs/Makefile +0 -177
  201. biolib/pyppeteer/docs/_static/custom.css +0 -28
  202. biolib/pyppeteer/docs/_templates/layout.html +0 -10
  203. biolib/pyppeteer/docs/changes.md +0 -1
  204. biolib/pyppeteer/docs/conf.py +0 -299
  205. biolib/pyppeteer/docs/index.md +0 -21
  206. biolib/pyppeteer/docs/make.bat +0 -242
  207. biolib/pyppeteer/docs/reference.md +0 -211
  208. biolib/pyppeteer/docs/server.py +0 -60
  209. biolib/pyppeteer/poetry.lock +0 -1699
  210. biolib/pyppeteer/pyppeteer/__init__.py +0 -135
  211. biolib/pyppeteer/pyppeteer/accessibility.py +0 -286
  212. biolib/pyppeteer/pyppeteer/browser.py +0 -401
  213. biolib/pyppeteer/pyppeteer/browser_fetcher.py +0 -194
  214. biolib/pyppeteer/pyppeteer/command.py +0 -22
  215. biolib/pyppeteer/pyppeteer/connection/__init__.py +0 -242
  216. biolib/pyppeteer/pyppeteer/connection/cdpsession.py +0 -101
  217. biolib/pyppeteer/pyppeteer/coverage.py +0 -346
  218. biolib/pyppeteer/pyppeteer/device_descriptors.py +0 -787
  219. biolib/pyppeteer/pyppeteer/dialog.py +0 -79
  220. biolib/pyppeteer/pyppeteer/domworld.py +0 -597
  221. biolib/pyppeteer/pyppeteer/emulation_manager.py +0 -53
  222. biolib/pyppeteer/pyppeteer/errors.py +0 -48
  223. biolib/pyppeteer/pyppeteer/events.py +0 -63
  224. biolib/pyppeteer/pyppeteer/execution_context.py +0 -156
  225. biolib/pyppeteer/pyppeteer/frame/__init__.py +0 -299
  226. biolib/pyppeteer/pyppeteer/frame/frame_manager.py +0 -306
  227. biolib/pyppeteer/pyppeteer/helpers.py +0 -245
  228. biolib/pyppeteer/pyppeteer/input.py +0 -371
  229. biolib/pyppeteer/pyppeteer/jshandle.py +0 -598
  230. biolib/pyppeteer/pyppeteer/launcher.py +0 -683
  231. biolib/pyppeteer/pyppeteer/lifecycle_watcher.py +0 -169
  232. biolib/pyppeteer/pyppeteer/models/__init__.py +0 -103
  233. biolib/pyppeteer/pyppeteer/models/_protocol.py +0 -12460
  234. biolib/pyppeteer/pyppeteer/multimap.py +0 -82
  235. biolib/pyppeteer/pyppeteer/network_manager.py +0 -678
  236. biolib/pyppeteer/pyppeteer/options.py +0 -8
  237. biolib/pyppeteer/pyppeteer/page.py +0 -1728
  238. biolib/pyppeteer/pyppeteer/pipe_transport.py +0 -59
  239. biolib/pyppeteer/pyppeteer/target.py +0 -147
  240. biolib/pyppeteer/pyppeteer/task_queue.py +0 -24
  241. biolib/pyppeteer/pyppeteer/timeout_settings.py +0 -36
  242. biolib/pyppeteer/pyppeteer/tracing.py +0 -93
  243. biolib/pyppeteer/pyppeteer/us_keyboard_layout.py +0 -305
  244. biolib/pyppeteer/pyppeteer/util.py +0 -18
  245. biolib/pyppeteer/pyppeteer/websocket_transport.py +0 -47
  246. biolib/pyppeteer/pyppeteer/worker.py +0 -101
  247. biolib/pyppeteer/pyproject.toml +0 -97
  248. biolib/pyppeteer/spell.txt +0 -137
  249. biolib/pyppeteer/tox.ini +0 -72
  250. biolib/pyppeteer/utils/generate_protocol_types.py +0 -603
  251. biolib/start_cli.py +0 -7
  252. biolib/utils.py +0 -47
  253. biolib/validators/validate_app_version.py +0 -183
  254. biolib/validators/validate_argument.py +0 -134
  255. biolib/validators/validate_module.py +0 -323
  256. biolib/validators/validate_zip_file.py +0 -40
  257. biolib/validators/validator_utils.py +0 -103
  258. pybiolib-0.2.951.dist-info/LICENSE +0 -21
  259. pybiolib-0.2.951.dist-info/METADATA +0 -61
  260. pybiolib-0.2.951.dist-info/RECORD +0 -153
  261. pybiolib-0.2.951.dist-info/entry_points.txt +0 -3
  262. /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