pybiolib 1.2.558__py3-none-any.whl → 1.2.565__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 +193 -0
- biolib/compute_node/job_worker/executors/docker_executor.py +2 -10
- biolib/compute_node/job_worker/executors/types.py +0 -1
- {pybiolib-1.2.558.dist-info → pybiolib-1.2.565.dist-info}/METADATA +1 -1
- {pybiolib-1.2.558.dist-info → pybiolib-1.2.565.dist-info}/RECORD +8 -8
- {pybiolib-1.2.558.dist-info → pybiolib-1.2.565.dist-info}/LICENSE +0 -0
- {pybiolib-1.2.558.dist-info → pybiolib-1.2.565.dist-info}/WHEEL +0 -0
- {pybiolib-1.2.558.dist-info → pybiolib-1.2.565.dist-info}/entry_points.txt +0 -0
biolib/__init__.py
CHANGED
@@ -29,6 +29,24 @@ def call_cli() -> None:
|
|
29
29
|
|
30
30
|
|
31
31
|
def load(uri: str) -> _BioLibApp:
|
32
|
+
r"""Load a BioLib application by its URI or website URL.
|
33
|
+
|
34
|
+
Args:
|
35
|
+
uri (str): The URI or website URL of the application to load. Can be either:
|
36
|
+
- App URI (e.g., 'biolib/myapp:1.0.0')
|
37
|
+
- Website URL (e.g., 'https://biolib.com/biolib/myapp/')
|
38
|
+
|
39
|
+
Returns:
|
40
|
+
BioLibApp: The loaded application object
|
41
|
+
|
42
|
+
Example::
|
43
|
+
|
44
|
+
>>> # Load by URI
|
45
|
+
>>> app = biolib.load('biolib/myapp:1.0.0')
|
46
|
+
>>> # Load by website URL
|
47
|
+
>>> app = biolib.load('https://biolib.com/biolib/myapp/')
|
48
|
+
>>> result = app.cli('--help')
|
49
|
+
"""
|
32
50
|
return _BioLibApp(uri)
|
33
51
|
|
34
52
|
|
@@ -37,27 +55,126 @@ def search(
|
|
37
55
|
team: Optional[str] = None,
|
38
56
|
count: int = 100,
|
39
57
|
) -> List[str]:
|
58
|
+
r"""Search for BioLib applications.
|
59
|
+
|
60
|
+
Args:
|
61
|
+
search_query (str, optional): Search query string
|
62
|
+
team (str, optional): Filter by team name
|
63
|
+
count (int): Maximum number of results to return. Defaults to 100.
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
List[str]: List of application URIs matching the search criteria
|
67
|
+
|
68
|
+
Example::
|
69
|
+
|
70
|
+
>>> # Search all apps
|
71
|
+
>>> apps = biolib.search()
|
72
|
+
>>> # Search by query
|
73
|
+
>>> alignment_apps = biolib.search('alignment')
|
74
|
+
>>> # Search team's apps
|
75
|
+
>>> team_apps = biolib.search(team='myteam')
|
76
|
+
"""
|
40
77
|
apps: List[str] = search_apps(search_query, team, count)
|
41
78
|
return apps
|
42
79
|
|
43
80
|
|
44
81
|
def get_job(job_id: str, job_token: Optional[str] = None) -> _Job:
|
82
|
+
r"""Get a job by its ID.
|
83
|
+
|
84
|
+
Args:
|
85
|
+
job_id (str): The UUID of the job to retrieve
|
86
|
+
job_token (str, optional): Authentication token for accessing the job.
|
87
|
+
Only needed for jobs that aren't owned by the current user.
|
88
|
+
|
89
|
+
Returns:
|
90
|
+
Job: The job object
|
91
|
+
|
92
|
+
Example::
|
93
|
+
|
94
|
+
>>> job = biolib.get_job('abc123')
|
95
|
+
>>> # Access shared job
|
96
|
+
>>> job = biolib.get_job('abc123', job_token='xyz789')
|
97
|
+
"""
|
45
98
|
return _Job.create_from_uuid(uuid=job_id, auth_token=job_token)
|
46
99
|
|
47
100
|
|
48
101
|
def get_data_record(uri: str) -> _DataRecord:
|
102
|
+
r"""Get a data record by its URI.
|
103
|
+
|
104
|
+
Args:
|
105
|
+
uri (str): The URI of the data record to retrieve
|
106
|
+
|
107
|
+
Returns:
|
108
|
+
DataRecord: The data record object
|
109
|
+
|
110
|
+
Example::
|
111
|
+
|
112
|
+
>>> record = biolib.get_data_record('biolib/data/sequences:1.0.0')
|
113
|
+
"""
|
49
114
|
return _DataRecord.get_by_uri(uri)
|
50
115
|
|
51
116
|
|
52
117
|
def fetch_jobs(count: int = 25, status: Optional[str] = None) -> List[_Job]:
|
118
|
+
r"""Fetch a list of jobs from the server.
|
119
|
+
|
120
|
+
Args:
|
121
|
+
count (int): Maximum number of jobs to fetch. Defaults to 25.
|
122
|
+
status (str, optional): Filter jobs by status. One of:
|
123
|
+
'in_progress', 'completed', 'failed', 'cancelled'
|
124
|
+
|
125
|
+
Returns:
|
126
|
+
List[Job]: List of job objects matching the criteria
|
127
|
+
|
128
|
+
Example::
|
129
|
+
|
130
|
+
>>> # Get last 10 completed jobs
|
131
|
+
>>> jobs = biolib.fetch_jobs(10, status='completed')
|
132
|
+
>>> # Get last 100 jobs of any status
|
133
|
+
>>> all_jobs = biolib.fetch_jobs(100)
|
134
|
+
"""
|
53
135
|
return _Job.fetch_jobs(count, status)
|
54
136
|
|
55
137
|
|
56
138
|
def fetch_data_records(uri: Optional[str] = None, count: Optional[int] = None) -> List[_DataRecord]:
|
139
|
+
r"""Fetch a list of data records from the server.
|
140
|
+
|
141
|
+
Args:
|
142
|
+
uri (str, optional): Filter records by URI prefix
|
143
|
+
count (int, optional): Maximum number of records to fetch
|
144
|
+
|
145
|
+
Returns:
|
146
|
+
List[DataRecord]: List of data record objects matching the criteria
|
147
|
+
|
148
|
+
Example::
|
149
|
+
|
150
|
+
>>> # Get all records
|
151
|
+
>>> records = biolib.fetch_data_records()
|
152
|
+
>>> # Get records with URI prefix
|
153
|
+
>>> seq_records = biolib.fetch_data_records('biolib/data/sequences')
|
154
|
+
"""
|
57
155
|
return _DataRecord.fetch(uri, count)
|
58
156
|
|
59
157
|
|
60
158
|
def get_experiment(uri: Optional[str] = None, name: Optional[str] = None) -> Experiment:
|
159
|
+
r"""Get an experiment by its URI or name.
|
160
|
+
|
161
|
+
Args:
|
162
|
+
uri (str, optional): The URI of the experiment
|
163
|
+
name (str, optional): The name of the experiment
|
164
|
+
|
165
|
+
Returns:
|
166
|
+
Experiment: The experiment object
|
167
|
+
|
168
|
+
Raises:
|
169
|
+
ValueError: If neither or both uri and name are provided
|
170
|
+
|
171
|
+
Example::
|
172
|
+
|
173
|
+
>>> # Get by URI
|
174
|
+
>>> exp = biolib.get_experiment(uri='biolib/experiments/analysis')
|
175
|
+
>>> # Get by name
|
176
|
+
>>> exp = biolib.get_experiment(name='sequence-analysis')
|
177
|
+
"""
|
61
178
|
if (not uri and not name) or (uri and name):
|
62
179
|
raise ValueError('Must provide either uri or name')
|
63
180
|
|
@@ -65,10 +182,30 @@ def get_experiment(uri: Optional[str] = None, name: Optional[str] = None) -> Exp
|
|
65
182
|
|
66
183
|
|
67
184
|
def show_jobs(count: int = 25) -> None:
|
185
|
+
r"""Display a table of recent jobs.
|
186
|
+
|
187
|
+
Args:
|
188
|
+
count (int): Maximum number of jobs to display. Defaults to 25.
|
189
|
+
|
190
|
+
Example::
|
191
|
+
|
192
|
+
>>> biolib.show_jobs() # Show last 25 jobs
|
193
|
+
>>> biolib.show_jobs(100) # Show last 100 jobs
|
194
|
+
"""
|
68
195
|
_Job.show_jobs(count=count)
|
69
196
|
|
70
197
|
|
71
198
|
def show_experiments(count: int = 25) -> None:
|
199
|
+
r"""Display a table of experiments.
|
200
|
+
|
201
|
+
Args:
|
202
|
+
count (int): Maximum number of experiments to display. Defaults to 25.
|
203
|
+
|
204
|
+
Example::
|
205
|
+
|
206
|
+
>>> biolib.show_experiments() # Show last 25 experiments
|
207
|
+
>>> biolib.show_experiments(100) # Show last 100 experiments
|
208
|
+
"""
|
72
209
|
Experiment.show_experiments(count=count)
|
73
210
|
|
74
211
|
|
@@ -81,14 +218,39 @@ def sign_out() -> None:
|
|
81
218
|
|
82
219
|
|
83
220
|
def login() -> None:
|
221
|
+
r"""Alias for :func:`sign_in`.
|
222
|
+
|
223
|
+
Example::
|
224
|
+
|
225
|
+
>>> biolib.login() # Same as biolib.sign_in()
|
226
|
+
"""
|
84
227
|
sign_in()
|
85
228
|
|
86
229
|
|
87
230
|
def logout() -> None:
|
231
|
+
r"""Alias for :func:`sign_out`.
|
232
|
+
|
233
|
+
Example::
|
234
|
+
|
235
|
+
>>> biolib.logout() # Same as biolib.sign_out()
|
236
|
+
"""
|
88
237
|
sign_out()
|
89
238
|
|
90
239
|
|
91
240
|
def set_api_base_url(api_base_url: str) -> None:
|
241
|
+
r"""Set the base URL for the BioLib API.
|
242
|
+
|
243
|
+
Args:
|
244
|
+
api_base_url (str): The base URL for the BioLib API
|
245
|
+
|
246
|
+
Example::
|
247
|
+
|
248
|
+
>>> biolib.set_api_base_url('https://biolib.com')
|
249
|
+
|
250
|
+
Note:
|
251
|
+
This will also update related configuration like site hostname
|
252
|
+
and environment flags.
|
253
|
+
"""
|
92
254
|
_BioLibApiClient.initialize(base_url=api_base_url)
|
93
255
|
biolib.utils.BIOLIB_BASE_URL = api_base_url
|
94
256
|
biolib.utils.BIOLIB_SITE_HOSTNAME = _urlparse(api_base_url).hostname
|
@@ -98,15 +260,46 @@ def set_api_base_url(api_base_url: str) -> None:
|
|
98
260
|
|
99
261
|
|
100
262
|
def set_base_url(base_url: str) -> None:
|
263
|
+
r"""Alias for :func:`set_api_base_url`.
|
264
|
+
|
265
|
+
Args:
|
266
|
+
base_url (str): The base URL for the BioLib API
|
267
|
+
|
268
|
+
Example::
|
269
|
+
|
270
|
+
>>> biolib.set_base_url('https://biolib.com')
|
271
|
+
"""
|
101
272
|
return set_api_base_url(base_url)
|
102
273
|
|
103
274
|
|
104
275
|
def set_api_token(api_token: str) -> None:
|
276
|
+
r"""Sign in using an API token.
|
277
|
+
|
278
|
+
Args:
|
279
|
+
api_token (str): The API token to authenticate with
|
280
|
+
|
281
|
+
Example::
|
282
|
+
|
283
|
+
>>> biolib.set_api_token('my-api-token')
|
284
|
+
# Signed in using API token
|
285
|
+
"""
|
105
286
|
api_client = _BioLibApiClient.get()
|
106
287
|
api_client.sign_in_with_api_token(api_token)
|
107
288
|
|
108
289
|
|
109
290
|
def set_log_level(level: _typing_utils.Union[str, int]) -> None:
|
291
|
+
r"""Set the logging level for BioLib.
|
292
|
+
|
293
|
+
Args:
|
294
|
+
level (Union[str, int]): The log level to use. Can be a string
|
295
|
+
('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL') or an integer
|
296
|
+
level from the logging module.
|
297
|
+
|
298
|
+
Example::
|
299
|
+
|
300
|
+
>>> biolib.set_log_level('DEBUG') # Enable debug logging
|
301
|
+
>>> biolib.set_log_level('WARNING') # Only show warnings and errors
|
302
|
+
"""
|
110
303
|
_logger.setLevel(level)
|
111
304
|
_logger_no_user_data.setLevel(level)
|
112
305
|
|
@@ -201,9 +201,6 @@ class DockerExecutor:
|
|
201
201
|
stream=True,
|
202
202
|
)
|
203
203
|
|
204
|
-
logger_no_user_data.debug(f'Running diff for Docker container for {job_uuid}')
|
205
|
-
pre_start_diff = self._container.diff()
|
206
|
-
|
207
204
|
logger_no_user_data.debug(f'Starting Docker container for {job_uuid}')
|
208
205
|
startup_error_string: Optional[str] = None
|
209
206
|
try:
|
@@ -218,7 +215,6 @@ class DockerExecutor:
|
|
218
215
|
self._metadata_for_save_output_on_cancel = MetadataToSaveOutput(
|
219
216
|
arguments=module_input['arguments'],
|
220
217
|
startup_error_string=startup_error_string,
|
221
|
-
pre_start_diff=pre_start_diff,
|
222
218
|
)
|
223
219
|
|
224
220
|
if self._options['job']['app_version'].get('stdout_render_type') != 'markdown':
|
@@ -264,7 +260,6 @@ class DockerExecutor:
|
|
264
260
|
module_output_path=self._options['module_output_path'],
|
265
261
|
stderr=full_stderr,
|
266
262
|
stdout=full_stdout,
|
267
|
-
pre_start_diff=metadata['pre_start_diff'],
|
268
263
|
)
|
269
264
|
|
270
265
|
def cleanup(self):
|
@@ -532,12 +527,11 @@ class DockerExecutor:
|
|
532
527
|
module_output_path: str,
|
533
528
|
stderr: bytes,
|
534
529
|
stdout: bytes,
|
535
|
-
pre_start_diff: List[Dict],
|
536
530
|
) -> None:
|
537
531
|
mapped_files: List[FileInContainer] = []
|
538
532
|
try:
|
539
533
|
mappings = Mappings(mappings_list=self._options['module']['output_files_mappings'], arguments=arguments)
|
540
|
-
changed_files: List[FileInContainer] = self._get_changed_files_in_docker_container(
|
534
|
+
changed_files: List[FileInContainer] = self._get_changed_files_in_docker_container()
|
541
535
|
|
542
536
|
for file in changed_files:
|
543
537
|
if file.is_file():
|
@@ -602,15 +596,13 @@ class DockerExecutor:
|
|
602
596
|
|
603
597
|
return None
|
604
598
|
|
605
|
-
def _get_changed_files_in_docker_container(self
|
599
|
+
def _get_changed_files_in_docker_container(self) -> List[FileInContainer]:
|
606
600
|
from_mappings = [mapping['from_path'] for mapping in self._options['module']['output_files_mappings']]
|
607
|
-
pre_start_diff_paths = [obj['Path'] for obj in pre_start_diff]
|
608
601
|
post_run_diff = self._container.diff()
|
609
602
|
run_diff_paths: List[str] = [
|
610
603
|
obj['Path']
|
611
604
|
for obj in post_run_diff
|
612
605
|
if obj['Kind'] in (DockerDiffKind.CHANGED.value, DockerDiffKind.ADDED.value)
|
613
|
-
and obj['Path'] not in pre_start_diff_paths
|
614
606
|
]
|
615
607
|
|
616
608
|
known_directories = set()
|
@@ -1,4 +1,4 @@
|
|
1
|
-
biolib/__init__.py,sha256=
|
1
|
+
biolib/__init__.py,sha256=nPgMXXoJ4wqGwDqMgwtAYrw_-GVMdaWwKemOpRKKljU,9774
|
2
2
|
biolib/_data_record/data_record.py,sha256=zKvnh5T-dIVY46-kgVzMBoZ666ZhcTCFQnWvZT0D6RM,12026
|
3
3
|
biolib/_internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
biolib/_internal/data_record/__init__.py,sha256=fGdME6JGRU_2VxpJbYpGXYndjN-feUkmKY4fuMyq3cg,76
|
@@ -76,10 +76,10 @@ 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=RBBPjxL-zqI77vHWG7ssrFGFSsHVob7TuIMw36URPQ0,31111
|
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=wbjWZZ2f9FttjqUCCOeZmn7n3L3Hu-7-2PZJ3BVf_Ps,1626
|
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
|
@@ -119,8 +119,8 @@ biolib/utils/cache_state.py,sha256=u256F37QSRIVwqKlbnCyzAX4EMI-kl6Dwu6qwj-Qmag,3
|
|
119
119
|
biolib/utils/multipart_uploader.py,sha256=XvGP1I8tQuKhAH-QugPRoEsCi9qvbRk-DVBs5PNwwJo,8452
|
120
120
|
biolib/utils/seq_util.py,sha256=Ozk0blGtPur_D9MwShD02r_mphyQmgZkx-lOHOwnlIM,6730
|
121
121
|
biolib/utils/zip/remote_zip.py,sha256=0wErYlxir5921agfFeV1xVjf29l9VNgGQvNlWOlj2Yc,23232
|
122
|
-
pybiolib-1.2.
|
123
|
-
pybiolib-1.2.
|
124
|
-
pybiolib-1.2.
|
125
|
-
pybiolib-1.2.
|
126
|
-
pybiolib-1.2.
|
122
|
+
pybiolib-1.2.565.dist-info/LICENSE,sha256=F2h7gf8i0agDIeWoBPXDMYScvQOz02pAWkKhTGOHaaw,1067
|
123
|
+
pybiolib-1.2.565.dist-info/METADATA,sha256=_CM-jsOMgyM_KMENpfQz0auad3iMgTcoiGDKlvfTcC8,1570
|
124
|
+
pybiolib-1.2.565.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
125
|
+
pybiolib-1.2.565.dist-info/entry_points.txt,sha256=p6DyaP_2kctxegTX23WBznnrDi4mz6gx04O5uKtRDXg,42
|
126
|
+
pybiolib-1.2.565.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|