From 0d85fcac2ce9bb2c156f57544d4c2b60134dbf0d Mon Sep 17 00:00:00 2001 From: Yoann Schneider <yschneider@teklia.com> Date: Fri, 2 Sep 2022 10:15:38 +0000 Subject: [PATCH] Create missing types option when checking required types existence --- arkindex_worker/worker/element.py | 47 ++++++++++++++--- tests/test_elements_worker/test_elements.py | 57 ++++++++++++++++++--- 2 files changed, 90 insertions(+), 14 deletions(-) diff --git a/arkindex_worker/worker/element.py b/arkindex_worker/worker/element.py index a22dbd0e..bf263e5c 100644 --- a/arkindex_worker/worker/element.py +++ b/arkindex_worker/worker/element.py @@ -4,13 +4,15 @@ ElementsWorker methods for elements and element types. """ import uuid -from typing import Dict, Iterable, List, Optional, Union +from typing import Dict, Iterable, List, NamedTuple, Optional, Union from peewee import IntegrityError from arkindex_worker import logger from arkindex_worker.cache import CachedElement, CachedImage -from arkindex_worker.models import Element +from arkindex_worker.models import Corpus, Element + +ElementType = NamedTuple("ElementType", name=str, slug=str, is_folder=bool) class MissingTypeError(Exception): @@ -24,13 +26,34 @@ class ElementMixin(object): Mixin for the :class:`ElementsWorker` to provide ``Element`` helpers. """ - def check_required_types(self, corpus_id: str, *type_slugs: str) -> bool: + def create_required_types(self, corpus: Corpus, element_types: List[ElementType]): + """Creates given element types in the corpus. + + :param Corpus corpus: The corpus to create types on. + :param List[ElementType] element_types: The missing element types to create. + """ + for element_type in element_types: + self.request( + "CreateElementType", + body={ + "slug": element_type.slug, + "display_name": element_type.name, + "folder": element_type.is_folder, + "corpus": corpus.id, + }, + ) + logger.info(f"Created a new element type with slug {element_type.slug}") + + def check_required_types( + self, corpus_id: str, *type_slugs: str, create_missing: bool = False + ) -> bool: """ Check that a corpus has a list of required element types, and raise an exception if any of them are missing. :param str corpus_id: ID of the corpus to check types on. :param str \\*type_slugs: Type slugs to look for. + :param bool create_missing: Whether missing types should be created. :returns bool: True if all of the specified type slugs have been found. :raises MissingTypeError: If any of the specified type slugs were not found. """ @@ -42,14 +65,22 @@ class ElementMixin(object): isinstance(slug, str) for slug in type_slugs ), "Element type slugs must be strings." - corpus = self.request("RetrieveCorpus", id=corpus_id) - available_slugs = {element_type["slug"] for element_type in corpus["types"]} + corpus = Corpus(self.request("RetrieveCorpus", id=corpus_id)) + available_slugs = {element_type.slug for element_type in corpus.types} missing_slugs = set(type_slugs) - available_slugs if missing_slugs: - raise MissingTypeError( - f'Element type(s) {", ".join(sorted(missing_slugs))} were not found in the {corpus["name"]} corpus ({corpus["id"]}).' - ) + if create_missing: + self.create_required_types( + corpus, + element_types=[ + ElementType(slug, slug, False) for slug in missing_slugs + ], + ) + else: + raise MissingTypeError( + f'Element type(s) {", ".join(sorted(missing_slugs))} were not found in the {corpus.name} corpus ({corpus.id}).' + ) return True diff --git a/tests/test_elements_worker/test_elements.py b/tests/test_elements_worker/test_elements.py index 7ff16855..c74aa273 100644 --- a/tests/test_elements_worker/test_elements.py +++ b/tests/test_elements_worker/test_elements.py @@ -5,6 +5,7 @@ from uuid import UUID import pytest from apistar.exceptions import ErrorResponse +from responses import matchers from arkindex_worker.cache import ( SQL_VERSION, @@ -33,11 +34,7 @@ def test_check_required_types_argument_types(mock_elements_worker): assert str(e.value) == "Element type slugs must be strings." -def test_check_required_types(monkeypatch, tmp_path, mock_elements_worker, responses): - elements_path = tmp_path / "elements.json" - elements_path.write_text("[]") - monkeypatch.setenv("TASK_ELEMENTS", str(elements_path)) - +def test_check_required_types(responses): corpus_id = "12341234-1234-1234-1234-123412341234" responses.add( responses.GET, @@ -49,7 +46,7 @@ def test_check_required_types(monkeypatch, tmp_path, mock_elements_worker, respo }, ) worker = ElementsWorker() - worker.configure() + worker.setup_api_client() assert worker.check_required_types(corpus_id, "page") assert worker.check_required_types(corpus_id, "page", "folder") @@ -62,6 +59,54 @@ def test_check_required_types(monkeypatch, tmp_path, mock_elements_worker, respo ) +def test_create_missing_types(responses): + corpus_id = "12341234-1234-1234-1234-123412341234" + + responses.add( + responses.GET, + f"http://testserver/api/v1/corpus/{corpus_id}/", + json={ + "id": corpus_id, + "name": "Some Corpus", + "types": [{"slug": "folder"}, {"slug": "page"}], + }, + ) + responses.add( + responses.POST, + "http://testserver/api/v1/elements/type/", + match=[ + matchers.json_params_matcher( + { + "slug": "text_line", + "display_name": "text_line", + "folder": False, + "corpus": corpus_id, + } + ) + ], + ) + responses.add( + responses.POST, + "http://testserver/api/v1/elements/type/", + match=[ + matchers.json_params_matcher( + { + "slug": "act", + "display_name": "act", + "folder": False, + "corpus": corpus_id, + } + ) + ], + ) + worker = ElementsWorker() + worker.setup_api_client() + + assert worker.check_required_types( + corpus_id, "page", "text_line", "act", create_missing=True + ) + + def test_list_elements_elements_list_arg_wrong_type( monkeypatch, tmp_path, mock_elements_worker ): -- GitLab