Skip to content

Commit

Permalink
[PT-5886] Simplify order construction (#698)
Browse files Browse the repository at this point in the history
* Introduce order get method

* Code and test adaptation

* Convert order to dataclass

* Drop unneeded test

* Update changelog entries

* Clean up
  • Loading branch information
javidq authored Dec 17, 2024
1 parent ca9d6b6 commit b60f3e4
Show file tree
Hide file tree
Showing 8 changed files with 95 additions and 173 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ You can check your current version with the following command:
```

For more information, see [UP42 Python package description](https://pypi.org/project/up42-py/).
## 2.2.0a1
**Dec 17, 2024**
- Converted `Order` to dataclass.
- Dropped eager loading of `Order::info`.
- Added `Order::get` class method as part of conversion to active record pattern.
- Extended `Order::order_details` to cover archive orders as well.
- Dropped `Order::__repr__` in favour of native dataclass implementation.
- Added `Order::track` method and deprecated `Order::track_status` method.

## 2.1.1
**Dec 10, 2024**

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "up42-py"
version = "2.1.1"
version = "2.2.0a1"
description = "Python SDK for UP42, the geospatial marketplace and developer platform."
authors = ["UP42 GmbH <[email protected]>"]
license = "https://github.com/up42/up42-py/blob/master/LICENSE"
Expand Down
10 changes: 3 additions & 7 deletions tests/test_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,9 @@ def test_should_place_order(
collection_type: glossary.CollectionType,
):
info = {"status": "SOME STATUS"}
requests_mock.get(
url=f"{constants.API_HOST}/v2/orders/{constants.ORDER_ID}",
json=info,
)
requests_mock.post(
url=f"{constants.API_HOST}/v2/orders?workspaceId={constants.WORKSPACE_ID}",
json={"results": [{"id": constants.ORDER_ID}], "errors": []},
json={"results": [{"id": constants.ORDER_ID} | info], "errors": []},
)
order_obj = catalog.CatalogBase(collection_type).place_order(order_parameters=order_parameters)
assert order_obj.order_id == constants.ORDER_ID
Expand All @@ -100,10 +96,10 @@ def test_should_track_order_status(
):
requests_mock.post(
url=f"{constants.API_HOST}/v2/orders?workspaceId={constants.WORKSPACE_ID}",
json={"results": [{"id": constants.ORDER_ID}], "errors": []},
json={"results": [{"id": constants.ORDER_ID, "status": "CREATED"}], "errors": []},
)
statuses = ["INITIAL STATUS", "PLACED", "BEING_FULFILLED", "FULFILLED"]
responses = [{"json": {"status": status, **info}} for status in statuses]
responses = [{"json": {"status": status, "id": constants.ORDER_ID, **info}} for status in statuses]
requests_mock.get(f"{constants.API_HOST}/v2/orders/{constants.ORDER_ID}", responses)
order_obj = catalog.CatalogBase(collection_type).place_order(
order_parameters=order_parameters,
Expand Down
105 changes: 34 additions & 71 deletions tests/test_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@
ASSET_ORDER_ID = "22d0b8e9-b649-4971-8adc-1a5eac1fa6f3"
ORDER_URL = f"{constants.API_HOST}/v2/orders/{constants.ORDER_ID}"
ORDER_PLACEMENT_URL = f"{constants.API_HOST}/v2/orders?workspaceId={constants.WORKSPACE_ID}"
ORDER_INFO = {
"id": constants.ORDER_ID,
"status": "CREATED",
"other": "data",
"createdAt": "2023-01-01T12:00:00Z",
"updatedAt": "2023-01-01T12:30:00Z",
}


class TestOrder:
Expand All @@ -18,66 +25,28 @@ def order_parameters(self, request) -> order.OrderParams:
"params": {geometry_key: {"some": "shape"}},
}

def test_should_initialize_with_info_provided(self):
info = {"some": "data"}
order_obj = order.Order(constants.ORDER_ID, info)
assert order_obj.order_id == constants.ORDER_ID
assert order_obj._info == info # pylint: disable=protected-access

def test_should_initialize(self, requests_mock: req_mock.Mocker):
info = {"some": "data"}
requests_mock.get(url=ORDER_URL, json=info)
order_obj = order.Order(constants.ORDER_ID)
assert order_obj.order_id == constants.ORDER_ID
assert order_obj.info == info

def test_should_provide_representation(self):
info = {
"id": constants.ORDER_ID,
"status": "PLACED",
"createdAt": "2023-01-01T12:00:00Z",
"updatedAt": "2023-01-01T12:30:00Z",
}
order_obj = order.Order(order_id=constants.ORDER_ID, order_info=info)
expected_repr = (
f"Order(order_id: {constants.ORDER_ID}, status: PLACED,"
"createdAt: 2023-01-01T12:00:00Z, updatedAt: 2023-01-01T12:30:00Z)"
)
assert repr(order_obj) == expected_repr
def test_should_provide_order_id(self):
assert order.Order(ORDER_INFO).order_id == constants.ORDER_ID

def test_should_provide_status(self, requests_mock: req_mock.Mocker):
info = {"status": "random"}
requests_mock.get(url=ORDER_URL, json=info)
order_obj = order.Order(order_id=constants.ORDER_ID, order_info=info)
assert order_obj.status == info["status"]
def test_should_provide_status(self):
assert order.Order(ORDER_INFO).status == ORDER_INFO["status"]

@pytest.mark.parametrize(
"info, expected",
[
({"type": "ARCHIVE"}, {}),
(
{"type": "TASKING", "orderDetails": {"order": "details"}},
{"order": "details"},
),
],
ids=["ARCHIVE", "TASKING"],
"details, expected", [({"orderDetails": {"order": "details"}}, {"order": "details"}), ({}, {})]
)
def test_should_provide_order_details(self, requests_mock: req_mock.Mocker, info: dict, expected: dict):
requests_mock.get(url=ORDER_URL, json=info)
order_obj = order.Order(order_id=constants.ORDER_ID, order_info=info)
def test_should_provide_order_details(self, details: dict, expected: dict):
order_obj = order.Order(info=ORDER_INFO | details)
assert order_obj.order_details == expected

@pytest.mark.parametrize(
"info, expected",
"status, expected",
[
({"status": "FULFILLED"}, True),
({"status": "OTHER STATUS"}, False),
("FULFILLED", True),
("OTHER STATUS", False),
],
ids=["FULFILLED", "OTHER STATUS"],
)
def test_should_compute_is_fulfilled(self, requests_mock: req_mock.Mocker, info: dict, expected: bool):
requests_mock.get(url=ORDER_URL, json=info)
order_obj = order.Order(order_id=constants.ORDER_ID, order_info=info)
def test_should_compute_is_fulfilled(self, status: str, expected: bool):
order_obj = order.Order(info=ORDER_INFO | {"status": status})
assert order_obj.is_fulfilled == expected

@pytest.mark.parametrize(
Expand All @@ -88,8 +57,6 @@ def test_should_compute_is_fulfilled(self, requests_mock: req_mock.Mocker, info:
],
)
def test_should_get_assets_if_valid(self, requests_mock: req_mock.Mocker, status: str):
info = {"id": constants.ORDER_ID, "status": status}
requests_mock.get(url=ORDER_URL, json=info)
url_asset_info = f"{constants.API_HOST}/v2/assets?search={constants.ORDER_ID}"
asset_info = {
"content": [
Expand All @@ -100,7 +67,7 @@ def test_should_get_assets_if_valid(self, requests_mock: req_mock.Mocker, status
"totalPages": 1,
}
requests_mock.get(url=url_asset_info, json=asset_info)
order_obj = order.Order(order_id=constants.ORDER_ID)
order_obj = order.Order(info=ORDER_INFO | {"status": status})
(asset_obj,) = order_obj.get_assets()
assert isinstance(asset_obj, asset.Asset)
assert asset_obj.asset_id == ASSET_ORDER_ID
Expand All @@ -118,39 +85,40 @@ def test_should_get_assets_if_valid(self, requests_mock: req_mock.Mocker, status
"FAILED_PERMANENTLY",
],
)
def test_fails_to_get_assets_if_not_fulfilled(self, requests_mock: req_mock.Mocker, status: str):
info = {"status": status}
requests_mock.get(url=ORDER_URL, json=info)
order_obj = order.Order(order_id=constants.ORDER_ID, order_info=info)
def test_fails_to_get_assets_if_not_fulfilled(self, status: str):
order_obj = order.Order(info=ORDER_INFO | {"status": status})
with pytest.raises(order.UnfulfilledOrder, match=f".*{constants.ORDER_ID}.*{status}"):
order_obj.get_assets()

@pytest.mark.parametrize(
"info",
"extra_info",
[
{"type": "ARCHIVE"},
{"type": "TASKING", "orderDetails": {"subStatus": "substatus"}},
],
ids=["ARCHIVE", "TASKING"],
)
def test_should_track_order_status_until_fulfilled(self, requests_mock: req_mock.Mocker, info: dict):
def test_should_track_order_status_until_fulfilled(self, requests_mock: req_mock.Mocker, extra_info: dict):
statuses = ["PLACED", "BEING_FULFILLED", "FULFILLED"]
responses = [{"json": {"status": status, **info}} for status in statuses]
responses = [{"json": ORDER_INFO | {"status": status} | extra_info} for status in statuses]
requests_mock.get(ORDER_URL, responses)
order_obj = order.Order(order_id=constants.ORDER_ID)
order_obj = order.Order.get(order_id=constants.ORDER_ID)
assert order_obj.track_status(report_time=0.1) == "FULFILLED"

@pytest.mark.parametrize("status", ["FAILED", "FAILED_PERMANENTLY"])
def test_fails_to_track_order_if_status_not_valid(self, requests_mock: req_mock.Mocker, status: str):
info = {"status": status, "type": "ANY"}
requests_mock.get(
url=ORDER_URL,
json=info,
json=ORDER_INFO | {"status": status, "type": "ANY"},
)
order_obj = order.Order(order_id=constants.ORDER_ID)
order_obj = order.Order.get(order_id=constants.ORDER_ID)
with pytest.raises(order.FailedOrder):
order_obj.track_status()

def test_should_get(self, requests_mock: req_mock.Mocker):
requests_mock.get(url=ORDER_URL, json=ORDER_INFO)
assert order.Order.get(constants.ORDER_ID) == order.Order(ORDER_INFO)

def test_should_estimate(self, requests_mock: req_mock.Mocker, order_parameters: order.OrderParams):
order_estimate_url = f"{constants.API_HOST}/v2/orders/estimate"
expected_credits = 100
Expand All @@ -164,17 +132,12 @@ def test_should_estimate(self, requests_mock: req_mock.Mocker, order_parameters:
assert order.Order.estimate(order_parameters) == expected_credits

def test_should_place_order(self, requests_mock: req_mock.Mocker, order_parameters: order.OrderParams):
info = {"status": "SOME STATUS"}
requests_mock.get(
url=ORDER_URL,
json=info,
)
requests_mock.post(
url=ORDER_PLACEMENT_URL,
json={"results": [{"id": constants.ORDER_ID}], "errors": []},
json={"results": [ORDER_INFO], "errors": []},
)
order_obj = order.Order.place(order_parameters, constants.WORKSPACE_ID)
assert order_obj == order.Order(order_id=constants.ORDER_ID, order_info=info)
assert order_obj == order.Order(info=ORDER_INFO)

def test_fails_to_place_order_if_response_contains_error(
self, requests_mock: req_mock.Mocker, order_parameters: order.OrderParams
Expand Down
4 changes: 2 additions & 2 deletions tests/test_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def test_should_get_orders(
},
doseq=True,
)
expected = [{"order": "info", "id": constants.ORDER_ID}] * 20
expected = [{"order": "info", "id": constants.ORDER_ID, "status": "some-status"}] * 20
requests_mock.get(
f"{constants.API_HOST}/v2/orders?{query}",
json={"content": expected, "page": 0, "totalPages": 1},
Expand All @@ -120,4 +120,4 @@ def test_should_get_orders(
if return_json:
assert orders == expected[:limit]
else:
assert orders == [order.Order(order_id=info["id"], order_info=info) for info in expected[:limit]]
assert orders == [order.Order(info=info) for info in expected[:limit]]
2 changes: 1 addition & 1 deletion up42/initialization.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def initialize_order(order_id: str) -> order.Order:
Args:
order_id: The UP42 order_id
"""
up42_order = order.Order(order_id=order_id)
up42_order = order.Order.get(order_id=order_id)
logger.info(INITIALIZED_MSG, up42_order)
return up42_order

Expand Down
Loading

0 comments on commit b60f3e4

Please sign in to comment.