From bf6ecf378a365f39ea144343d71010663cb7db85 Mon Sep 17 00:00:00 2001 From: Dylan Verheul Date: Sat, 24 Jan 2026 10:26:01 +0100 Subject: [PATCH 1/2] Add stricter Place Code validation --- src/euring/codes.py | 12 ++++++++++++ src/euring/fields.py | 13 ++++++++++--- tests/test_decoding.py | 11 +++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/euring/codes.py b/src/euring/codes.py index fa57eac..548b40b 100644 --- a/src/euring/codes.py +++ b/src/euring/codes.py @@ -1,3 +1,4 @@ +import re from collections.abc import Callable, Mapping from datetime import date from typing import Any @@ -200,6 +201,17 @@ def parse_direction(value: str) -> int | None: return parsed +_PLACE_CODE_RE = re.compile(r"^[A-Z]{2}([A-Z]{2}|[0-9]{2}|--)$") + + +def parse_place_code(value: str) -> str: + """Validate the place code pattern (AA##, AAAA, or AA--).""" + value_str = f"{value}" + if not _PLACE_CODE_RE.match(value_str): + raise EuringConstraintException(f'Value "{value}" is not a valid place code format.') + return value_str + + def _parse_decimal_coordinate(value: str, *, max_abs: int, max_decimals: int, field_name: str) -> float: """Parse and validate a decimal latitude/longitude string.""" try: diff --git a/src/euring/fields.py b/src/euring/fields.py index 583acc5..a8cb96d 100644 --- a/src/euring/fields.py +++ b/src/euring/fields.py @@ -42,6 +42,7 @@ parse_latitude, parse_longitude, parse_old_greater_coverts, + parse_place_code, ) from .field_schema import EuringField, EuringFormattedField, EuringLookupField from .types import ( @@ -173,8 +174,13 @@ lookup=LOOKUP_ACCURACY_OF_DATE, ), EuringField(name="Time", key="time", type_name=TYPE_ALPHANUMERIC, length=4), - EuringLookupField( - name="Place Code", key="place_code", type_name=TYPE_ALPHANUMERIC, length=4, lookup=lookup_place_code + EuringFormattedField( + name="Place Code", + key="place_code", + type_name=TYPE_ALPHANUMERIC, + length=4, + parser=parse_place_code, + lookup=lookup_place_code, ), EuringFormattedField( name="Geographical Co-ordinates", @@ -337,12 +343,13 @@ required=False, parser=parse_longitude, ), - EuringLookupField( + EuringFormattedField( name="Current Place Code", key="current_place_code", type_name=TYPE_ALPHANUMERIC, length=4, required=False, + parser=parse_place_code, lookup=lookup_place_code, ), EuringField(name="More Other Marks", key="more_other_marks", type_name=TYPE_ALPHABETIC, required=False), diff --git a/tests/test_decoding.py b/tests/test_decoding.py index 3a09f2b..ee04a7b 100644 --- a/tests/test_decoding.py +++ b/tests/test_decoding.py @@ -9,6 +9,7 @@ parse_direction, parse_geographical_coordinates, parse_old_greater_coverts, + parse_place_code, ) from euring.exceptions import EuringConstraintException, EuringTypeException from euring.fields import EURING_FIELDS @@ -180,6 +181,16 @@ def test_parse_direction_allows_hyphens(self): assert parse_direction("---") is None assert parse_direction("-") is None + def test_parse_place_code_allows_country_unknown_subdivision(self): + assert parse_place_code("NL--") == "NL--" + + def test_parse_place_code_allows_numeric_subdivision(self): + assert parse_place_code("ES00") == "ES00" + + def test_parse_place_code_rejects_invalid_pattern(self): + with pytest.raises(EuringConstraintException): + parse_place_code("N1--") + def test_parse_direction_rejects_out_of_range(self): with pytest.raises(EuringConstraintException): parse_direction("360") From 9da1b0edf5678db5a087f6338d4f88277b64d0ab Mon Sep 17 00:00:00 2001 From: Dylan Verheul Date: Sat, 24 Jan 2026 10:26:30 +0100 Subject: [PATCH 2/2] CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 901f888..d1cfb5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- Add stricter Place Code validation (#99). - Parse raw values to values for all fields (#98). - Add constraints and tests for Direction (#97). - Improve support for Distance, Direction and Elapsed Time (#96).