pybiolib 1.2.883__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 +33 -10
- biolib/_data_record/data_record.py +220 -126
- biolib/_index/index.py +55 -0
- biolib/_index/query_result.py +103 -0
- biolib/_internal/add_copilot_prompts.py +24 -11
- biolib/_internal/add_gui_files.py +81 -0
- biolib/_internal/data_record/__init__.py +1 -1
- biolib/_internal/data_record/data_record.py +1 -18
- biolib/_internal/data_record/push_data.py +65 -16
- biolib/_internal/data_record/remote_storage_endpoint.py +18 -13
- biolib/_internal/file_utils.py +48 -0
- biolib/_internal/lfs/cache.py +4 -2
- biolib/_internal/push_application.py +95 -24
- biolib/_internal/runtime.py +2 -0
- biolib/_internal/string_utils.py +13 -0
- biolib/_internal/{llm_instructions → templates/copilot_template}/.github/instructions/style-general.instructions.md +5 -0
- biolib/_internal/templates/copilot_template/.github/instructions/style-react-ts.instructions.md +47 -0
- biolib/_internal/templates/copilot_template/.github/prompts/biolib_onboard_repo.prompt.md +19 -0
- biolib/_internal/templates/dashboard_template/.biolib/config.yml +5 -0
- biolib/_internal/templates/{init_template → github_workflow_template}/.github/workflows/biolib.yml +7 -2
- 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 +1 -0
- biolib/_internal/templates/init_template/Dockerfile +5 -1
- biolib/_internal/templates/init_template/run.py +6 -15
- biolib/_internal/templates/init_template/run.sh +1 -0
- biolib/_internal/templates/templates.py +21 -1
- biolib/_internal/utils/__init__.py +47 -0
- biolib/_internal/utils/auth.py +46 -0
- biolib/_internal/utils/job_url.py +33 -0
- biolib/_internal/utils/multinode.py +12 -14
- biolib/_runtime/runtime.py +15 -2
- biolib/_session/session.py +7 -5
- 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/{_internal → _shared}/types/experiment.py +1 -0
- biolib/_shared/types/resource.py +37 -0
- biolib/_shared/types/resource_deploy_key.py +11 -0
- biolib/{_internal → _shared}/types/resource_version.py +8 -2
- biolib/_shared/types/user.py +19 -0
- biolib/_shared/utils/__init__.py +7 -0
- biolib/_shared/utils/resource_uri.py +75 -0
- biolib/api/client.py +5 -48
- biolib/app/app.py +97 -55
- biolib/biolib_api_client/api_client.py +3 -47
- biolib/biolib_api_client/app_types.py +1 -1
- biolib/biolib_api_client/biolib_app_api.py +31 -6
- biolib/biolib_api_client/biolib_job_api.py +1 -1
- biolib/biolib_api_client/user_state.py +34 -2
- biolib/biolib_binary_format/module_input.py +8 -0
- biolib/biolib_binary_format/remote_endpoints.py +3 -3
- biolib/biolib_binary_format/remote_stream_seeker.py +39 -25
- biolib/biolib_logging.py +1 -1
- biolib/cli/__init__.py +2 -2
- biolib/cli/auth.py +4 -16
- biolib/cli/data_record.py +82 -0
- biolib/cli/index.py +32 -0
- biolib/cli/init.py +393 -71
- biolib/cli/lfs.py +1 -1
- biolib/cli/run.py +9 -6
- biolib/cli/start.py +14 -1
- biolib/compute_node/job_worker/executors/docker_executor.py +31 -9
- biolib/compute_node/job_worker/executors/docker_types.py +1 -1
- biolib/compute_node/job_worker/executors/types.py +6 -5
- biolib/compute_node/job_worker/job_storage.py +2 -1
- biolib/compute_node/job_worker/job_worker.py +155 -90
- biolib/compute_node/job_worker/large_file_system.py +2 -6
- 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 +2 -2
- biolib/compute_node/remote_host_proxy.py +163 -79
- biolib/compute_node/utils.py +2 -0
- 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 +64 -19
- biolib/experiments/experiment.py +111 -16
- biolib/jobs/job.py +128 -31
- biolib/jobs/job_result.py +74 -34
- biolib/jobs/types.py +1 -0
- biolib/sdk/__init__.py +28 -3
- biolib/typing_utils.py +1 -1
- biolib/utils/cache_state.py +8 -5
- biolib/utils/multipart_uploader.py +24 -18
- biolib/utils/seq_util.py +1 -1
- pybiolib-1.2.1890.dist-info/METADATA +41 -0
- pybiolib-1.2.1890.dist-info/RECORD +177 -0
- {pybiolib-1.2.883.dist-info → pybiolib-1.2.1890.dist-info}/WHEEL +1 -1
- pybiolib-1.2.1890.dist-info/entry_points.txt +2 -0
- biolib/_internal/llm_instructions/.github/instructions/style-react-ts.instructions.md +0 -22
- biolib/_internal/templates/init_template/.gitignore +0 -2
- biolib/_internal/types/__init__.py +0 -6
- biolib/_internal/types/resource.py +0 -18
- biolib/biolib_download_container.py +0 -38
- biolib/cli/download_container.py +0 -14
- biolib/utils/app_uri.py +0 -57
- pybiolib-1.2.883.dist-info/METADATA +0 -50
- pybiolib-1.2.883.dist-info/RECORD +0 -148
- pybiolib-1.2.883.dist-info/entry_points.txt +0 -3
- /biolib/{_internal/llm_instructions → _index}/__init__.py +0 -0
- /biolib/_internal/{llm_instructions → templates/copilot_template}/.github/instructions/general-app-knowledge.instructions.md +0 -0
- /biolib/_internal/{llm_instructions → templates/copilot_template}/.github/instructions/style-python.instructions.md +0 -0
- /biolib/_internal/{llm_instructions → templates/copilot_template}/.github/prompts/biolib_app_inputs.prompt.md +0 -0
- /biolib/_internal/{llm_instructions → templates/copilot_template}/.github/prompts/biolib_run_apps.prompt.md +0 -0
- /biolib/{_internal → _shared}/types/app.py +0 -0
- /biolib/{_internal → _shared}/types/data_record.py +0 -0
- /biolib/{_internal → _shared}/types/file_node.py +0 -0
- /biolib/{_internal → _shared}/types/push.py +0 -0
- /biolib/{_internal → _shared}/types/resource_permission.py +0 -0
- /biolib/{_internal → _shared}/types/result.py +0 -0
- /biolib/{_internal → _shared}/types/typing.py +0 -0
- {pybiolib-1.2.883.dist-info → pybiolib-1.2.1890.dist-info/licenses}/LICENSE +0 -0
biolib/cli/run.py
CHANGED
|
@@ -13,19 +13,23 @@ from biolib.typing_utils import Optional, Tuple
|
|
|
13
13
|
help='Run an application on BioLib.',
|
|
14
14
|
)
|
|
15
15
|
@click.option('--experiment', type=str, required=False, help='Experiment name or URI to add the run to.')
|
|
16
|
-
@click.option('--local', is_flag=True, required=False,
|
|
16
|
+
@click.option('--local', is_flag=True, required=False, hidden=True)
|
|
17
17
|
@click.option('--non-blocking', is_flag=True, required=False, help='Run the application non blocking.')
|
|
18
18
|
@click.argument('uri', required=True)
|
|
19
19
|
@click.argument('args', nargs=-1, type=click.UNPROCESSED)
|
|
20
20
|
def run(experiment: Optional[str], local: bool, non_blocking: bool, uri: str, args: Tuple[str]) -> None:
|
|
21
|
+
if local:
|
|
22
|
+
print('Error: Running applications locally with --local is no longer supported.', file=sys.stderr)
|
|
23
|
+
sys.exit(1)
|
|
24
|
+
|
|
21
25
|
if experiment:
|
|
22
26
|
with Experiment(uri=experiment):
|
|
23
|
-
_run(
|
|
27
|
+
_run(non_blocking=non_blocking, uri=uri, args=args)
|
|
24
28
|
else:
|
|
25
|
-
_run(
|
|
29
|
+
_run(non_blocking=non_blocking, uri=uri, args=args)
|
|
26
30
|
|
|
27
31
|
|
|
28
|
-
def _run(
|
|
32
|
+
def _run(non_blocking: bool, uri: str, args: Tuple[str]) -> None:
|
|
29
33
|
try:
|
|
30
34
|
app = BioLibApp(uri=uri)
|
|
31
35
|
except biolib_errors.BioLibError as error:
|
|
@@ -43,12 +47,11 @@ def _run(local: bool, non_blocking: bool, uri: str, args: Tuple[str]) -> None:
|
|
|
43
47
|
args=list(args),
|
|
44
48
|
stdin=_get_stdin(),
|
|
45
49
|
files=None,
|
|
46
|
-
machine=('local' if local else ''),
|
|
47
50
|
blocking=blocking,
|
|
48
51
|
)
|
|
49
52
|
|
|
50
53
|
if blocking:
|
|
51
|
-
job.save_files('biolib_results')
|
|
54
|
+
job.save_files('biolib_results', overwrite=True)
|
|
52
55
|
|
|
53
56
|
# Write stdout and stderr if it has not been streamed (Markdown is not streamed)
|
|
54
57
|
if app.version.get('stdout_render_type') == 'markdown' or not sys.stdout.isatty():
|
biolib/cli/start.py
CHANGED
|
@@ -13,7 +13,10 @@ from biolib.typing_utils import Optional
|
|
|
13
13
|
@click.option('--port', default=5000, type=click.IntRange(1, 65_535), required=False)
|
|
14
14
|
@click.option('--tls-certificate', type=click.Path(exists=True), required=False, hidden=True)
|
|
15
15
|
@click.option('--tls-key', type=click.Path(exists=True), required=False, hidden=True)
|
|
16
|
-
|
|
16
|
+
@click.option('--initialize-network-buffer', is_flag=True, help='Initialize the remote host network buffer and exit')
|
|
17
|
+
def start(
|
|
18
|
+
host: str, port: int, tls_certificate: Optional[str], tls_key: Optional[str], initialize_network_buffer: bool
|
|
19
|
+
) -> None:
|
|
17
20
|
logger.configure(default_log_level=logging.INFO)
|
|
18
21
|
logger_no_user_data.configure(default_log_level=logging.INFO)
|
|
19
22
|
if platform.system() == 'Windows':
|
|
@@ -22,6 +25,16 @@ def start(host: str, port: int, tls_certificate: Optional[str], tls_key: Optiona
|
|
|
22
25
|
if tls_certificate and not tls_key or tls_key and not tls_certificate:
|
|
23
26
|
raise Exception('Options --tls-certificate and --tls-key must be specified together')
|
|
24
27
|
|
|
28
|
+
if initialize_network_buffer:
|
|
29
|
+
from biolib.compute_node.job_worker.network_buffer import ( # pylint: disable=import-outside-toplevel
|
|
30
|
+
NetworkBuffer,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
network_buffer = NetworkBuffer.get_instance()
|
|
34
|
+
created = network_buffer.fill_buffer()
|
|
35
|
+
logger_no_user_data.info(f'Initialized network buffer (created {created} networks)')
|
|
36
|
+
return
|
|
37
|
+
|
|
25
38
|
try:
|
|
26
39
|
from biolib.compute_node.webserver import webserver # pylint: disable=import-outside-toplevel
|
|
27
40
|
|
|
@@ -11,10 +11,10 @@ import zipfile
|
|
|
11
11
|
from copy import copy
|
|
12
12
|
from datetime import datetime
|
|
13
13
|
|
|
14
|
-
import docker
|
|
15
|
-
import docker.types
|
|
16
|
-
from docker.errors import APIError, ImageNotFound
|
|
17
|
-
from docker.models.containers import Container
|
|
14
|
+
import docker
|
|
15
|
+
import docker.types
|
|
16
|
+
from docker.errors import APIError, ImageNotFound
|
|
17
|
+
from docker.models.containers import Container
|
|
18
18
|
|
|
19
19
|
from biolib import utils
|
|
20
20
|
from biolib._internal.runtime import RuntimeJobDataDict
|
|
@@ -40,7 +40,7 @@ class DockerExecutor:
|
|
|
40
40
|
self._options: LocalExecutorOptions = options
|
|
41
41
|
self._is_cleaning_up = False
|
|
42
42
|
|
|
43
|
-
self._absolute_image_uri = f
|
|
43
|
+
self._absolute_image_uri = f'{utils.BIOLIB_SITE_HOSTNAME}/{self._options["module"]["image_uri"]}'
|
|
44
44
|
self._send_system_exception = options['send_system_exception']
|
|
45
45
|
self._send_stdout_and_stderr = options['send_stdout_and_stderr']
|
|
46
46
|
self._random_docker_id = compute_node_utils.random_string(15)
|
|
@@ -308,7 +308,8 @@ class DockerExecutor:
|
|
|
308
308
|
job_uuid = self._options['job']['public_id']
|
|
309
309
|
logger_no_user_data.debug(f'Job "{job_uuid}" initializing Docker container...')
|
|
310
310
|
module = self._options['module']
|
|
311
|
-
logger.debug(f
|
|
311
|
+
logger.debug(f'Initializing docker container with command: {module["command"]}')
|
|
312
|
+
docker_client = BiolibDockerClient.get_docker_client()
|
|
312
313
|
|
|
313
314
|
docker_volume_mounts = [lfs.docker_mount for lfs in self._options['large_file_systems'].values()]
|
|
314
315
|
|
|
@@ -318,10 +319,12 @@ class DockerExecutor:
|
|
|
318
319
|
biolib_system_secret = RuntimeJobDataDict(
|
|
319
320
|
version='1.0.0',
|
|
320
321
|
job_requested_machine=self._options['job']['requested_machine'],
|
|
322
|
+
job_requested_machine_spot=self._options['job'].get('requested_machine_spot', False),
|
|
321
323
|
job_uuid=self._options['job']['public_id'],
|
|
322
324
|
job_auth_token=self._options['job']['auth_token'],
|
|
323
325
|
app_uri=self._options['job']['app_uri'],
|
|
324
326
|
is_environment_biolib_cloud=bool(utils.IS_RUNNING_IN_CLOUD),
|
|
327
|
+
job_reserved_machines=self._options['job']['reserved_machines'],
|
|
325
328
|
)
|
|
326
329
|
docker_volume_mounts.append(
|
|
327
330
|
self._create_secrets_mount(
|
|
@@ -365,9 +368,11 @@ class DockerExecutor:
|
|
|
365
368
|
)
|
|
366
369
|
|
|
367
370
|
logger_no_user_data.debug(f'Job "{job_uuid}" initializing Docker container. Getting IPs for proxies...')
|
|
371
|
+
|
|
372
|
+
networks_to_connect = []
|
|
368
373
|
for proxy in self._options['remote_host_proxies']:
|
|
369
|
-
proxy_ip = proxy.get_ip_address_on_network(internal_network)
|
|
370
374
|
if proxy.is_app_caller_proxy:
|
|
375
|
+
proxy_ip = proxy.get_ip_address_on_network(internal_network)
|
|
371
376
|
logger_no_user_data.debug('Found app caller proxy, setting both base URLs in compute container')
|
|
372
377
|
environment_vars.update(
|
|
373
378
|
{
|
|
@@ -381,7 +386,11 @@ class DockerExecutor:
|
|
|
381
386
|
}
|
|
382
387
|
)
|
|
383
388
|
else:
|
|
384
|
-
extra_hosts
|
|
389
|
+
extra_hosts.update(proxy.get_hostname_to_ip_mapping())
|
|
390
|
+
|
|
391
|
+
for network in proxy.get_remote_host_networks():
|
|
392
|
+
if network != internal_network:
|
|
393
|
+
networks_to_connect.append(network)
|
|
385
394
|
|
|
386
395
|
logger_no_user_data.debug(f'Job "{job_uuid}" initializing Docker container. Constructing container args...')
|
|
387
396
|
create_container_args = {
|
|
@@ -391,6 +400,9 @@ class DockerExecutor:
|
|
|
391
400
|
'mounts': docker_volume_mounts,
|
|
392
401
|
'network': internal_network.name,
|
|
393
402
|
'working_dir': module['working_directory'],
|
|
403
|
+
'networking_config': {
|
|
404
|
+
internal_network.name: docker_client.api.create_endpoint_config(aliases=['main'])
|
|
405
|
+
},
|
|
394
406
|
}
|
|
395
407
|
|
|
396
408
|
if self._options['job'].get('arguments_override_command'):
|
|
@@ -429,9 +441,19 @@ class DockerExecutor:
|
|
|
429
441
|
if docker_runtime is not None:
|
|
430
442
|
create_container_args['runtime'] = docker_runtime
|
|
431
443
|
|
|
432
|
-
docker_client = BiolibDockerClient.get_docker_client()
|
|
433
444
|
logger_no_user_data.debug(f'Job "{job_uuid}" initializing Docker container. Creating container...')
|
|
434
445
|
self._docker_container = docker_client.containers.create(**create_container_args)
|
|
446
|
+
|
|
447
|
+
if networks_to_connect:
|
|
448
|
+
network_connection_start = time.time()
|
|
449
|
+
for network in networks_to_connect:
|
|
450
|
+
network.connect(self._docker_container.id)
|
|
451
|
+
logger_no_user_data.debug(f'Connected app container to network {network.name}')
|
|
452
|
+
network_connection_time = time.time() - network_connection_start
|
|
453
|
+
logger_no_user_data.debug(
|
|
454
|
+
f'Connected app container to {len(networks_to_connect)} networks in {network_connection_time:.2f}s'
|
|
455
|
+
)
|
|
456
|
+
|
|
435
457
|
logger_no_user_data.debug(f'Job "{job_uuid}" finished initializing Docker container.')
|
|
436
458
|
except Exception as exception:
|
|
437
459
|
raise ComputeProcessException(
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
from docker.models.networks import Network
|
|
1
|
+
from docker.models.networks import Network
|
|
2
2
|
|
|
3
|
+
from biolib.biolib_api_client.app_types import Module
|
|
4
|
+
from biolib.biolib_api_client.job_types import CloudJob, CreatedJobDict
|
|
3
5
|
from biolib.compute_node.job_worker.large_file_system import LargeFileSystem
|
|
4
|
-
from biolib.compute_node.webserver.webserver_types import ComputeNodeInfo
|
|
5
|
-
from biolib.typing_utils import TypedDict, Callable, Optional, List, Dict
|
|
6
6
|
from biolib.compute_node.remote_host_proxy import RemoteHostProxy
|
|
7
|
-
from biolib.
|
|
8
|
-
from biolib.
|
|
7
|
+
from biolib.compute_node.webserver.webserver_types import ComputeNodeInfo
|
|
8
|
+
from biolib.typing_utils import Callable, Dict, List, Optional, TypedDict
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class StatusUpdate(TypedDict):
|
|
@@ -43,6 +43,7 @@ class LocalExecutorOptions(TypedDict):
|
|
|
43
43
|
send_system_exception: SendSystemExceptionType
|
|
44
44
|
send_stdout_and_stderr: SendStdoutAndStderrType
|
|
45
45
|
|
|
46
|
+
|
|
46
47
|
class MetadataToSaveOutput(TypedDict):
|
|
47
48
|
arguments: List[str]
|
|
48
49
|
startup_error_string: Optional[str]
|
|
@@ -97,11 +97,12 @@ class JobStorage:
|
|
|
97
97
|
@staticmethod
|
|
98
98
|
def download_module_input(job: CreatedJobDict, path: str):
|
|
99
99
|
job_uuid = job['public_id']
|
|
100
|
-
logger_no_user_data.debug(f'Job "{job_uuid}"
|
|
100
|
+
logger_no_user_data.debug(f'Job "{job_uuid}" getting module input url...')
|
|
101
101
|
presigned_download_url = BiolibJobApi.get_job_storage_download_url(
|
|
102
102
|
job_uuid=job_uuid,
|
|
103
103
|
job_auth_token=job['auth_token'],
|
|
104
104
|
storage_type='input',
|
|
105
105
|
)
|
|
106
|
+
logger_no_user_data.debug(f'Job "{job_uuid}" downloading module input...')
|
|
106
107
|
HttpClient.request(url=presigned_download_url, response_path=path)
|
|
107
108
|
logger_no_user_data.debug(f'Job "{job_uuid}" module input downloaded')
|