diff --git a/src/euring/fields.py b/src/euring/fields.py index 2458586..988e82e 100644 --- a/src/euring/fields.py +++ b/src/euring/fields.py @@ -1,5 +1,7 @@ from __future__ import annotations +from types import MappingProxyType + from .codes import ( LOOKUP_ACCURACY_OF_COORDINATES, LOOKUP_ACCURACY_OF_DATE, @@ -59,7 +61,7 @@ # Schema list (definitions), not per-record data. -EURING_FIELDS = [ +EURING_FIELDS = ( EuringLookupField( name="Ringing Scheme", key="ringing_scheme", @@ -416,20 +418,24 @@ lookup=lookup_place_code, ), EuringField(name="More Other Marks", key="more_other_marks", euring_type=TYPE_ALPHABETIC, required=False), -] - -# All keys -EURING_KEYS = [field.key for field in EURING_FIELDS] - -# Map keys to index -EURING_KEY_INDEX = {key: index for index, key in enumerate(EURING_KEYS)} +) -# Fields per format (as per the EURING Code Manual) +# These are the field definitions per format as per the EURING Code Manual EURING2020_FIELDS = EURING_FIELDS # 64 fields EURING2000PLUS_FIELDS = EURING_FIELDS[:60] EURING2000_FIELDS = EURING_FIELDS[:33] -# Keys per format -EURING2020_KEYS = [field.key for field in EURING2020_FIELDS] -EURING2000PLUS_KEYS = [field.key for field in EURING2000PLUS_FIELDS] -EURING2000_KEYS = [field.key for field in EURING2000_FIELDS] +# All keys and keys per format +EURING_KEYS = tuple(field.key for field in EURING_FIELDS) +EURING2020_KEYS = tuple(field.key for field in EURING2020_FIELDS) +EURING2000PLUS_KEYS = tuple(field.key for field in EURING2000PLUS_FIELDS) +EURING2000_KEYS = tuple(field.key for field in EURING2000_FIELDS) + +# Mapping keys to indexes and names +EURING_KEY_INDEX = MappingProxyType({key: index for index, key in enumerate(EURING_KEYS)}) +EURING_KEY_NAME = MappingProxyType({field.key: field.name for field in EURING_FIELDS}) + +# Helpers +EURING2020_ONLY_KEYS = tuple(set(EURING2020_KEYS).difference(EURING2000PLUS_KEYS)) +NON_EURING2000_KEYS = tuple(set(EURING2000PLUS_KEYS + EURING2020_ONLY_KEYS).difference(EURING2000_KEYS)) +NON_EURING2000PLUS_KEYS = tuple(key for key in EURING_KEYS if key not in EURING2000PLUS_KEYS) diff --git a/src/euring/rules.py b/src/euring/rules.py index 9489dcb..845ba8c 100644 --- a/src/euring/rules.py +++ b/src/euring/rules.py @@ -2,17 +2,15 @@ from __future__ import annotations -from .fields import EURING2000_FIELDS, EURING2000PLUS_FIELDS, EURING2020_FIELDS, EURING_FIELDS +from .fields import ( + EURING2020_ONLY_KEYS, + EURING_FIELDS, + NON_EURING2000_KEYS, +) from .formats import FORMAT_EURING2000, FORMAT_EURING2000PLUS, FORMAT_EURING2020 _FIELD_NAME_BY_KEY = {field["key"]: field["name"] for field in EURING_FIELDS} -EURING2000_KEYS = tuple(field["key"] for field in EURING2000_FIELDS) -EURING2000PLUS_KEYS = tuple(field["key"] for field in EURING2000PLUS_FIELDS) -EURING2020_KEYS = tuple(field["key"] for field in EURING2020_FIELDS) -EURING2020_ONLY_KEYS = tuple(set(EURING2020_KEYS).difference(EURING2000PLUS_KEYS)) -NON_EURING2000_KEYS = tuple(set(EURING2000PLUS_KEYS + EURING2020_ONLY_KEYS).difference(EURING2000_KEYS)) - def field_name_for_key(key: str) -> str: """Return the field name for a key, falling back to the key.""" diff --git a/tests/fixtures/__init__.py b/tests/fixtures/__init__.py index b8d4196..db8adad 100644 --- a/tests/fixtures/__init__.py +++ b/tests/fixtures/__init__.py @@ -7,7 +7,7 @@ ) from euring.formats import FORMAT_EURING2000, FORMAT_EURING2000PLUS, FORMAT_EURING2020 -DEFAULT_TEST_VALUES = { +EURING_TEST_DATA = { # Default test data for a EURING record in key-value format "ringing_scheme": "GBB", "primary_identification_method": "A0", @@ -33,7 +33,7 @@ "accuracy_of_date": "0", "time": "0000", "place_code": "AB00", - "geographical_coordinates": "+0000000+0000000", + "geographical_coordinates": "+000000+0000000", "accuracy_of_coordinates": "1", "condition": "9", "circumstances": "99", @@ -77,24 +77,31 @@ "more_other_marks": "", } +EURING2000_TEST_DATA = {key: value for key, value in EURING_TEST_DATA.items() if key in EURING2000_KEYS} +EURING2000PLUS_TEST_DATA = {key: value for key, value in EURING_TEST_DATA.items() if key in EURING2000PLUS_KEYS} +EURING2020_TEST_DATA = {key: value for key, value in EURING_TEST_DATA.items() if key in EURING2020_KEYS} + def _make_euring_record(data: dict, format: str) -> str: + record = dict() if format == FORMAT_EURING2000: keys = EURING2000_KEYS + record.update(EURING2000_TEST_DATA) separator = "" elif format == FORMAT_EURING2000PLUS: keys = EURING2000PLUS_KEYS + record.update(EURING2000PLUS_TEST_DATA) separator = "|" elif format == FORMAT_EURING2020: keys = EURING2020_KEYS + record.update(EURING2020_TEST_DATA) separator = "|" else: raise ValueError(f"Unknown format: {format}") - record_dict = {key: value for key, value in DEFAULT_TEST_VALUES.items() if key in keys} for key, value in data.items(): assert key in keys, f"Invalid key: {key}" - record_dict[key] = value - return separator.join(record_dict.values()) + record[key] = value + return separator.join(record.get(key, "") for key in keys) def _make_euring2000_record(**kwargs) -> str: diff --git a/tests/test_rules.py b/tests/test_rules.py index 3c74f6c..089a0a7 100644 --- a/tests/test_rules.py +++ b/tests/test_rules.py @@ -1,11 +1,13 @@ """Tests for record_rules helpers.""" -from euring.rules import ( +from euring.fields import ( EURING2000_KEYS, EURING2000PLUS_KEYS, EURING2020_KEYS, EURING2020_ONLY_KEYS, NON_EURING2000_KEYS, +) +from euring.rules import ( matches_euring2000, record_rule_errors, requires_euring2000plus,