diff --git a/arkindex_worker/worker.py b/arkindex_worker/worker.py index e00e4952ec20e694d916f914fe28599b51dc6592..3bfc1be0b9d5812ffd29eeb1f8e07ade404523ce 100644 --- a/arkindex_worker/worker.py +++ b/arkindex_worker/worker.py @@ -394,6 +394,65 @@ class ElementsWorker(BaseWorker): return sub_element["id"] + def create_elements(self, parent, elements): + """ + Create children elements on the given element through API + Return the IDs of created elements + """ + assert parent and isinstance( + parent, Element + ), "element shouldn't be null and should be of type Element" + assert elements and isinstance( + elements, list + ), "elements shouldn't be null and should be of type list" + + for index, element in enumerate(elements): + assert isinstance( + element, dict + ), f"Element at index {index} in elements: Should be of type dict" + + name = element.get("name") + assert name and isinstance( + name, str + ), f"Element at index {index} in elements: name shouldn't be null and should be of type str" + + type = element.get("type") + assert type and isinstance( + type, str + ), f"Element at index {index} in elements: type shouldn't be null and should be of type str" + + polygon = element.get("polygon") + assert polygon and isinstance( + polygon, list + ), f"Element at index {index} in elements: polygon shouldn't be null and should be of type list" + assert ( + len(polygon) >= 3 + ), f"Element at index {index} in elements: polygon should have at least three points" + assert all( + isinstance(point, list) and len(point) == 2 for point in polygon + ), f"Element at index {index} in elements: polygon points should be lists of two items" + assert all( + isinstance(coord, (int, float)) for point in polygon for coord in point + ), f"Element at index {index} in elements: polygon points should be lists of two numbers" + + if self.is_read_only: + logger.warning("Cannot create elements as this worker is in read-only mode") + return + + created_ids = self.api_client.request( + "CreateElements", + id=parent.id, + body={ + "worker_version": self.worker_version_id, + "elements": elements, + }, + ) + + for element in elements: + self.report.add_element(parent.id, element["type"]) + + return created_ids + def create_transcription(self, element, text, type=None, score=None): """ Create a transcription on the given element through the API. diff --git a/tests/test_elements_worker/test_elements.py b/tests/test_elements_worker/test_elements.py index 87e9363c6dfd2d7665c999c0dce7c83930a0c910..a1faf67f4ff42b95c2248bdd277538591e65e970 100644 --- a/tests/test_elements_worker/test_elements.py +++ b/tests/test_elements_worker/test_elements.py @@ -392,6 +392,290 @@ def test_create_sub_element(responses, mock_elements_worker): assert sub_element_id == "12345678-1234-1234-1234-123456789123" +def test_create_elements_wrong_parent(mock_elements_worker): + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=None, + elements=[], + ) + assert str(e.value) == "element shouldn't be null and should be of type Element" + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent="not element type", + elements=[], + ) + assert str(e.value) == "element shouldn't be null and should be of type Element" + + +def test_create_elements_wrong_elements(mock_elements_worker): + elt = Element({"zone": None}) + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements=None, + ) + assert str(e.value) == "elements shouldn't be null and should be of type list" + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements="not a list", + ) + assert str(e.value) == "elements shouldn't be null and should be of type list" + + +def test_create_elements_wrong_elements_instance(mock_elements_worker): + elt = Element({"zone": None}) + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements=["not a dict"], + ) + assert str(e.value) == "Element at index 0 in elements: Should be of type dict" + + +def test_create_elements_wrong_elements_name(mock_elements_worker): + elt = Element({"zone": None}) + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements=[ + { + "name": None, + "type": "something", + "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]], + } + ], + ) + assert ( + str(e.value) + == "Element at index 0 in elements: name shouldn't be null and should be of type str" + ) + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements=[ + { + "name": 1234, + "type": "something", + "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]], + } + ], + ) + assert ( + str(e.value) + == "Element at index 0 in elements: name shouldn't be null and should be of type str" + ) + + +def test_create_elements_wrong_elements_type(mock_elements_worker): + elt = Element({"zone": None}) + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements=[ + { + "name": "0", + "type": None, + "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]], + } + ], + ) + assert ( + str(e.value) + == "Element at index 0 in elements: type shouldn't be null and should be of type str" + ) + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements=[ + { + "name": "0", + "type": 1234, + "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]], + } + ], + ) + assert ( + str(e.value) + == "Element at index 0 in elements: type shouldn't be null and should be of type str" + ) + + +def test_create_elements_wrong_elements_polygon(mock_elements_worker): + elt = Element({"zone": None}) + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements=[ + { + "name": "0", + "type": "something", + "polygon": None, + } + ], + ) + assert ( + str(e.value) + == "Element at index 0 in elements: polygon shouldn't be null and should be of type list" + ) + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements=[ + { + "name": "0", + "type": "something", + "polygon": "not a polygon", + } + ], + ) + assert ( + str(e.value) + == "Element at index 0 in elements: polygon shouldn't be null and should be of type list" + ) + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements=[ + { + "name": "0", + "type": "something", + "polygon": [[1, 1], [2, 2]], + } + ], + ) + assert ( + str(e.value) + == "Element at index 0 in elements: polygon should have at least three points" + ) + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements=[ + { + "name": "0", + "type": "something", + "polygon": [[1, 1, 1], [2, 2, 1], [2, 1, 1], [1, 2, 1]], + } + ], + ) + assert ( + str(e.value) + == "Element at index 0 in elements: polygon points should be lists of two items" + ) + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements=[ + { + "name": "0", + "type": "something", + "polygon": [[1], [2], [2], [1]], + } + ], + ) + assert ( + str(e.value) + == "Element at index 0 in elements: polygon points should be lists of two items" + ) + + with pytest.raises(AssertionError) as e: + mock_elements_worker.create_elements( + parent=elt, + elements=[ + { + "name": "0", + "type": "something", + "polygon": [["not a coord", 1], [2, 2], [2, 1], [1, 2]], + } + ], + ) + assert ( + str(e.value) + == "Element at index 0 in elements: polygon points should be lists of two numbers" + ) + + +def test_create_elements_api_error(responses, mock_elements_worker): + elt = Element({"id": "12341234-1234-1234-1234-123412341234"}) + responses.add( + responses.POST, + "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/", + status=500, + ) + + with pytest.raises(ErrorResponse): + mock_elements_worker.create_elements( + parent=elt, + elements=[ + { + "name": "0", + "type": "something", + "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]], + } + ], + ) + + assert len(responses.calls) == 3 + assert [call.request.url for call in responses.calls] == [ + "http://testserver/api/v1/user/", + "http://testserver/api/v1/workers/versions/12341234-1234-1234-1234-123412341234/", + "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/", + ] + + +def test_create_elements(responses, mock_elements_worker): + elt = Element({"id": "12341234-1234-1234-1234-123412341234"}) + responses.add( + responses.POST, + "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/", + status=200, + json=[{"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"}], + ) + + created_ids = mock_elements_worker.create_elements( + parent=elt, + elements=[ + { + "name": "0", + "type": "something", + "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]], + } + ], + ) + + assert len(responses.calls) == 3 + assert [call.request.url for call in responses.calls] == [ + "http://testserver/api/v1/user/", + "http://testserver/api/v1/workers/versions/12341234-1234-1234-1234-123412341234/", + "http://testserver/api/v1/element/12341234-1234-1234-1234-123412341234/children/bulk/", + ] + assert json.loads(responses.calls[2].request.body) == { + "elements": [ + { + "name": "0", + "type": "something", + "polygon": [[1, 1], [2, 2], [2, 1], [1, 2]], + } + ], + "worker_version": "12341234-1234-1234-1234-123412341234", + } + assert created_ids == [{"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08"}] + + def test_list_element_children_wrong_element(mock_elements_worker): with pytest.raises(AssertionError) as e: mock_elements_worker.list_element_children(element=None)