From ef25e5b7457116456ab5d3479f637657f5718155 Mon Sep 17 00:00:00 2001 From: Dave Walker Date: Thu, 31 Oct 2024 06:22:00 +0000 Subject: [PATCH] Fixup 'S casing and species addition bug --- docker/Dockerfile | 4 +-- setup.py | 2 +- src/naturerec_model/logic/categories.py | 6 ++-- src/naturerec_model/logic/naming.py | 30 +++++++++++++++++++ src/naturerec_model/logic/species.py | 9 +++--- .../species/species_blueprint.py | 2 +- .../test_sightings_export_helper.py | 2 +- .../test_sightings_import_helper.py | 2 +- tests/naturerec_model/logic/test_species.py | 10 +++---- .../logic/test_species_status_ratings.py | 2 +- tests/naturerec_model/model/test_sighting.py | 4 +-- tests/naturerec_model/model/test_species.py | 4 +-- 12 files changed, 54 insertions(+), 23 deletions(-) create mode 100644 src/naturerec_model/logic/naming.py diff --git a/docker/Dockerfile b/docker/Dockerfile index 519a51c..311e349 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,12 +1,12 @@ FROM python:3.10-slim-bullseye AS runtime -COPY naturerecorderpy-1.9.0.0 /opt/naturerecorderpy +COPY naturerecorderpy-1.10.0.0 /opt/naturerecorderpy WORKDIR /opt/naturerecorderpy RUN apt-get update -y RUN pip install -r requirements.txt -RUN pip install nature_recorder-1.9.0-py3-none-any.whl +RUN pip install nature_recorder-1.10.0-py3-none-any.whl ENV NATURE_RECORDER_DATA_FOLDER=/var/opt/naturerecorderpy ENV NATURE_RECORDER_DB=/var/opt/naturerecorderpy/naturerecorder.db diff --git a/setup.py b/setup.py index 87a22fe..381fb6d 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ def find_package_files(directory, remove_root): setuptools.setup( name="nature_recorder", - version="1.9.0", + version="1.10.0", description="Wildlife sightings database", packages=setuptools.find_packages("src"), include_package_data=True, diff --git a/src/naturerec_model/logic/categories.py b/src/naturerec_model/logic/categories.py index c3ab8b7..0369d2e 100644 --- a/src/naturerec_model/logic/categories.py +++ b/src/naturerec_model/logic/categories.py @@ -7,7 +7,7 @@ from datetime import datetime as dt from sqlalchemy.exc import IntegrityError, NoResultFound from ..model import Session, Category, Species - +from .naming import tidy_string, Casing def _check_for_existing_records(session, name): """ @@ -36,7 +36,7 @@ def create_category(name, user): with Session.begin() as session: # There is a check constraint to prevent duplicates in the Python model but the pre-existing database # does not have that constraint so explicitly check for duplicates before adding a new record - tidied = " ".join(name.split()).title() if name else None + tidied = tidy_string(name, Casing.TITLE_CASE) if len(_check_for_existing_records(session, tidied)): raise ValueError("Duplicate category found") @@ -68,7 +68,7 @@ def update_category(category_id, name, user): with Session.begin() as session: # There is a check constraint to prevent duplicates in the Python model but the pre-existing database # does not have that constraint so explicitly check for duplicates before adding a new record - tidied = " ".join(name.split()).title() if name else None + tidied = tidy_string(name, Casing.TITLE_CASE) category_ids = _check_for_existing_records(session, tidied) # Remove the current category from the list, if it's there diff --git a/src/naturerec_model/logic/naming.py b/src/naturerec_model/logic/naming.py new file mode 100644 index 0000000..5a53006 --- /dev/null +++ b/src/naturerec_model/logic/naming.py @@ -0,0 +1,30 @@ +""" +Species and category common and scientific naming logic +""" + +class Casing: + TITLE_CASE = "title_case" + CAPITALISED = "capitalised" + + +def tidy_string(text, required_case): + """ + Tidy the case of the specified string and remove duplicate spaces + + :param name: Text string to tidy + :param required_case: Required casing + :returns: Tidied text string + """ + + tidied_text = None + + if text: + match required_case: + case Casing.TITLE_CASE: + tidied_text = " ".join(text.split()).title().replace("'S", "'s") + case Casing.CAPITALISED: + tidied_text = " ".join(text.split()).capitalize() + case _: + tidied_text = text + + return tidied_text diff --git a/src/naturerec_model/logic/species.py b/src/naturerec_model/logic/species.py index b0c119e..6629b74 100644 --- a/src/naturerec_model/logic/species.py +++ b/src/naturerec_model/logic/species.py @@ -7,6 +7,7 @@ from datetime import datetime as dt from sqlalchemy.exc import IntegrityError, NoResultFound from ..model import Session, Species, Sighting, SpeciesStatusRating +from .naming import tidy_string, Casing def _check_for_existing_records(session, category_id, name): @@ -41,8 +42,8 @@ def create_species(category_id, name, scientific_name, user): with Session.begin() as session: # There is a check constraint to prevent duplicates in the Python model but the pre-existing database # does not have that constraint so explicitly check for duplicates before adding a new record - tidied_name = " ".join(name.split()).title() if name else None - tidied_scientific_name = " ".join(scientific_name.split()).title() if scientific_name else None + tidied_name = tidy_string(name, Casing.TITLE_CASE) + tidied_scientific_name = tidy_string(scientific_name, Casing.CAPITALISED) if len(_check_for_existing_records(session, category_id, tidied_name)): raise ValueError("Duplicate category found") @@ -77,8 +78,8 @@ def update_species(species_id, category_id, name, scientific_name, user): with Session.begin() as session: # There is a check constraint to prevent duplicates in the Python model but the pre-existing database # does not have that constraint so explicitly check for duplicates before adding a new record - tidied_name = " ".join(name.split()).title() if name else None - tidied_scientific_name = " ".join(scientific_name.split()).title() if scientific_name else None + tidied_name = tidy_string(name, Casing.TITLE_CASE) + tidied_scientific_name = tidy_string(scientific_name, Casing.CAPITALISED) species_ids = _check_for_existing_records(session, category_id, tidied_name) # Remove the current category from the list, if it's there diff --git a/src/naturerec_web/species/species_blueprint.py b/src/naturerec_web/species/species_blueprint.py index 8a5e4b4..05857d7 100644 --- a/src/naturerec_web/species/species_blueprint.py +++ b/src/naturerec_web/species/species_blueprint.py @@ -89,7 +89,7 @@ def edit(species_id): if species_id: _ = update_species(species_id, get_posted_int("category"), request.form["name"], request.form["scientific_name"], current_user) else: - _ = create_species(get_posted_int("category"), request.form["name"], current_user) + _ = create_species(get_posted_int("category"), request.form["name"], request.form["scientific_name"], current_user) return redirect("/species/list") except ValueError as e: return _render_species_editing_page(species_id, e) diff --git a/tests/naturerec_model/data_exchange/test_sightings_export_helper.py b/tests/naturerec_model/data_exchange/test_sightings_export_helper.py index 4c39c1e..9b276e5 100644 --- a/tests/naturerec_model/data_exchange/test_sightings_export_helper.py +++ b/tests/naturerec_model/data_exchange/test_sightings_export_helper.py @@ -38,7 +38,7 @@ def test_can_export_sightings(self): self.assertEqual(SightingsExportHelper.COLUMN_NAMES, rows[0]) self.assertEqual(16, len(rows[1])) self.assertEqual("Black-Headed Gull", rows[1][0]) - self.assertEqual("Chroicocephalus Ridibundus", rows[1][1]) + self.assertEqual("Chroicocephalus ridibundus", rows[1][1]) self.assertEqual("Birds", rows[1][2]) self.assertEqual("", rows[1][3]) self.assertEqual("Unknown", rows[1][4]) diff --git a/tests/naturerec_model/data_exchange/test_sightings_import_helper.py b/tests/naturerec_model/data_exchange/test_sightings_import_helper.py index 487f930..4fe00bb 100644 --- a/tests/naturerec_model/data_exchange/test_sightings_import_helper.py +++ b/tests/naturerec_model/data_exchange/test_sightings_import_helper.py @@ -53,7 +53,7 @@ def _perform_valid_import(self): category = get_category("Birds") self.assertEqual(1, len(category.species)) self.assertEqual("Robin", category.species[0].name) - self.assertEqual("Erithacus Rubecula", category.species[0].scientific_name) + self.assertEqual("Erithacus rubecula", category.species[0].scientific_name) # Check the location was imported correctly location = get_location("Abingdon") diff --git a/tests/naturerec_model/logic/test_species.py b/tests/naturerec_model/logic/test_species.py index 82feb9e..9863419 100644 --- a/tests/naturerec_model/logic/test_species.py +++ b/tests/naturerec_model/logic/test_species.py @@ -20,12 +20,12 @@ def test_can_create_species(self): species = session.query(Species).one() self.assertTrue(category.id, species.categoryId) self.assertEqual("Red Kite", species.name) - self.assertEqual("Milvus Milvus", species.scientific_name) + self.assertEqual("Milvus milvus", species.scientific_name) def test_cannot_create_duplicate_species(self): with self.assertRaises(ValueError), Session.begin() as session: category_id = session.query(Species).one().categoryId - _ = create_species(category_id, "Red Kite", "Milvus Milvus", self._user) + _ = create_species(category_id, "Red Kite", "Milvus milvus", self._user) def test_can_update_species(self): category_id = create_category("Insects", self._user).id @@ -35,13 +35,13 @@ def test_can_update_species(self): species = get_species(species_id) self.assertEqual("Insects", species.category.name) self.assertEqual("Azure Damselfly", species.name) - self.assertEqual("Coenagrion Puella", species.scientific_name) + self.assertEqual("Coenagrion puella", species.scientific_name) def test_cannot_update_species_to_create_duplicate(self): category = get_category("Birds") species = create_species(category.id, "Robin", "Erithacus rubecula", self._user) with self.assertRaises(ValueError): - _ = update_species(species.id, category.id, "Red Kite", "Milvus Milvus", self._user) + _ = update_species(species.id, category.id, "Red Kite", "Milvus milvus", self._user) def test_cannot_update_missing_species(self): category = get_category("Birds") @@ -98,7 +98,7 @@ def test_can_list_species(self): species = list_species(category_id) self.assertEqual(1, len(species)) self.assertEqual("Red Kite", species[0].name) - self.assertEqual("Milvus Milvus", species[0].scientific_name) + self.assertEqual("Milvus milvus", species[0].scientific_name) def test_can_delete_species(self): category_id = get_category("Birds").id diff --git a/tests/naturerec_model/logic/test_species_status_ratings.py b/tests/naturerec_model/logic/test_species_status_ratings.py index 851ac2a..131fc40 100644 --- a/tests/naturerec_model/logic/test_species_status_ratings.py +++ b/tests/naturerec_model/logic/test_species_status_ratings.py @@ -109,7 +109,7 @@ def test_can_list_filter_ratings_by_species(self): ratings = list_species_status_ratings(species_id=species.id) self.assertEqual(1, len(ratings)) # Python title casing's a bit interesting! - self.assertEqual("Bewick'S Swan", ratings[0].species.name) + self.assertEqual("Bewick's Swan", ratings[0].species.name) self.assertEqual("BOCC4", ratings[0].rating.scheme.name) self.assertEqual("Amber", ratings[0].rating.name) self.assertEqual("United Kingdom", ratings[0].region) diff --git a/tests/naturerec_model/model/test_sighting.py b/tests/naturerec_model/model/test_sighting.py index df8451f..365e48d 100644 --- a/tests/naturerec_model/model/test_sighting.py +++ b/tests/naturerec_model/model/test_sighting.py @@ -12,7 +12,7 @@ def setUp(self) -> None: create_database() self._user = User(id=1) self._category = create_category("Birds", self._user) - self._gull = create_species(self._category.id, "Black-Headed Gull", "Chroicocephalus Ridibundus", self._user) + self._gull = create_species(self._category.id, "Black-Headed Gull", "Chroicocephalus ridibundus", self._user) self._cormorant = create_species(self._category.id, "Cormorant", None, self._user) self._location = create_location(name="Radley Lakes", county="Oxfordshire", country="United Kingdom", user=self._user) _ = create_sighting(self._location.id, self._gull.id, datetime.date(2021, 12, 14), None, Gender.UNKNOWN, False, @@ -101,7 +101,7 @@ def test_can_get_csv_columns(self): columns = session.query(Sighting).one().csv_columns self.assertEqual(16, len(columns)) self.assertEqual("Black-Headed Gull", columns[0]) - self.assertEqual("Chroicocephalus Ridibundus", columns[1]) + self.assertEqual("Chroicocephalus ridibundus", columns[1]) self.assertEqual("Birds", columns[2]) self.assertIsNone(columns[3]) self.assertEqual("Unknown", columns[4]) diff --git a/tests/naturerec_model/model/test_species.py b/tests/naturerec_model/model/test_species.py index 4e6fbc8..b32c351 100644 --- a/tests/naturerec_model/model/test_species.py +++ b/tests/naturerec_model/model/test_species.py @@ -9,13 +9,13 @@ def setUp(self) -> None: create_database() self._user = User(id=1) category = create_category("Birds", self._user) - _ = create_species(category.id, "Red Kite", "Milvus Milvus", self._user) + _ = create_species(category.id, "Red Kite", "Milvus milvus", self._user) def test_can_create_species(self): with Session.begin() as session: species = session.query(Species).one() self.assertEqual("Red Kite", species.name) - self.assertEqual("Milvus Milvus", species.scientific_name) + self.assertEqual("Milvus milvus", species.scientific_name) self.assertEqual("Birds", species.category.name) def test_cannot_create_species_against_missing_category(self):