Skip to content

Commit 9ffd1aa

Browse files
nekhtiariChristoph Rieke
and
Christoph Rieke
authored
Add price estimation endpoint in SDK (#171)
* Add price estimation endpoint in SDK * Update the tests * Add reviewer cm * Bump the version * correct the version * Add reviewer cm * add to docs structure * rename * example in docstring * add livetest * Add estimation in the 30 seconds example * revert version Co-authored-by: Christoph Rieke <[email protected]>
1 parent b0d715c commit 9ffd1aa

9 files changed

+380
-34
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ pip show up42-py
1515
```
1616

1717
## Versions
18+
### [0.14.0](https://pypi.org/project/up42-py/) (2020-11-18)
19+
- Add `workflow.estimate_job` for getting estimation the cost of running a workflow.
20+
- Add boolean `get_estimation` parameter to `workflow.test_job` for getting cost's estimation when running test job. By default is set to false.
1821

1922
### [0.13.1](https://pypi.org/project/up42-py/) (2020-11-18)
2023
- Handle request rate limits via retry mechanism.

docs/structure.md

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ function.
5050
- `.workflow_tasks`
5151
- `.add_workflow_tasks()`
5252
- `.construct_parameters()`
53+
- `.estimate_job()`
5354
- `.test_job()`
5455
- `.run_job()`
5556
- `.construct_parameters_parallel()`

examples/guides/30-seconds-example.ipynb

+13-3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@
5757
"input_parameters"
5858
]
5959
},
60+
{
61+
"cell_type": "code",
62+
"execution_count": null,
63+
"metadata": {},
64+
"outputs": [],
65+
"source": [
66+
"# Get the estimation of credits for running the job\n",
67+
"estimate_job = workflow.estimate_job(input_parameters)"
68+
]
69+
},
6070
{
6171
"cell_type": "code",
6272
"execution_count": null,
@@ -99,9 +109,9 @@
99109
],
100110
"metadata": {
101111
"kernelspec": {
102-
"display_name": "up42-py",
112+
"display_name": "up42-pydev",
103113
"language": "python",
104-
"name": "up42-py"
114+
"name": "up42-pydev"
105115
},
106116
"language_info": {
107117
"codemirror_mode": {
@@ -113,7 +123,7 @@
113123
"name": "python",
114124
"nbconvert_exporter": "python",
115125
"pygments_lexer": "ipython3",
116-
"version": "3.7.5"
126+
"version": "3.7.7"
117127
}
118128
},
119129
"nbformat": 4,

tests/context.py

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from up42.jobcollection import JobCollection
2222
from up42.jobtask import JobTask
2323
from up42.catalog import Catalog
24+
from up42.estimation import Estimation
2425
from up42.__init__ import (
2526
authenticate,
2627
initialize_project,

tests/fixtures.py

+109-10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
JobTask,
1313
Tools,
1414
Catalog,
15+
Estimation,
1516
)
1617

1718

@@ -36,36 +37,48 @@
3637

3738

3839
JSON_WORKFLOW_TASKS = {
40+
"error": "None",
3941
"data": [
4042
{
41-
"id": "c0d04ec3-98d7-4183-902f-5bcb2a176d89",
43+
"id": "aa2cba17-d35c-4395-ab01-a0fd8191a4b3",
4244
"name": "sobloo-s2-l1c-aoiclipped:1",
43-
"blockVersionTag": "2.2.2",
45+
"parentsIds": [],
46+
"blockName": "sobloo-s2-l1c-aoiclipped",
47+
"blockVersionTag": "2.3.0",
4448
"block": {
49+
"id": "3a381e6b-acb7-4cec-ae65-50798ce80e64",
4550
"name": "sobloo-s2-l1c-aoiclipped",
51+
"displayName": "Sentinel-2 L1C MSI AOI clipped",
4652
"parameters": {
47-
"nodata": {
48-
"type": "number",
49-
},
53+
"ids": {"type": "array", "default": "None"},
54+
"bbox": {"type": "array", "default": "None"},
5055
"time": {
5156
"type": "dateRange",
5257
"default": "2018-01-01T00:00:00+00:00/2020-12-31T23:59:59+00:00",
5358
},
5459
},
60+
"type": "DATA",
61+
"isDryRunSupported": True,
62+
"version": "2.3.0",
5563
},
64+
"environment": "None",
5665
},
5766
{
58-
"id": "af626c54-156e-4f13-a743-55efd27de533",
67+
"id": "24375b2a-288b-46c8-b404-53e48d4e7b25",
5968
"name": "tiling:1",
60-
"blockVersionTag": "1.0.0",
69+
"parentsIds": ["aa2cba17-d35c-4395-ab01-a0fd8191a4b3"],
70+
"blockName": "tiling",
71+
"blockVersionTag": "2.2.3",
6172
"block": {
73+
"id": "3e146dd6-2b67-4d6e-a422-bb3d973e32ff",
6274
"name": "tiling",
75+
"displayName": "Raster Tiling",
6376
"parameters": {
6477
"nodata": {
6578
"type": "number",
66-
"default": None,
79+
"default": "None",
6780
"required": False,
68-
"description": "Value representing..",
81+
"description": "Value representing ...",
6982
},
7083
"tile_width": {
7184
"type": "number",
@@ -74,10 +87,13 @@
7487
"description": "Width of a tile in pixels",
7588
},
7689
},
90+
"type": "PROCESSING",
91+
"isDryRunSupported": False,
92+
"version": "2.2.3",
7793
},
94+
"environment": "None",
7895
},
7996
],
80-
"error": {},
8197
}
8298

8399
JSON_BLOCKS = {
@@ -101,6 +117,32 @@
101117
"error": {},
102118
}
103119

120+
JSON_WORKFLOW_ESTIMATION = {
121+
"data": {
122+
"sobloo-s2-l1c-aoiclipped:1": {
123+
"blockConsumption": {
124+
"resources": {"unit": "MEGABYTE", "min": 3.145728, "max": 3.145728},
125+
"credit": {"min": 0, "max": 0},
126+
},
127+
"machineConsumption": {
128+
"duration": {"min": 4041, "max": 26380},
129+
"credit": {"min": 3, "max": 3},
130+
},
131+
},
132+
"tiling:1": {
133+
"blockConsumption": {
134+
"resources": {"unit": "MEGABYTE", "min": 3.145728, "max": 3.145728},
135+
"credit": {"min": 0, "max": 0},
136+
},
137+
"machineConsumption": {
138+
"duration": {"min": 80930, "max": 428927},
139+
"credit": {"min": 2, "max": 9},
140+
},
141+
},
142+
},
143+
"error": {},
144+
}
145+
104146

105147
# TODO: Use patch.dict instead of 2 fictures?
106148
@pytest.fixture()
@@ -426,6 +468,63 @@ def jobs_live(auth_live):
426468
return [job_1, job_2]
427469

428470

471+
@pytest.fixture()
472+
def estimation_mock(auth_mock):
473+
input_parameters = {
474+
"sobloo-s2-l1c-aoiclipped:1": {
475+
"time": "2018-01-01T00:00:00+00:00/2020-12-31T23:59:59+00:00",
476+
"limit": 1,
477+
"bbox": [13.33409, 52.474922, 13.38547, 52.500398],
478+
},
479+
"tiling:1": {"tile_width": 768},
480+
}
481+
482+
input_tasks = [
483+
{
484+
"name": "sobloo-s2-l1c-aoiclipped:1",
485+
"parentName": None,
486+
"blockId": "3a381e6b-acb7-4cec-ae65-50798ce80e64",
487+
"blockVersionTag": "2.3.0",
488+
},
489+
{
490+
"name": "tiling:1",
491+
"parentName": "sobloo-s2-l1c-aoiclipped:1",
492+
"blockId": "3e146dd6-2b67-4d6e-a422-bb3d973e32ff",
493+
"blockVersionTag": "2.2.3",
494+
},
495+
]
496+
497+
return Estimation(auth_mock, input_parameters, input_tasks)
498+
499+
500+
@pytest.fixture()
501+
def estimation_live(auth_live):
502+
input_parameters = {
503+
"sobloo-s2-l1c-aoiclipped:1": {
504+
"time": "2018-01-01T00:00:00+00:00/2020-12-31T23:59:59+00:00",
505+
"limit": 1,
506+
"bbox": [13.33409, 52.474922, 13.38547, 52.500398],
507+
},
508+
"tiling:1": {"tile_width": 768},
509+
}
510+
511+
input_tasks = [
512+
{
513+
"name": "sobloo-s2-l1c-aoiclipped:1",
514+
"parentName": None,
515+
"blockId": "3a381e6b-acb7-4cec-ae65-50798ce80e64",
516+
"blockVersionTag": "2.3.0",
517+
},
518+
{
519+
"name": "tiling:1",
520+
"parentName": "sobloo-s2-l1c-aoiclipped:1",
521+
"blockId": "3e146dd6-2b67-4d6e-a422-bb3d973e32ff",
522+
"blockVersionTag": "2.2.3",
523+
},
524+
]
525+
return Estimation(auth_live, input_parameters, input_tasks)
526+
527+
429528
@pytest.fixture()
430529
def jobcollection_single_mock(auth_mock, job_mock):
431530
return JobCollection(

tests/test_estimation.py

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import pytest
2+
3+
# pylint: disable=unused-import,wrong-import-order
4+
from .context import Estimation
5+
from .fixtures import (
6+
auth_mock,
7+
auth_live,
8+
estimation_mock,
9+
JSON_WORKFLOW_ESTIMATION,
10+
)
11+
12+
13+
def test_estimate_price(requests_mock, auth_mock, estimation_mock):
14+
input_tasks = [
15+
{
16+
"name": "sobloo-s2-l1c-aoiclipped:1",
17+
"parentName": None,
18+
"blockId": "3a381e6b-acb7-4cec-ae65-50798ce80e64",
19+
"blockVersionTag": "2.3.0",
20+
},
21+
{
22+
"name": "tiling:1",
23+
"parentName": "sobloo-s2-l1c-aoiclipped:1",
24+
"blockId": "3e146dd6-2b67-4d6e-a422-bb3d973e32ff",
25+
"blockVersionTag": "2.2.3",
26+
},
27+
]
28+
29+
url_workflow_estimation = f"{auth_mock._endpoint()}/estimate/job"
30+
requests_mock.post(url=url_workflow_estimation, json=JSON_WORKFLOW_ESTIMATION)
31+
_ = estimation_mock.estimate()
32+
assert list(estimation_mock.payload.keys()) == ["tasks", "inputs"]
33+
assert estimation_mock.payload["tasks"] == input_tasks
34+
35+
36+
@pytest.mark.live
37+
def test_estimate_price_live(auth_live):
38+
input_parameters = {
39+
"sobloo-s2-l1c-aoiclipped:1": {
40+
"time": "2018-01-01T00:00:00+00:00/2020-12-31T23:59:59+00:00",
41+
"limit": 1,
42+
"bbox": [13.33409, 52.474922, 13.38547, 52.500398],
43+
},
44+
"tiling:1": {"tile_width": 768},
45+
}
46+
47+
input_tasks = [
48+
{
49+
"name": "sobloo-s2-l1c-aoiclipped:1",
50+
"parentName": None,
51+
"blockId": "3a381e6b-acb7-4cec-ae65-50798ce80e64",
52+
"blockVersionTag": "2.3.0",
53+
},
54+
{
55+
"name": "tiling:1",
56+
"parentName": "sobloo-s2-l1c-aoiclipped:1",
57+
"blockId": "3e146dd6-2b67-4d6e-a422-bb3d973e32ff",
58+
"blockVersionTag": "2.2.3",
59+
},
60+
]
61+
estimation = Estimation(auth_live, input_parameters, input_tasks).estimate()
62+
assert isinstance(estimation, dict)
63+
assert len(estimation) == 2
64+
assert list(estimation.keys()) == ["sobloo-s2-l1c-aoiclipped:1", "tiling:1"]
65+
assert list(estimation["sobloo-s2-l1c-aoiclipped:1"].keys()) == [
66+
"blockConsumption",
67+
"machineConsumption",
68+
]

0 commit comments

Comments
 (0)