qarnot 2.16.0__py3-none-any.whl → 2.18.0__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.
- qarnot/__init__.py +11 -1
- qarnot/_version.py +3 -3
- qarnot/advanced_bucket.py +1 -1
- qarnot/bucket.py +13 -13
- qarnot/carbon_facts.py +208 -0
- qarnot/computing_quotas.py +328 -0
- qarnot/connection.py +47 -30
- qarnot/error.py +3 -3
- qarnot/forced_network_rule.py +11 -11
- qarnot/hardware_constraint.py +9 -9
- qarnot/helper.py +4 -3
- qarnot/job.py +18 -18
- qarnot/pool.py +76 -34
- qarnot/privileges.py +1 -1
- qarnot/retry_settings.py +2 -2
- qarnot/scheduling_type.py +3 -3
- qarnot/secrets.py +4 -4
- qarnot/status.py +66 -66
- qarnot/task.py +91 -49
- {qarnot-2.16.0.dist-info → qarnot-2.18.0.dist-info}/METADATA +3 -2
- qarnot-2.18.0.dist-info/RECORD +31 -0
- {qarnot-2.16.0.dist-info → qarnot-2.18.0.dist-info}/WHEEL +1 -1
- qarnot-2.16.0.dist-info/RECORD +0 -29
- {qarnot-2.16.0.dist-info → qarnot-2.18.0.dist-info/licenses}/LICENSE +0 -0
- {qarnot-2.16.0.dist-info → qarnot-2.18.0.dist-info}/top_level.txt +0 -0
qarnot/__init__.py
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
# limitations under the License.
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
from typing import Dict
|
|
19
20
|
from .exceptions import QarnotGenericException, SecretConflictException, SecretNotFoundException, UnauthorizedException
|
|
20
21
|
from ._util import get_error_message_from_http_response
|
|
21
22
|
|
|
@@ -65,7 +66,8 @@ def get_url(key, **kwargs):
|
|
|
65
66
|
'task stderr': '/tasks/{uuid}/stderr', # GET -> task stderr
|
|
66
67
|
'task instance stdout': '/tasks/{uuid}/stdout/{instanceId}', # GET -> task instance stdout
|
|
67
68
|
'task instance stderr': '/tasks/{uuid}/stderr/{instanceId}', # GET -> task instance stderr
|
|
68
|
-
'task abort': '/tasks/{uuid}/abort', #
|
|
69
|
+
'task abort': '/tasks/{uuid}/abort', # POST -> abort task
|
|
70
|
+
'task carbon facts': '/carbon/v1/tasks/{uuid}/carbon-facts', # GET -> task carbon facts
|
|
69
71
|
'pools': '/pools', # POST -> submit pool
|
|
70
72
|
'paginate pools': '/pools/paginate', # GET -> paginate pools
|
|
71
73
|
'paginate pools summaries': '/pools/summaries/paginate', # GET -> paginate pools summaries
|
|
@@ -76,6 +78,7 @@ def get_url(key, **kwargs):
|
|
|
76
78
|
'pool stderr': '/pools/{uuid}/stderr', # GET -> pool stderr
|
|
77
79
|
'pool instance stdout': '/pools/{uuid}/stdout/{instanceId}', # GET -> pool instance stdout
|
|
78
80
|
'pool instance stderr': '/pools/{uuid}/stderr/{instanceId}', # GET -> pool instance stderr
|
|
81
|
+
'pool carbon facts': '/carbon/v1/pools/{uuid}/carbon-facts', # GET -> pool carbon facts
|
|
79
82
|
'secrets data': '/secrets-manager/data/{secret_key}', # GET -> get secret , PUT -> create secret, PATCH -> update secret, DELETE -> delete secret
|
|
80
83
|
'secrets search': '/secrets-manager/search/{secret_prefix}', # GET -> lists secrets starting with prefix
|
|
81
84
|
'user': '/info', # GET -> user info
|
|
@@ -88,6 +91,13 @@ def get_url(key, **kwargs):
|
|
|
88
91
|
return urls[key].format(**kwargs)
|
|
89
92
|
|
|
90
93
|
|
|
94
|
+
def get_url_with_param(key, params: Dict[str, str], **kwargs):
|
|
95
|
+
if (params is None or len(params) == 0):
|
|
96
|
+
return get_url(key, **kwargs)
|
|
97
|
+
param_string = "&".join(f'{key}={value}' for key, value in params.items())
|
|
98
|
+
return "{url}?{param}".format(url=get_url(key, **kwargs), param=param_string)
|
|
99
|
+
|
|
100
|
+
|
|
91
101
|
from ._version import get_versions # noqa
|
|
92
102
|
__version__ = get_versions()['version'] # type: ignore
|
|
93
103
|
del get_versions
|
qarnot/_version.py
CHANGED
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2025-
|
|
11
|
+
"date": "2025-05-22T14:41:22+0200",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "v2.
|
|
14
|
+
"full-revisionid": "9361585630d3dbcc8fa50ecbb9d20d592234a808",
|
|
15
|
+
"version": "v2.18.0"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
qarnot/advanced_bucket.py
CHANGED
|
@@ -180,7 +180,7 @@ class PrefixResourcesTransformation(AbstractResourcesTransformation):
|
|
|
180
180
|
:return: The PrefixResourcesTransformation new object
|
|
181
181
|
:rtype: :class:`PrefixResourcesTransformation`
|
|
182
182
|
"""
|
|
183
|
-
return PrefixResourcesTransformation(json
|
|
183
|
+
return PrefixResourcesTransformation(json.get("prefix"))
|
|
184
184
|
|
|
185
185
|
def to_json(self) -> object:
|
|
186
186
|
"""Get a dict ready to be json packed.
|
qarnot/bucket.py
CHANGED
|
@@ -107,14 +107,14 @@ class Bucket(Storage): # pylint: disable=W0223
|
|
|
107
107
|
:returns: The created :class:`~qarnot.bucket.Bucket`.
|
|
108
108
|
"""
|
|
109
109
|
filtering = None
|
|
110
|
-
if "filtering" in json_bucket and json_bucket
|
|
111
|
-
filtering = Filtering.from_json(json_bucket
|
|
110
|
+
if "filtering" in json_bucket and json_bucket.get('filtering'):
|
|
111
|
+
filtering = Filtering.from_json(json_bucket.get('filtering'))
|
|
112
112
|
|
|
113
113
|
resource_transformation = None
|
|
114
|
-
if "resourcesTransformation" in json_bucket and json_bucket
|
|
115
|
-
resource_transformation = ResourcesTransformation.from_json(json_bucket
|
|
114
|
+
if "resourcesTransformation" in json_bucket and json_bucket.get('resourcesTransformation'):
|
|
115
|
+
resource_transformation = ResourcesTransformation.from_json(json_bucket.get('resourcesTransformation'))
|
|
116
116
|
|
|
117
|
-
bucket = Bucket(connection, json_bucket
|
|
117
|
+
bucket = Bucket(connection, json_bucket.get('bucketName'), create=False, filtering=filtering, resources_transformation=resource_transformation, cacheTTLSec=json_bucket.get('cacheTTLSec'))
|
|
118
118
|
return bucket
|
|
119
119
|
|
|
120
120
|
def with_filtering(self, filtering):
|
|
@@ -218,7 +218,7 @@ class Bucket(Storage): # pylint: disable=W0223
|
|
|
218
218
|
)
|
|
219
219
|
self._connection.s3client.delete_bucket(Bucket=self._uuid)
|
|
220
220
|
except self._connection.s3resource.meta.client.exceptions.NoSuchBucket as err:
|
|
221
|
-
raise MissingBucketException("Cannot delete {}. Bucket not found.".format(err.response
|
|
221
|
+
raise MissingBucketException("Cannot delete {}. Bucket not found.".format(err.response.get('Error').get('BucketName'))) from err
|
|
222
222
|
|
|
223
223
|
def list_files(self):
|
|
224
224
|
"""List files in the bucket
|
|
@@ -231,7 +231,7 @@ class Bucket(Storage): # pylint: disable=W0223
|
|
|
231
231
|
bucket = self._connection.s3resource.Bucket(self._uuid)
|
|
232
232
|
return [b for b in bucket.objects.all() if b.key is not None]
|
|
233
233
|
except self._connection.s3resource.meta.client.exceptions.NoSuchBucket as err:
|
|
234
|
-
raise MissingBucketException("Cannot list files. Bucket {} not found.".format(err.response
|
|
234
|
+
raise MissingBucketException("Cannot list files. Bucket {} not found.".format(err.response.get('Error').get('BucketName'))) from err
|
|
235
235
|
|
|
236
236
|
def directory(self, directory=''):
|
|
237
237
|
"""List files in a directory of the bucket according to prefix.
|
|
@@ -281,7 +281,7 @@ class Bucket(Storage): # pylint: disable=W0223
|
|
|
281
281
|
list_files_only = [x for x in entries if not x.key.endswith('/')]
|
|
282
282
|
list_directories_only = [x for x in entries if x.key.endswith('/')]
|
|
283
283
|
except self._connection.s3resource.meta.client.exceptions.NoSuchBucket as err:
|
|
284
|
-
raise MissingBucketException("Cannot synchronize. Bucket {} not found.".format(err.response
|
|
284
|
+
raise MissingBucketException("Cannot synchronize. Bucket {} not found.".format(err.response.get('Error').get('BucketName'))) from err
|
|
285
285
|
|
|
286
286
|
for directory in list_directories_only:
|
|
287
287
|
if not os.path.isdir(os.path.join(local_directoy, get_key_for_local(directory.key))):
|
|
@@ -459,7 +459,7 @@ class Bucket(Storage): # pylint: disable=W0223
|
|
|
459
459
|
self._connection.logger.info("Copy %s to %s" % (entry[0].name, link.name))
|
|
460
460
|
self.copy_file(entry[0].name, link.name)
|
|
461
461
|
except self._connection.s3resource.meta.client.exceptions.NoSuchBucket as err:
|
|
462
|
-
raise MissingBucketException("Cannot sync files. Bucket {} not found.".format(err.response
|
|
462
|
+
raise MissingBucketException("Cannot sync files. Bucket {} not found.".format(err.response.get('Error').get('BucketName'))) from err
|
|
463
463
|
|
|
464
464
|
def add_string(self, string, remote):
|
|
465
465
|
"""Add a string on the storage.
|
|
@@ -484,7 +484,7 @@ class Bucket(Storage): # pylint: disable=W0223
|
|
|
484
484
|
try:
|
|
485
485
|
self._connection.s3client.upload_fileobj(file_, self._uuid, dest, Config=s3_multipart_config)
|
|
486
486
|
except self._connection.s3resource.meta.client.exceptions.NoSuchBucket as err:
|
|
487
|
-
raise MissingBucketException("Cannot add string. Bucket {} not found.".format(err.response
|
|
487
|
+
raise MissingBucketException("Cannot add string. Bucket {} not found.".format(err.response.get('Error').get('BucketName'))) from err
|
|
488
488
|
finally:
|
|
489
489
|
if tobeclosed:
|
|
490
490
|
file_.close()
|
|
@@ -523,7 +523,7 @@ class Bucket(Storage): # pylint: disable=W0223
|
|
|
523
523
|
}
|
|
524
524
|
return self._connection.s3client.copy_object(CopySource=copy_source, Bucket=self._uuid, Key=dest)
|
|
525
525
|
except self._connection.s3resource.meta.client.exceptions.NoSuchBucket as err:
|
|
526
|
-
raise MissingBucketException("Cannot copy file {} to {} from bucket {}. Bucket not found.".format(source, dest, err.response
|
|
526
|
+
raise MissingBucketException("Cannot copy file {} to {} from bucket {}. Bucket not found.".format(source, dest, err.response.get('Error').get('BucketName'))) from err
|
|
527
527
|
|
|
528
528
|
@deprecation.deprecated(deprecated_in="2.6.0", removed_in="3.0",
|
|
529
529
|
current_version=__version__, # type: ignore
|
|
@@ -547,7 +547,7 @@ class Bucket(Storage): # pylint: disable=W0223
|
|
|
547
547
|
try:
|
|
548
548
|
self._connection.s3client.download_fileobj(self._uuid, remote, data)
|
|
549
549
|
except self._connection.s3resource.meta.client.exceptions.NoSuchBucket as err:
|
|
550
|
-
raise MissingBucketException("Cannot download file {} from bucket {}. Bucket not found.".format(remote, err.response
|
|
550
|
+
raise MissingBucketException("Cannot download file {} from bucket {}. Bucket not found.".format(remote, err.response.get('Error').get('BucketName'))) from err
|
|
551
551
|
return local
|
|
552
552
|
|
|
553
553
|
@_util.copy_docs(Storage.delete_file)
|
|
@@ -557,7 +557,7 @@ class Bucket(Storage): # pylint: disable=W0223
|
|
|
557
557
|
remote = _util.get_sanitized_bucket_path(remote, self._connection._show_bucket_warnings)
|
|
558
558
|
self._connection.s3client.delete_object(Bucket=self._uuid, Key=remote)
|
|
559
559
|
except self._connection.s3resource.meta.client.exceptions.NoSuchBucket as err:
|
|
560
|
-
raise MissingBucketException("Cannot delete file {} from bucket {}. Bucket not found.".format(remote, err.response
|
|
560
|
+
raise MissingBucketException("Cannot delete file {} from bucket {}. Bucket not found.".format(remote, err.response.get('Error').get('BucketName'))) from err
|
|
561
561
|
|
|
562
562
|
@property
|
|
563
563
|
def uuid(self):
|
qarnot/carbon_facts.py
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""Carbon facts prototype"""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
from requests import Response
|
|
5
|
+
from .exceptions import MissingPoolException, MissingTaskException
|
|
6
|
+
from . import get_url, get_url_with_param, raise_on_error, _util
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CarbonFacts(object):
|
|
10
|
+
"""
|
|
11
|
+
Carbon facts details of a computed element
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
energy_consumption: float = 0,
|
|
17
|
+
energy_it: float = 0,
|
|
18
|
+
energy_reuse: float = 0,
|
|
19
|
+
carbon_footprint: float = 0,
|
|
20
|
+
equivalent_dc_name: str = "",
|
|
21
|
+
equivalent_dc_carbon_footprint: float = 0,
|
|
22
|
+
saved_carbon_footprint_compute: float = 0,
|
|
23
|
+
saved_carbon_footprint_heat: float = 0,
|
|
24
|
+
saved_carbon_footprint_compute_heat: float = 0,
|
|
25
|
+
saved_carbon_footprint_percent: float = 0,
|
|
26
|
+
PUE: float = 0,
|
|
27
|
+
ERE: float = 0,
|
|
28
|
+
ERF: float = 0,
|
|
29
|
+
WUE: float = 0):
|
|
30
|
+
"""The CarbonFacts constructor
|
|
31
|
+
|
|
32
|
+
:param energy_consumption: the total energy consumed, in W.h
|
|
33
|
+
:type energy_consumption: `float`
|
|
34
|
+
:param energy_it: the energy consumed by IT, in W.h
|
|
35
|
+
:type energy_it: `float`
|
|
36
|
+
:param energy_reuse: the reuse heat, in W.h
|
|
37
|
+
:type energy_reuse: `float`
|
|
38
|
+
:param carbon_footprint: the actual carbon footprint of the computation, in gCO2eq
|
|
39
|
+
:type carbon_footprint: `float`
|
|
40
|
+
:param equivalent_dc_name: the name of the equivalent datacenter used for comparison
|
|
41
|
+
:type equivalent_dc_name: `str`
|
|
42
|
+
:param equivalent_dc_carbon_footprint: the carbon footprint the computation would generate in an equivalent DC, in gCO2eq
|
|
43
|
+
:type equivalent_dc_carbon_footprint: `float`
|
|
44
|
+
:param saved_carbon_footprint_compute: the carbon footprint saved by the computation part by using Qarnot instead of the equivalent DC, in gCO2eq
|
|
45
|
+
:type saved_carbon_footprint_compute: `float`
|
|
46
|
+
:param saved_carbon_footprint_heat: the carbon footprint saved by the heating part by using Qarnot instead of the equivalent DC, in gCO2eq
|
|
47
|
+
:type saved_carbon_footprint_heat: `float`
|
|
48
|
+
:param saved_carbon_footprint_compute_heat: the total carbon footprint saved by using Qarnot instead of the equivalent DC, gCO2eq
|
|
49
|
+
:type saved_carbon_footprint_compute_heat: `float`
|
|
50
|
+
:param saved_carbon_footprint_percent: the percentage of carbon footprint saved by using Qarnot instead of the equivalent DC, in %
|
|
51
|
+
:type saved_carbon_footprint_percent: `float`
|
|
52
|
+
:param PUE: the energy efficiency of the computation site
|
|
53
|
+
:type PUE: `float`
|
|
54
|
+
:param ERE: the energy reuse ratio of the computation site
|
|
55
|
+
:type ERE: `float`
|
|
56
|
+
:param ERF: the heat reuse ratio of the computation site
|
|
57
|
+
:type ERF: `float`
|
|
58
|
+
:param WUE: the water consumption of the computation site, in L/kWh
|
|
59
|
+
:type WUE: `float`
|
|
60
|
+
"""
|
|
61
|
+
self.energy_consumption_Wh: float = energy_consumption
|
|
62
|
+
self.energy_it_Wh: float = energy_it
|
|
63
|
+
self.energy_reuse_Wh: float = energy_reuse
|
|
64
|
+
self.carbon_footprint_gC02eq: float = carbon_footprint
|
|
65
|
+
self.equivalent_datacenter_name: str = equivalent_dc_name
|
|
66
|
+
self.equivalent_dc_carbon_footprint_gC02eq: float = equivalent_dc_carbon_footprint
|
|
67
|
+
self.saved_carbon_footprint_compute_gC02eq: float = saved_carbon_footprint_compute
|
|
68
|
+
self.saved_carbon_footprint_heat_gC02eq: float = saved_carbon_footprint_heat
|
|
69
|
+
self.saved_carbon_footprint_compute_heat_gC02eq: float = saved_carbon_footprint_compute_heat
|
|
70
|
+
self.saved_carbon_footprint_percent: float = saved_carbon_footprint_percent
|
|
71
|
+
self.PUE: float = PUE
|
|
72
|
+
self.ERE: float = ERE
|
|
73
|
+
self.ERF: float = ERF
|
|
74
|
+
self.WUE: float = WUE
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def from_json(cls, json: Dict[str, Any]):
|
|
78
|
+
"""Create a CarbonFacts from a json representation
|
|
79
|
+
|
|
80
|
+
:param json: the json to use to create the SecretsAccessRights object.
|
|
81
|
+
:type json: `Dict[str, float]`
|
|
82
|
+
:returns: The created :class:`~qarnot.carbon_facts.CarbonFacts`.
|
|
83
|
+
"""
|
|
84
|
+
if json is None:
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
energy_consumption = json.get("total_consumed_energy_Wh")
|
|
88
|
+
energy_it = json.get("total_energy_it_Wh")
|
|
89
|
+
energy_reuse = json.get("total_reused_energy_Wh")
|
|
90
|
+
carbon_footprint = json.get("qarnot_carbon_footprint")
|
|
91
|
+
equivalent_datacenter_name = json.get("equivalent_datacenter_name")
|
|
92
|
+
equivalent_dc_carbon_footprint = json.get("equivalent_DC_carbon_footprint")
|
|
93
|
+
saved_carbon_footprint_compute = json.get("saved_carbon_footprint_compute")
|
|
94
|
+
saved_carbon_footprint_heat = json.get("saved_carbon_footprint_heat")
|
|
95
|
+
saved_carbon_footprint_compute_heat = json.get("saved_carbon_footprint_compute_heat")
|
|
96
|
+
saved_carbon_footprint_percent = json.get("saved_carbon_footprint_percent")
|
|
97
|
+
PUE = json.get("PUE")
|
|
98
|
+
ERE = json.get("ERE")
|
|
99
|
+
ERF = json.get("ERF")
|
|
100
|
+
WUE = json.get("WUE")
|
|
101
|
+
|
|
102
|
+
return CarbonFacts(energy_consumption, energy_it, energy_reuse, carbon_footprint, equivalent_datacenter_name,
|
|
103
|
+
equivalent_dc_carbon_footprint, saved_carbon_footprint_compute, saved_carbon_footprint_heat,
|
|
104
|
+
saved_carbon_footprint_compute_heat, saved_carbon_footprint_percent, PUE, ERE, ERF, WUE)
|
|
105
|
+
|
|
106
|
+
def to_json(self) -> object:
|
|
107
|
+
"""Get a dict ready to be json packed.
|
|
108
|
+
|
|
109
|
+
:return: the json elements of the class.
|
|
110
|
+
:rtype: `dict`
|
|
111
|
+
|
|
112
|
+
"""
|
|
113
|
+
return {
|
|
114
|
+
"total_consumed_energy_Wh": self.energy_consumption_Wh,
|
|
115
|
+
"total_energy_it_Wh": self.energy_it_Wh,
|
|
116
|
+
"total_reused_energy_Wh": self.energy_reuse_Wh,
|
|
117
|
+
"qarnot_carbon_footprint": self.carbon_footprint_gC02eq,
|
|
118
|
+
"equivalent_datacenter_name": self.equivalent_datacenter_name,
|
|
119
|
+
"equivalent_DC_carbon_footprint": self.equivalent_dc_carbon_footprint_gC02eq,
|
|
120
|
+
"saved_carbon_footprint_compute": self.saved_carbon_footprint_compute_gC02eq,
|
|
121
|
+
"saved_carbon_footprint_heat": self.saved_carbon_footprint_heat_gC02eq,
|
|
122
|
+
"saved_carbon_footprint_compute_heat": self.saved_carbon_footprint_compute_heat_gC02eq,
|
|
123
|
+
"saved_carbon_footprint_percent": self.saved_carbon_footprint_percent,
|
|
124
|
+
"PUE": self.PUE,
|
|
125
|
+
"ERE": self.ERE,
|
|
126
|
+
"ERF": self.ERF,
|
|
127
|
+
"WUE": self.WUE
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class CarbonClient(object):
|
|
132
|
+
"""
|
|
133
|
+
Client used to interact with the Qarnot carbon API.
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
def __init__(self, connection, datacenter_name: str = None):
|
|
137
|
+
"""The CarbonClient constructor.
|
|
138
|
+
|
|
139
|
+
:param connection: the cluster from where carbon facts are retrieved.
|
|
140
|
+
:type connection: `qarnot.connection.Connection`
|
|
141
|
+
:param datacenter_name: the name of the datacenter used as reference to compare carbon facts.
|
|
142
|
+
:type datacenter_name: `str`
|
|
143
|
+
"""
|
|
144
|
+
self._connection = connection
|
|
145
|
+
self.reference_datacenter_name = datacenter_name
|
|
146
|
+
|
|
147
|
+
def _get_carbon_facts_url(self, resource_type: str, uuid: str):
|
|
148
|
+
if self.reference_datacenter_name is None or self.reference_datacenter_name == "":
|
|
149
|
+
return get_url('%s carbon facts' % resource_type, uuid=uuid)
|
|
150
|
+
return get_url_with_param('%s carbon facts' % resource_type, {'comparisonDatacenter': self.reference_datacenter_name}, uuid=uuid)
|
|
151
|
+
|
|
152
|
+
def _get_pool_carbon_facts_raw(self, pool_id: str) -> Response:
|
|
153
|
+
"""Requests the carbon facts for the pool `pool_id`.
|
|
154
|
+
|
|
155
|
+
:param pool_id: the uuid of the pool
|
|
156
|
+
:type pool_id: `str`
|
|
157
|
+
:rtype: `requests.Response`
|
|
158
|
+
:raises ~qarnot.exceptions.MissingPoolException: Pool was not found.
|
|
159
|
+
:raises ~qarnot.exceptions.UnauthorizedException: Unauthorized.
|
|
160
|
+
:raises ~qarnot.exceptions.QarnotGenericException: API general error, see message for details
|
|
161
|
+
"""
|
|
162
|
+
response = self._connection._get(self._get_carbon_facts_url('pool', pool_id))
|
|
163
|
+
if response.status_code == 404:
|
|
164
|
+
raise MissingPoolException(_util.get_error_message_from_http_response(response))
|
|
165
|
+
raise_on_error(response)
|
|
166
|
+
return response
|
|
167
|
+
|
|
168
|
+
def get_pool_carbon_facts(self, pool_id: str) -> CarbonFacts:
|
|
169
|
+
"""Retrieves the carbon facts of the pool `pool_id` and parses it to a CarbonFacts object.
|
|
170
|
+
|
|
171
|
+
:param pool_id: the uuid of the pool
|
|
172
|
+
:type pool_id: `str`
|
|
173
|
+
:rtype: CarbonFacts
|
|
174
|
+
:raises ~qarnot.exceptions.MissingPoolException: Pool was not found.
|
|
175
|
+
:raises ~qarnot.exceptions.UnauthorizedException: Unauthorized.
|
|
176
|
+
:raises ~qarnot.exceptions.QarnotGenericException: API general error, see message for details
|
|
177
|
+
"""
|
|
178
|
+
raw_carbon_facts = self._get_pool_carbon_facts_raw(pool_id)
|
|
179
|
+
return CarbonFacts.from_json(raw_carbon_facts.json())
|
|
180
|
+
|
|
181
|
+
def _get_task_carbon_facts_raw(self, task_id: str) -> Response:
|
|
182
|
+
"""Requests the carbon facts for the task `task_id`.
|
|
183
|
+
|
|
184
|
+
:param task_id: the uuid of the task
|
|
185
|
+
:type task_id: `str`
|
|
186
|
+
:rtype: `requests.Response`
|
|
187
|
+
:raises ~qarnot.exceptions.MissingTaskException: Task was not found.
|
|
188
|
+
:raises ~qarnot.exceptions.UnauthorizedException: Unauthorized.
|
|
189
|
+
:raises ~qarnot.exceptions.QarnotGenericException: API general error, see message for details
|
|
190
|
+
"""
|
|
191
|
+
response = self._connection._get(self._get_carbon_facts_url('task', task_id))
|
|
192
|
+
if response.status_code == 404:
|
|
193
|
+
raise MissingTaskException(_util.get_error_message_from_http_response(response))
|
|
194
|
+
raise_on_error(response)
|
|
195
|
+
return response
|
|
196
|
+
|
|
197
|
+
def get_task_carbon_facts(self, task_id: str) -> CarbonFacts:
|
|
198
|
+
"""Retrieves the carbon facts of the task `task_id` and parses it to a CarbonFacts object.
|
|
199
|
+
|
|
200
|
+
:param task_id: the uuid of the task
|
|
201
|
+
:type task_id: `str`
|
|
202
|
+
:rtype: CarbonFacts
|
|
203
|
+
:raises ~qarnot.exceptions.MissingTaskException: Task was not found.
|
|
204
|
+
:raises ~qarnot.exceptions.UnauthorizedException: Unauthorized.
|
|
205
|
+
:raises ~qarnot.exceptions.QarnotGenericException: API general error, see message for details
|
|
206
|
+
"""
|
|
207
|
+
raw_carbon_facts = self._get_task_carbon_facts_raw(task_id)
|
|
208
|
+
return CarbonFacts.from_json(raw_carbon_facts.json())
|