pybiolib 1.2.576__py3-none-any.whl → 1.2.589__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/_session/session.py +39 -0
- biolib/api/client.py +106 -17
- biolib/app/app.py +7 -3
- biolib/biolib_api_client/biolib_app_api.py +4 -2
- biolib/biolib_api_client/biolib_job_api.py +42 -39
- biolib/jobs/job.py +35 -9
- biolib/sdk/__init__.py +5 -0
- {pybiolib-1.2.576.dist-info → pybiolib-1.2.589.dist-info}/METADATA +1 -1
- {pybiolib-1.2.576.dist-info → pybiolib-1.2.589.dist-info}/RECORD +12 -11
- {pybiolib-1.2.576.dist-info → pybiolib-1.2.589.dist-info}/LICENSE +0 -0
- {pybiolib-1.2.576.dist-info → pybiolib-1.2.589.dist-info}/WHEEL +0 -0
- {pybiolib-1.2.576.dist-info → pybiolib-1.2.589.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
from biolib import utils
|
2
|
+
from biolib._internal.types import Optional
|
3
|
+
from biolib.api.client import ApiClient, ApiClientInitDict
|
4
|
+
from biolib.app import BioLibApp
|
5
|
+
|
6
|
+
|
7
|
+
class Session:
|
8
|
+
def __init__(self, _init_dict: ApiClientInitDict) -> None:
|
9
|
+
self._api = ApiClient(_init_dict=_init_dict)
|
10
|
+
|
11
|
+
@staticmethod
|
12
|
+
def get_session(refresh_token: str, base_url: Optional[str] = None) -> 'Session':
|
13
|
+
return Session(
|
14
|
+
_init_dict=ApiClientInitDict(
|
15
|
+
refresh_token=refresh_token,
|
16
|
+
base_url=base_url or utils.load_base_url_from_env(),
|
17
|
+
)
|
18
|
+
)
|
19
|
+
|
20
|
+
def load(self, uri: str) -> BioLibApp:
|
21
|
+
r"""Load a BioLib application by its URI or website URL.
|
22
|
+
|
23
|
+
Args:
|
24
|
+
uri (str): The URI or website URL of the application to load. Can be either:
|
25
|
+
- App URI (e.g., 'biolib/myapp:1.0.0')
|
26
|
+
- Website URL (e.g., 'https://biolib.com/biolib/myapp/')
|
27
|
+
|
28
|
+
Returns:
|
29
|
+
BioLibApp: The loaded application object
|
30
|
+
|
31
|
+
Example::
|
32
|
+
|
33
|
+
>>> # Load by URI
|
34
|
+
>>> app = biolib.load('biolib/myapp:1.0.0')
|
35
|
+
>>> # Load by website URL
|
36
|
+
>>> app = biolib.load('https://biolib.com/biolib/myapp/')
|
37
|
+
>>> result = app.cli('--help')
|
38
|
+
"""
|
39
|
+
return BioLibApp(uri=uri, _api_client=self._api)
|
biolib/api/client.py
CHANGED
@@ -1,10 +1,17 @@
|
|
1
|
+
import base64
|
2
|
+
import binascii
|
3
|
+
import json
|
4
|
+
from datetime import datetime, timezone
|
5
|
+
from json.decoder import JSONDecodeError
|
1
6
|
from urllib.parse import urlencode, urljoin
|
2
7
|
|
3
8
|
import importlib_metadata
|
4
9
|
|
5
10
|
from biolib._internal.http_client import HttpClient, HttpResponse
|
11
|
+
from biolib._internal.types.typing import Any, Dict, Optional, TypedDict, Union, cast
|
6
12
|
from biolib.biolib_api_client import BiolibApiClient as DeprecatedApiClient
|
7
|
-
from biolib.
|
13
|
+
from biolib.biolib_errors import BioLibError
|
14
|
+
from biolib.biolib_logging import logger
|
8
15
|
|
9
16
|
OptionalHeaders = Union[
|
10
17
|
Optional[Dict[str, str]],
|
@@ -20,9 +27,23 @@ def _get_biolib_package_version() -> str:
|
|
20
27
|
return '0.0.0'
|
21
28
|
|
22
29
|
|
30
|
+
class ApiClientInitDict(TypedDict):
|
31
|
+
refresh_token: str
|
32
|
+
base_url: str
|
33
|
+
|
34
|
+
|
35
|
+
class JwtDecodeError(Exception):
|
36
|
+
pass
|
37
|
+
|
38
|
+
|
23
39
|
class ApiClient(HttpClient):
|
24
40
|
_biolib_package_version: str = _get_biolib_package_version()
|
25
41
|
|
42
|
+
def __init__(self, _init_dict: Optional[ApiClientInitDict] = None) -> None:
|
43
|
+
self._access_token: Optional[str] = None
|
44
|
+
self._refresh_token: Optional[str] = _init_dict['refresh_token'] if _init_dict else None
|
45
|
+
self._base_url: Optional[str] = _init_dict['base_url'] if _init_dict else None
|
46
|
+
|
26
47
|
def get(
|
27
48
|
self,
|
28
49
|
path: str,
|
@@ -83,36 +104,104 @@ class ApiClient(HttpClient):
|
|
83
104
|
url=self._get_absolute_url(path=path, query_params=None),
|
84
105
|
)
|
85
106
|
|
86
|
-
|
87
|
-
def _get_headers(opt_headers: OptionalHeaders, authenticate: bool) -> Dict[str, str]:
|
107
|
+
def _get_headers(self, opt_headers: OptionalHeaders, authenticate: bool) -> Dict[str, str]:
|
88
108
|
# Only keep header keys with a value
|
89
109
|
headers: Dict[str, str] = {key: value for key, value in (opt_headers or {}).items() if value}
|
90
110
|
|
91
111
|
if authenticate:
|
92
|
-
|
93
|
-
|
94
|
-
deprecated_api_client.refresh_access_token()
|
95
|
-
|
96
|
-
if deprecated_api_client.resource_deploy_key:
|
97
|
-
headers['Authorization'] = f'Token {deprecated_api_client.resource_deploy_key}'
|
112
|
+
if self._refresh_token:
|
113
|
+
headers['Authorization'] = f'Bearer {self._get_access_token()}'
|
98
114
|
else:
|
99
|
-
#
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
115
|
+
# TODO: Remove this block when deprecated api client is removed
|
116
|
+
deprecated_api_client = DeprecatedApiClient.get()
|
117
|
+
if deprecated_api_client.is_signed_in:
|
118
|
+
deprecated_api_client.refresh_access_token()
|
119
|
+
|
120
|
+
if deprecated_api_client.resource_deploy_key:
|
121
|
+
headers['Authorization'] = f'Token {deprecated_api_client.resource_deploy_key}'
|
122
|
+
else:
|
123
|
+
# Adding access_token outside is_signed_in check as job_worker.py currently sets access_token
|
124
|
+
# without setting refresh_token
|
125
|
+
access_token = deprecated_api_client.access_token
|
126
|
+
if access_token:
|
127
|
+
headers['Authorization'] = f'Bearer {access_token}'
|
104
128
|
|
105
129
|
headers['client-type'] = 'biolib-python'
|
106
130
|
headers['client-version'] = ApiClient._biolib_package_version
|
107
131
|
|
108
132
|
return headers
|
109
133
|
|
110
|
-
|
111
|
-
def _get_absolute_url(path: str, query_params: Optional[Dict[str, Union[str, int]]]) -> str:
|
134
|
+
def _get_absolute_url(self, path: str, query_params: Optional[Dict[str, Union[str, int]]]) -> str:
|
112
135
|
deprecated_api_client = DeprecatedApiClient.get()
|
113
|
-
|
136
|
+
base_url = self._base_url or deprecated_api_client.base_url
|
137
|
+
base_api_url = urljoin(base_url, '/api/')
|
114
138
|
url = urljoin(base_api_url, path.strip('/') + '/')
|
115
139
|
if query_params:
|
116
140
|
url = url + '?' + urlencode(query_params)
|
117
141
|
|
118
142
|
return url
|
143
|
+
|
144
|
+
def _get_access_token(self) -> str:
|
145
|
+
if self._access_token:
|
146
|
+
decoded_token = self._decode_jwt_without_checking_signature(self._access_token)
|
147
|
+
if datetime.now(tz=timezone.utc).timestamp() < decoded_token['payload']['exp'] - 60: # 60 second buffer
|
148
|
+
# Token has not expired yet
|
149
|
+
return self._access_token
|
150
|
+
|
151
|
+
# TODO: Implement nicer error handling
|
152
|
+
try:
|
153
|
+
response = HttpClient.request(
|
154
|
+
method='POST',
|
155
|
+
url=f'{self._base_url}/api/user/token/refresh/',
|
156
|
+
data={'refresh': self._refresh_token},
|
157
|
+
)
|
158
|
+
except Exception as exception:
|
159
|
+
logger.error('Sign in with refresh token failed')
|
160
|
+
raise exception
|
161
|
+
|
162
|
+
try:
|
163
|
+
response_dict = response.json()
|
164
|
+
except JSONDecodeError as error:
|
165
|
+
logger.error('Could not decode response from server as JSON:')
|
166
|
+
raise BioLibError(response.text) from error
|
167
|
+
|
168
|
+
self._access_token = cast(str, response_dict['access'])
|
169
|
+
return self._access_token
|
170
|
+
|
171
|
+
@staticmethod
|
172
|
+
def _decode_jwt_without_checking_signature(jwt: str) -> Dict[str, Any]:
|
173
|
+
jwt_bytes = jwt.encode('utf-8')
|
174
|
+
|
175
|
+
try:
|
176
|
+
signing_input, _ = jwt_bytes.rsplit(b'.', 1)
|
177
|
+
header_segment, payload_segment = signing_input.split(b'.', 1)
|
178
|
+
except ValueError as error:
|
179
|
+
raise JwtDecodeError('Not enough segments') from error
|
180
|
+
|
181
|
+
try:
|
182
|
+
header_data = base64.urlsafe_b64decode(header_segment)
|
183
|
+
except (TypeError, binascii.Error) as error:
|
184
|
+
raise JwtDecodeError('Invalid header padding') from error
|
185
|
+
|
186
|
+
try:
|
187
|
+
header = json.loads(header_data)
|
188
|
+
except ValueError as error:
|
189
|
+
raise JwtDecodeError(f'Invalid header string: {error}') from error
|
190
|
+
|
191
|
+
if not isinstance(header, dict):
|
192
|
+
raise JwtDecodeError('Invalid header string: must be a json object')
|
193
|
+
|
194
|
+
try:
|
195
|
+
payload_data = base64.urlsafe_b64decode(payload_segment)
|
196
|
+
except (TypeError, binascii.Error) as error:
|
197
|
+
raise JwtDecodeError('Invalid payload padding') from error
|
198
|
+
|
199
|
+
try:
|
200
|
+
payload = json.loads(payload_data)
|
201
|
+
except ValueError as error:
|
202
|
+
raise JwtDecodeError(f'Invalid payload string: {error}') from error
|
203
|
+
|
204
|
+
if not isinstance(header, dict):
|
205
|
+
raise JwtDecodeError('Invalid payload string: must be a json object')
|
206
|
+
|
207
|
+
return dict(header=header, payload=payload)
|
biolib/app/app.py
CHANGED
@@ -6,6 +6,7 @@ import string
|
|
6
6
|
from pathlib import Path
|
7
7
|
|
8
8
|
from biolib import utils
|
9
|
+
from biolib.api.client import ApiClient
|
9
10
|
from biolib.biolib_api_client import JobState
|
10
11
|
from biolib.biolib_api_client.app_types import App, AppVersion
|
11
12
|
from biolib.biolib_api_client.biolib_app_api import BiolibAppApi
|
@@ -16,13 +17,15 @@ from biolib.biolib_logging import logger
|
|
16
17
|
from biolib.compute_node.job_worker.job_worker import JobWorker
|
17
18
|
from biolib.experiments.experiment import Experiment
|
18
19
|
from biolib.jobs import Job
|
19
|
-
from biolib.typing_utils import
|
20
|
+
from biolib.typing_utils import Dict, Optional
|
20
21
|
from biolib.utils.app_uri import parse_app_uri
|
21
22
|
|
22
23
|
|
23
24
|
class BioLibApp:
|
24
|
-
def __init__(self, uri: str):
|
25
|
-
|
25
|
+
def __init__(self, uri: str, _api_client: Optional[ApiClient] = None):
|
26
|
+
self._api_client: Optional[ApiClient] = _api_client
|
27
|
+
|
28
|
+
app_response = BiolibAppApi.get_by_uri(uri=uri, api_client=self._api_client)
|
26
29
|
self._app: App = app_response['app']
|
27
30
|
self._app_uri = app_response['app_uri']
|
28
31
|
self._app_version: AppVersion = app_response['app_version']
|
@@ -98,6 +101,7 @@ class BioLibApp:
|
|
98
101
|
timeout=timeout,
|
99
102
|
requested_machine_count=machine_count,
|
100
103
|
temporary_client_secrets=temporary_client_secrets,
|
104
|
+
api_client=self._api_client,
|
101
105
|
)
|
102
106
|
logger.info(f'View the result in your browser at: {utils.BIOLIB_BASE_URL}/results/{job.id}/')
|
103
107
|
if blocking:
|
@@ -8,6 +8,7 @@ import urllib.parse
|
|
8
8
|
import biolib.api
|
9
9
|
from biolib import biolib_errors
|
10
10
|
from biolib._internal.http_client import HttpError
|
11
|
+
from biolib.api.client import ApiClient
|
11
12
|
from biolib.biolib_api_client import AppGetResponse
|
12
13
|
from biolib.biolib_logging import logger
|
13
14
|
from biolib.typing_utils import Optional
|
@@ -84,10 +85,11 @@ def _get_app_uri_from_str(input_str: str) -> str:
|
|
84
85
|
|
85
86
|
class BiolibAppApi:
|
86
87
|
@staticmethod
|
87
|
-
def get_by_uri(uri: str) -> AppGetResponse:
|
88
|
+
def get_by_uri(uri: str, api_client: Optional[ApiClient] = None) -> AppGetResponse:
|
88
89
|
uri = _get_app_uri_from_str(uri)
|
90
|
+
api = api_client or biolib.api.client
|
89
91
|
try:
|
90
|
-
response =
|
92
|
+
response = api.get(path='/app/', params={'uri': uri})
|
91
93
|
app_response: AppGetResponse = response.json()
|
92
94
|
return app_response
|
93
95
|
|
@@ -5,6 +5,7 @@ import biolib.api
|
|
5
5
|
|
6
6
|
from biolib import utils
|
7
7
|
from biolib._internal.http_client import HttpError
|
8
|
+
from biolib.api.client import ApiClient
|
8
9
|
from biolib.biolib_api_client import CloudJob, JobState
|
9
10
|
from biolib.biolib_errors import JobResultPermissionError, JobResultError, JobResultNotFound, StorageDownloadFailed
|
10
11
|
from biolib.biolib_logging import logger
|
@@ -35,19 +36,19 @@ def _get_user_info() -> Optional[str]:
|
|
35
36
|
|
36
37
|
|
37
38
|
class BiolibJobApi:
|
38
|
-
|
39
39
|
@staticmethod
|
40
40
|
def create(
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
41
|
+
app_version_id,
|
42
|
+
app_resource_name_prefix=None,
|
43
|
+
override_command=False,
|
44
|
+
caller_job=None,
|
45
|
+
machine='',
|
46
|
+
experiment_uuid: Optional[str] = None,
|
47
|
+
timeout: Optional[int] = None,
|
48
|
+
notify: bool = False,
|
49
|
+
requested_machine_count: Optional[int] = None,
|
50
|
+
temporary_client_secrets: Optional[Dict[str, str]] = None,
|
51
|
+
api_client: Optional[ApiClient] = None,
|
51
52
|
):
|
52
53
|
data = {
|
53
54
|
'app_version_id': app_version_id,
|
@@ -58,22 +59,16 @@ class BiolibJobApi:
|
|
58
59
|
}
|
59
60
|
|
60
61
|
if app_resource_name_prefix:
|
61
|
-
data.update({
|
62
|
-
'app_resource_name_prefix': app_resource_name_prefix
|
63
|
-
})
|
62
|
+
data.update({'app_resource_name_prefix': app_resource_name_prefix})
|
64
63
|
|
65
64
|
if override_command:
|
66
|
-
data.update({
|
67
|
-
'arguments_override_command': override_command
|
68
|
-
})
|
65
|
+
data.update({'arguments_override_command': override_command})
|
69
66
|
|
70
67
|
if caller_job:
|
71
68
|
data['caller_job'] = caller_job
|
72
69
|
|
73
70
|
if machine:
|
74
|
-
data.update({
|
75
|
-
'requested_machine': machine
|
76
|
-
})
|
71
|
+
data.update({'requested_machine': machine})
|
77
72
|
|
78
73
|
if requested_machine_count:
|
79
74
|
data.update({'requested_machine_count': requested_machine_count})
|
@@ -87,7 +82,8 @@ class BiolibJobApi:
|
|
87
82
|
if temporary_client_secrets:
|
88
83
|
data['temporary_client_secrets'] = temporary_client_secrets
|
89
84
|
|
90
|
-
|
85
|
+
api = api_client or biolib.api.client
|
86
|
+
response = api.post(path='/jobs/', data=data)
|
91
87
|
|
92
88
|
return response.json()
|
93
89
|
|
@@ -99,20 +95,25 @@ class BiolibJobApi:
|
|
99
95
|
logger.error(f'Failed to update job "{job_uuid}" to state "{state.value}" due to {error}')
|
100
96
|
|
101
97
|
@staticmethod
|
102
|
-
def create_cloud_job(
|
98
|
+
def create_cloud_job(
|
99
|
+
job_id: str,
|
100
|
+
result_name_prefix: Optional[str],
|
101
|
+
api_client: Optional[ApiClient] = None,
|
102
|
+
) -> CloudJob:
|
103
103
|
data = {'job_id': job_id}
|
104
104
|
if result_name_prefix:
|
105
105
|
data['result_name_prefix'] = result_name_prefix
|
106
106
|
|
107
|
-
|
107
|
+
api = api_client or biolib.api.client
|
108
|
+
response = api.post(path='/jobs/cloud/', data=data)
|
108
109
|
cloud_job: CloudJob = response.json()
|
109
110
|
return cloud_job
|
110
111
|
|
111
112
|
@staticmethod
|
112
113
|
def get_job_storage_download_url(
|
113
|
-
|
114
|
-
|
115
|
-
|
114
|
+
job_uuid: str,
|
115
|
+
job_auth_token: str,
|
116
|
+
storage_type: Literal['input', 'results'],
|
116
117
|
) -> str:
|
117
118
|
try:
|
118
119
|
response = biolib.api.client.get(
|
@@ -154,19 +155,21 @@ class BiolibJobApi:
|
|
154
155
|
|
155
156
|
@staticmethod
|
156
157
|
def create_job_with_data(
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
158
|
+
app_version_uuid: str,
|
159
|
+
app_resource_name_prefix: Optional[str],
|
160
|
+
module_input_serialized: bytes,
|
161
|
+
arguments_override_command: bool,
|
162
|
+
experiment_uuid: Optional[str],
|
163
|
+
requested_machine: Optional[str],
|
164
|
+
result_name_prefix: Optional[str],
|
165
|
+
caller_job_uuid: Optional[str] = None,
|
166
|
+
requested_timeout_seconds: Optional[int] = None,
|
167
|
+
notify: bool = False,
|
168
|
+
requested_machine_count: Optional[int] = None,
|
169
|
+
api_client: Optional[ApiClient] = None,
|
168
170
|
) -> Dict:
|
169
|
-
|
171
|
+
api = api_client or biolib.api.client
|
172
|
+
job_dict: Dict = api.post(
|
170
173
|
path='/jobs/create_job_with_data/',
|
171
174
|
data=module_input_serialized,
|
172
175
|
headers={
|
@@ -184,6 +187,6 @@ class BiolibJobApi:
|
|
184
187
|
'result-name-prefix': result_name_prefix,
|
185
188
|
'requested-timeout-seconds': str(requested_timeout_seconds) if requested_timeout_seconds else None,
|
186
189
|
'notify': 'true' if notify else 'false',
|
187
|
-
}
|
190
|
+
},
|
188
191
|
).json()
|
189
192
|
return job_dict
|
biolib/jobs/job.py
CHANGED
@@ -6,9 +6,11 @@ from datetime import datetime, timedelta
|
|
6
6
|
from pathlib import Path
|
7
7
|
from urllib.parse import urlparse
|
8
8
|
|
9
|
-
|
9
|
+
import biolib.api.client
|
10
|
+
from biolib import utils
|
10
11
|
from biolib._internal.http_client import HttpClient
|
11
12
|
from biolib._internal.utils import open_browser_window_from_notebook
|
13
|
+
from biolib.api.client import ApiClient
|
12
14
|
from biolib.biolib_api_client import BiolibApiClient, CreatedJobDict
|
13
15
|
from biolib.biolib_api_client.biolib_app_api import BiolibAppApi
|
14
16
|
from biolib.biolib_api_client.biolib_job_api import BiolibJobApi
|
@@ -39,7 +41,9 @@ class Job:
|
|
39
41
|
}
|
40
42
|
)
|
41
43
|
|
42
|
-
def __init__(self, job_dict: JobDict):
|
44
|
+
def __init__(self, job_dict: JobDict, _api_client: Optional[ApiClient] = None):
|
45
|
+
self._api_client: Optional[ApiClient] = _api_client
|
46
|
+
|
43
47
|
self._uuid: str = job_dict['uuid']
|
44
48
|
self._auth_token: str = job_dict['auth_token']
|
45
49
|
|
@@ -87,6 +91,24 @@ class Job:
|
|
87
91
|
self._refetch_job_dict()
|
88
92
|
return bool(self._job_dict['ended_at'])
|
89
93
|
|
94
|
+
def is_pending(self) -> bool:
|
95
|
+
"""Returns whether the job is in a pending state.
|
96
|
+
|
97
|
+
A job is considered pending if it's not finished yet.
|
98
|
+
The job state is re-fetched when this method is called.
|
99
|
+
|
100
|
+
Returns:
|
101
|
+
bool: True if the job is in a pending state, False otherwise.
|
102
|
+
|
103
|
+
Example::
|
104
|
+
>>> job = biolib.get_job("job_id")
|
105
|
+
>>> if job.is_pending():
|
106
|
+
>>> print("Job is still running")
|
107
|
+
>>> else:
|
108
|
+
>>> print("Job has finished")
|
109
|
+
"""
|
110
|
+
return not self.is_finished()
|
111
|
+
|
90
112
|
def get_name(self) -> str:
|
91
113
|
self._refetch_job_dict()
|
92
114
|
return self._job_dict['main_result']['name']
|
@@ -208,7 +230,7 @@ class Job:
|
|
208
230
|
|
209
231
|
def cancel(self) -> None:
|
210
232
|
try:
|
211
|
-
api.client.patch(
|
233
|
+
biolib.api.client.patch(
|
212
234
|
path=f'/jobs/{self._uuid}/',
|
213
235
|
headers={'Job-Auth-Token': self._auth_token} if self._auth_token else None,
|
214
236
|
data={'state': 'cancelled'},
|
@@ -219,7 +241,7 @@ class Job:
|
|
219
241
|
|
220
242
|
def rename(self, name: str) -> None:
|
221
243
|
try:
|
222
|
-
api.client.patch(
|
244
|
+
biolib.api.client.patch(
|
223
245
|
path=f'/jobs/{self._uuid}/main_result/',
|
224
246
|
headers={'Job-Auth-Token': self._auth_token} if self._auth_token else None,
|
225
247
|
data={'result_name_prefix': name},
|
@@ -325,20 +347,21 @@ class Job:
|
|
325
347
|
params['state'] = status
|
326
348
|
|
327
349
|
api_path = '/jobs/'
|
328
|
-
response = api.client.get(api_path, params=params).json()
|
350
|
+
response = biolib.api.client.get(api_path, params=params).json()
|
329
351
|
jobs = [job_dict for job_dict in response['results']]
|
330
352
|
|
331
353
|
for page_number in range(2, response['page_count'] + 1):
|
332
354
|
if len(jobs) >= count:
|
333
355
|
break
|
334
|
-
page_response = api.client.get(path=api_path, params=dict(**params, page=page_number)).json()
|
356
|
+
page_response = biolib.api.client.get(path=api_path, params=dict(**params, page=page_number)).json()
|
335
357
|
jobs.extend([job_dict for job_dict in page_response['results']])
|
336
358
|
|
337
359
|
return jobs[:count]
|
338
360
|
|
339
361
|
@staticmethod
|
340
|
-
def _get_job_dict(uuid: str, auth_token: Optional[str] = None) -> JobDict:
|
341
|
-
|
362
|
+
def _get_job_dict(uuid: str, auth_token: Optional[str] = None, api_client: Optional[ApiClient] = None) -> JobDict:
|
363
|
+
api = api_client or biolib.api.client
|
364
|
+
job_dict: JobDict = api.get(
|
342
365
|
path=f'/jobs/{uuid}/',
|
343
366
|
headers={'Job-Auth-Token': auth_token} if auth_token else None,
|
344
367
|
).json()
|
@@ -506,6 +529,7 @@ class Job:
|
|
506
529
|
notify: bool = False,
|
507
530
|
requested_machine_count: Optional[int] = None,
|
508
531
|
temporary_client_secrets: Optional[Dict[str, str]] = None,
|
532
|
+
api_client: Optional[ApiClient] = None,
|
509
533
|
) -> 'Job':
|
510
534
|
if len(module_input_serialized) < 500_000 and temporary_client_secrets is None:
|
511
535
|
_job_dict = BiolibJobApi.create_job_with_data(
|
@@ -519,6 +543,7 @@ class Job:
|
|
519
543
|
requested_timeout_seconds=timeout,
|
520
544
|
result_name_prefix=result_prefix,
|
521
545
|
requested_machine_count=requested_machine_count,
|
546
|
+
api_client=api_client,
|
522
547
|
)
|
523
548
|
return Job(cast(JobDict, _job_dict))
|
524
549
|
|
@@ -532,8 +557,9 @@ class Job:
|
|
532
557
|
timeout=timeout,
|
533
558
|
requested_machine_count=requested_machine_count,
|
534
559
|
temporary_client_secrets=temporary_client_secrets,
|
560
|
+
api_client=api_client,
|
535
561
|
)
|
536
562
|
JobStorage.upload_module_input(job=job_dict, module_input_serialized=module_input_serialized)
|
537
563
|
cloud_job = BiolibJobApi.create_cloud_job(job_id=job_dict['public_id'], result_name_prefix=result_prefix)
|
538
564
|
logger.debug(f"Cloud: Job created with id {cloud_job['public_id']}")
|
539
|
-
return Job(cast(JobDict, job_dict))
|
565
|
+
return Job(cast(JobDict, job_dict), _api_client=api_client)
|
biolib/sdk/__init__.py
CHANGED
@@ -5,12 +5,17 @@ from biolib._data_record.data_record import DataRecord as _DataRecord
|
|
5
5
|
from biolib._internal.push_application import push_application as _push_application
|
6
6
|
from biolib._internal.push_application import set_app_version_as_active as _set_app_version_as_active
|
7
7
|
from biolib._runtime.runtime import Runtime as _Runtime
|
8
|
+
from biolib._session.session import Session as _Session
|
8
9
|
from biolib.app import BioLibApp as _BioLibApp
|
9
10
|
|
10
11
|
# Classes to expose as public API
|
11
12
|
Runtime = _Runtime
|
12
13
|
|
13
14
|
|
15
|
+
def get_session(refresh_token: str, base_url: Optional[str] = None) -> _Session:
|
16
|
+
return _Session.get_session(refresh_token=refresh_token, base_url=base_url)
|
17
|
+
|
18
|
+
|
14
19
|
def push_app_version(uri: str, path: str) -> _BioLibApp:
|
15
20
|
push_data = _push_application(
|
16
21
|
app_uri=uri,
|
@@ -26,17 +26,18 @@ biolib/_internal/types/typing.py,sha256=qrsk8hHcGEbDpU1QQFzHAKnhQxkMe7uJ6pxHeAnf
|
|
26
26
|
biolib/_internal/utils/__init__.py,sha256=p5vsIFyu-zYqBgdSMfwW9NC_jk7rXvvCbV4Bzd3As7c,630
|
27
27
|
biolib/_internal/utils/multinode.py,sha256=-J3PEAK3NaOwCn--5T7vWHkA3yu5w9QhmuhkQcH-2wY,8229
|
28
28
|
biolib/_runtime/runtime.py,sha256=bZQ0m39R9jOBVAtlyvzDnOobKueOAQUCwMUZjDQnO7E,4439
|
29
|
+
biolib/_session/session.py,sha256=K-mbWKP6zMEdKha4Key6XEqRvduS_Ol4LgAVjf37tO4,1341
|
29
30
|
biolib/api/__init__.py,sha256=mQ4u8FijqyLzjYMezMUUbbBGNB3iFmkNdjXnWPZ7Jlw,138
|
30
|
-
biolib/api/client.py,sha256=
|
31
|
+
biolib/api/client.py,sha256=pILuZhmWCXGuzrp9rPwtwRizvIGGbIlT2o4wV-vwL24,7668
|
31
32
|
biolib/app/__init__.py,sha256=cdPtcfb_U-bxb9iSL4fCEq2rpD9OjkyY4W-Zw60B0LI,37
|
32
|
-
biolib/app/app.py,sha256=
|
33
|
+
biolib/app/app.py,sha256=HxW3T1iuDh-DMhVDB0NbgQjRXqgE7dPw8CAdhrd5lbw,9940
|
33
34
|
biolib/app/search_apps.py,sha256=K4a41f5XIWth2BWI7OffASgIsD0ko8elCax8YL2igaY,1470
|
34
35
|
biolib/biolib_api_client/__init__.py,sha256=E5EMa19wJoblwSdQPYrxc_BtIeRsAuO0L_jQweWw-Yk,182
|
35
36
|
biolib/biolib_api_client/api_client.py,sha256=ohvbWbpresxLHFGPkvXACfmiTYsBk8RBx5XsBbLYg_M,7546
|
36
37
|
biolib/biolib_api_client/app_types.py,sha256=1sXz9XnLRKNALMglNdTbew7AL6OkcUan0MPdj4xQLis,2456
|
37
38
|
biolib/biolib_api_client/auth.py,sha256=kjm0ZHnH3I8so3su2sZbBxNHYp-ZUdrZ5lwQ0K36RSw,949
|
38
|
-
biolib/biolib_api_client/biolib_app_api.py,sha256=
|
39
|
-
biolib/biolib_api_client/biolib_job_api.py,sha256=
|
39
|
+
biolib/biolib_api_client/biolib_app_api.py,sha256=DdE_kRfDgVa876Cdl_D1P0lBoaghFomEyy-ZP8K7SoY,5177
|
40
|
+
biolib/biolib_api_client/biolib_job_api.py,sha256=3Hzv5Os4d377pKrCzg3i7c5xiy9FiqeVssub690GLdA,7423
|
40
41
|
biolib/biolib_api_client/common_types.py,sha256=RH-1KNHqUF-EkTpfPOSTt5Mq1GPdfju_cqXDesscO1I,123
|
41
42
|
biolib/biolib_api_client/job_types.py,sha256=yBdBwjharbQJuXCi2xKMi0t_r6XxnbWnkchHekTpCJY,1351
|
42
43
|
biolib/biolib_api_client/lfs_types.py,sha256=joZWP6-sa5_Ug_6xIp5fHAgEo_bqLE3rbleQocZtDcg,339
|
@@ -101,12 +102,12 @@ biolib/compute_node/webserver/worker_thread.py,sha256=7uD9yQPhePYvP2HCJ27EeZ_h6p
|
|
101
102
|
biolib/experiments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
102
103
|
biolib/experiments/experiment.py,sha256=pBtnOHz0kKoFxlIGf08o8ZCEOze-CljwfOsTdhvCTCk,8646
|
103
104
|
biolib/jobs/__init__.py,sha256=aIb2H2DHjQbM2Bs-dysFijhwFcL58Blp0Co0gimED3w,32
|
104
|
-
biolib/jobs/job.py,sha256=
|
105
|
+
biolib/jobs/job.py,sha256=rcQPLrUsVHdzZ0g_T9f3m_mmVF0m-aYi_fKYTbQATaA,24174
|
105
106
|
biolib/jobs/job_result.py,sha256=rALHiKYNaC9lHi_JJqBob1RubzNLwG9Z386kwRJjd2M,5885
|
106
107
|
biolib/jobs/types.py,sha256=ezvaoTANsWazK6PmfpYcqezdfjP7MNBEBfqIZGoZhz8,997
|
107
108
|
biolib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
108
109
|
biolib/runtime/__init__.py,sha256=MlRepA11n2H-3plB5rzWyyHK2JmP6PiaP3i6x3vt0mg,506
|
109
|
-
biolib/sdk/__init__.py,sha256=
|
110
|
+
biolib/sdk/__init__.py,sha256=fvSPXe4JC4uq75-y7LGrn3C7VFrQ-1I6Yp6SF5oG2DY,2179
|
110
111
|
biolib/tables.py,sha256=MmruV-nJLc3HbLVJBAiDuDCgS2-4oaUkpoCLLUNYbxQ,1173
|
111
112
|
biolib/templates/__init__.py,sha256=Yx62sSyDCDesRQDQgmbDsLpfgEh93fWE8r9u4g2azXk,36
|
112
113
|
biolib/templates/example_app.py,sha256=EB3E3RT4SeO_ii5nVQqJpi5KDGNE_huF1ub-e5ZFveE,715
|
@@ -119,8 +120,8 @@ biolib/utils/cache_state.py,sha256=u256F37QSRIVwqKlbnCyzAX4EMI-kl6Dwu6qwj-Qmag,3
|
|
119
120
|
biolib/utils/multipart_uploader.py,sha256=XvGP1I8tQuKhAH-QugPRoEsCi9qvbRk-DVBs5PNwwJo,8452
|
120
121
|
biolib/utils/seq_util.py,sha256=Ozk0blGtPur_D9MwShD02r_mphyQmgZkx-lOHOwnlIM,6730
|
121
122
|
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.
|
123
|
+
pybiolib-1.2.589.dist-info/LICENSE,sha256=F2h7gf8i0agDIeWoBPXDMYScvQOz02pAWkKhTGOHaaw,1067
|
124
|
+
pybiolib-1.2.589.dist-info/METADATA,sha256=52kbUnHqEDKEEtKaD8fXAEvurFjhQ5rBn5fQxvF2XiY,1570
|
125
|
+
pybiolib-1.2.589.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
126
|
+
pybiolib-1.2.589.dist-info/entry_points.txt,sha256=p6DyaP_2kctxegTX23WBznnrDi4mz6gx04O5uKtRDXg,42
|
127
|
+
pybiolib-1.2.589.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|