pybiolib 1.2.567__py3-none-any.whl → 1.2.582__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 +8 -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 +17 -9
- biolib/sdk/__init__.py +5 -0
- {pybiolib-1.2.567.dist-info → pybiolib-1.2.582.dist-info}/METADATA +1 -1
- {pybiolib-1.2.567.dist-info → pybiolib-1.2.582.dist-info}/RECORD +12 -11
- {pybiolib-1.2.567.dist-info → pybiolib-1.2.582.dist-info}/LICENSE +0 -0
- {pybiolib-1.2.567.dist-info → pybiolib-1.2.582.dist-info}/WHEEL +0 -0
- {pybiolib-1.2.567.dist-info → pybiolib-1.2.582.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,7 +101,9 @@ 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
|
)
|
106
|
+
logger.info(f'View the result in your browser at: {utils.BIOLIB_BASE_URL}/results/{job.id}/')
|
102
107
|
if blocking:
|
103
108
|
# TODO: Deprecate utils.STREAM_STDOUT and always stream logs by simply calling job.stream_logs()
|
104
109
|
if utils.IS_RUNNING_IN_NOTEBOOK:
|
@@ -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
|
|
@@ -208,7 +212,7 @@ class Job:
|
|
208
212
|
|
209
213
|
def cancel(self) -> None:
|
210
214
|
try:
|
211
|
-
api.client.patch(
|
215
|
+
biolib.api.client.patch(
|
212
216
|
path=f'/jobs/{self._uuid}/',
|
213
217
|
headers={'Job-Auth-Token': self._auth_token} if self._auth_token else None,
|
214
218
|
data={'state': 'cancelled'},
|
@@ -219,7 +223,7 @@ class Job:
|
|
219
223
|
|
220
224
|
def rename(self, name: str) -> None:
|
221
225
|
try:
|
222
|
-
api.client.patch(
|
226
|
+
biolib.api.client.patch(
|
223
227
|
path=f'/jobs/{self._uuid}/main_result/',
|
224
228
|
headers={'Job-Auth-Token': self._auth_token} if self._auth_token else None,
|
225
229
|
data={'result_name_prefix': name},
|
@@ -325,20 +329,21 @@ class Job:
|
|
325
329
|
params['state'] = status
|
326
330
|
|
327
331
|
api_path = '/jobs/'
|
328
|
-
response = api.client.get(api_path, params=params).json()
|
332
|
+
response = biolib.api.client.get(api_path, params=params).json()
|
329
333
|
jobs = [job_dict for job_dict in response['results']]
|
330
334
|
|
331
335
|
for page_number in range(2, response['page_count'] + 1):
|
332
336
|
if len(jobs) >= count:
|
333
337
|
break
|
334
|
-
page_response = api.client.get(path=api_path, params=dict(**params, page=page_number)).json()
|
338
|
+
page_response = biolib.api.client.get(path=api_path, params=dict(**params, page=page_number)).json()
|
335
339
|
jobs.extend([job_dict for job_dict in page_response['results']])
|
336
340
|
|
337
341
|
return jobs[:count]
|
338
342
|
|
339
343
|
@staticmethod
|
340
|
-
def _get_job_dict(uuid: str, auth_token: Optional[str] = None) -> JobDict:
|
341
|
-
|
344
|
+
def _get_job_dict(uuid: str, auth_token: Optional[str] = None, api_client: Optional[ApiClient] = None) -> JobDict:
|
345
|
+
api = api_client or biolib.api.client
|
346
|
+
job_dict: JobDict = api.get(
|
342
347
|
path=f'/jobs/{uuid}/',
|
343
348
|
headers={'Job-Auth-Token': auth_token} if auth_token else None,
|
344
349
|
).json()
|
@@ -506,6 +511,7 @@ class Job:
|
|
506
511
|
notify: bool = False,
|
507
512
|
requested_machine_count: Optional[int] = None,
|
508
513
|
temporary_client_secrets: Optional[Dict[str, str]] = None,
|
514
|
+
api_client: Optional[ApiClient] = None,
|
509
515
|
) -> 'Job':
|
510
516
|
if len(module_input_serialized) < 500_000 and temporary_client_secrets is None:
|
511
517
|
_job_dict = BiolibJobApi.create_job_with_data(
|
@@ -519,6 +525,7 @@ class Job:
|
|
519
525
|
requested_timeout_seconds=timeout,
|
520
526
|
result_name_prefix=result_prefix,
|
521
527
|
requested_machine_count=requested_machine_count,
|
528
|
+
api_client=api_client,
|
522
529
|
)
|
523
530
|
return Job(cast(JobDict, _job_dict))
|
524
531
|
|
@@ -532,8 +539,9 @@ class Job:
|
|
532
539
|
timeout=timeout,
|
533
540
|
requested_machine_count=requested_machine_count,
|
534
541
|
temporary_client_secrets=temporary_client_secrets,
|
542
|
+
api_client=api_client,
|
535
543
|
)
|
536
544
|
JobStorage.upload_module_input(job=job_dict, module_input_serialized=module_input_serialized)
|
537
545
|
cloud_job = BiolibJobApi.create_cloud_job(job_id=job_dict['public_id'], result_name_prefix=result_prefix)
|
538
546
|
logger.debug(f"Cloud: Job created with id {cloud_job['public_id']}")
|
539
|
-
return Job(cast(JobDict, job_dict))
|
547
|
+
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=v6q7QbQWKeNCl5Sog912aduboq7PU1l4vhOVhlZewEI,23591
|
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.582.dist-info/LICENSE,sha256=F2h7gf8i0agDIeWoBPXDMYScvQOz02pAWkKhTGOHaaw,1067
|
124
|
+
pybiolib-1.2.582.dist-info/METADATA,sha256=EXVefv4YrS8ZoOBerWf0yDWbEHE_LIGzj5QLbzeZ2SY,1570
|
125
|
+
pybiolib-1.2.582.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88
|
126
|
+
pybiolib-1.2.582.dist-info/entry_points.txt,sha256=p6DyaP_2kctxegTX23WBznnrDi4mz6gx04O5uKtRDXg,42
|
127
|
+
pybiolib-1.2.582.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|