Skip to content

Commit a6d356a

Browse files
authored
Refactor fields and rules to use immutables (#115)
1 parent af6844c commit a6d356a

File tree

4 files changed

+39
-26
lines changed

4 files changed

+39
-26
lines changed

src/euring/fields.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import annotations
22

3+
from types import MappingProxyType
4+
35
from .codes import (
46
LOOKUP_ACCURACY_OF_COORDINATES,
57
LOOKUP_ACCURACY_OF_DATE,
@@ -59,7 +61,7 @@
5961

6062
# Schema list (definitions), not per-record data.
6163

62-
EURING_FIELDS = [
64+
EURING_FIELDS = (
6365
EuringLookupField(
6466
name="Ringing Scheme",
6567
key="ringing_scheme",
@@ -416,20 +418,24 @@
416418
lookup=lookup_place_code,
417419
),
418420
EuringField(name="More Other Marks", key="more_other_marks", euring_type=TYPE_ALPHABETIC, required=False),
419-
]
420-
421-
# All keys
422-
EURING_KEYS = [field.key for field in EURING_FIELDS]
423-
424-
# Map keys to index
425-
EURING_KEY_INDEX = {key: index for index, key in enumerate(EURING_KEYS)}
421+
)
426422

427-
# Fields per format (as per the EURING Code Manual)
423+
# These are the field definitions per format as per the EURING Code Manual
428424
EURING2020_FIELDS = EURING_FIELDS # 64 fields
429425
EURING2000PLUS_FIELDS = EURING_FIELDS[:60]
430426
EURING2000_FIELDS = EURING_FIELDS[:33]
431427

432-
# Keys per format
433-
EURING2020_KEYS = [field.key for field in EURING2020_FIELDS]
434-
EURING2000PLUS_KEYS = [field.key for field in EURING2000PLUS_FIELDS]
435-
EURING2000_KEYS = [field.key for field in EURING2000_FIELDS]
428+
# All keys and keys per format
429+
EURING_KEYS = tuple(field.key for field in EURING_FIELDS)
430+
EURING2020_KEYS = tuple(field.key for field in EURING2020_FIELDS)
431+
EURING2000PLUS_KEYS = tuple(field.key for field in EURING2000PLUS_FIELDS)
432+
EURING2000_KEYS = tuple(field.key for field in EURING2000_FIELDS)
433+
434+
# Mapping keys to indexes and names
435+
EURING_KEY_INDEX = MappingProxyType({key: index for index, key in enumerate(EURING_KEYS)})
436+
EURING_KEY_NAME = MappingProxyType({field.key: field.name for field in EURING_FIELDS})
437+
438+
# Helpers
439+
EURING2020_ONLY_KEYS = tuple(set(EURING2020_KEYS).difference(EURING2000PLUS_KEYS))
440+
NON_EURING2000_KEYS = tuple(set(EURING2000PLUS_KEYS + EURING2020_ONLY_KEYS).difference(EURING2000_KEYS))
441+
NON_EURING2000PLUS_KEYS = tuple(key for key in EURING_KEYS if key not in EURING2000PLUS_KEYS)

src/euring/rules.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,15 @@
22

33
from __future__ import annotations
44

5-
from .fields import EURING2000_FIELDS, EURING2000PLUS_FIELDS, EURING2020_FIELDS, EURING_FIELDS
5+
from .fields import (
6+
EURING2020_ONLY_KEYS,
7+
EURING_FIELDS,
8+
NON_EURING2000_KEYS,
9+
)
610
from .formats import FORMAT_EURING2000, FORMAT_EURING2000PLUS, FORMAT_EURING2020
711

812
_FIELD_NAME_BY_KEY = {field["key"]: field["name"] for field in EURING_FIELDS}
913

10-
EURING2000_KEYS = tuple(field["key"] for field in EURING2000_FIELDS)
11-
EURING2000PLUS_KEYS = tuple(field["key"] for field in EURING2000PLUS_FIELDS)
12-
EURING2020_KEYS = tuple(field["key"] for field in EURING2020_FIELDS)
13-
EURING2020_ONLY_KEYS = tuple(set(EURING2020_KEYS).difference(EURING2000PLUS_KEYS))
14-
NON_EURING2000_KEYS = tuple(set(EURING2000PLUS_KEYS + EURING2020_ONLY_KEYS).difference(EURING2000_KEYS))
15-
1614

1715
def field_name_for_key(key: str) -> str:
1816
"""Return the field name for a key, falling back to the key."""

tests/fixtures/__init__.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
)
88
from euring.formats import FORMAT_EURING2000, FORMAT_EURING2000PLUS, FORMAT_EURING2020
99

10-
DEFAULT_TEST_VALUES = {
10+
EURING_TEST_DATA = {
1111
# Default test data for a EURING record in key-value format
1212
"ringing_scheme": "GBB",
1313
"primary_identification_method": "A0",
@@ -33,7 +33,7 @@
3333
"accuracy_of_date": "0",
3434
"time": "0000",
3535
"place_code": "AB00",
36-
"geographical_coordinates": "+0000000+0000000",
36+
"geographical_coordinates": "+000000+0000000",
3737
"accuracy_of_coordinates": "1",
3838
"condition": "9",
3939
"circumstances": "99",
@@ -77,24 +77,31 @@
7777
"more_other_marks": "",
7878
}
7979

80+
EURING2000_TEST_DATA = {key: value for key, value in EURING_TEST_DATA.items() if key in EURING2000_KEYS}
81+
EURING2000PLUS_TEST_DATA = {key: value for key, value in EURING_TEST_DATA.items() if key in EURING2000PLUS_KEYS}
82+
EURING2020_TEST_DATA = {key: value for key, value in EURING_TEST_DATA.items() if key in EURING2020_KEYS}
83+
8084

8185
def _make_euring_record(data: dict, format: str) -> str:
86+
record = dict()
8287
if format == FORMAT_EURING2000:
8388
keys = EURING2000_KEYS
89+
record.update(EURING2000_TEST_DATA)
8490
separator = ""
8591
elif format == FORMAT_EURING2000PLUS:
8692
keys = EURING2000PLUS_KEYS
93+
record.update(EURING2000PLUS_TEST_DATA)
8794
separator = "|"
8895
elif format == FORMAT_EURING2020:
8996
keys = EURING2020_KEYS
97+
record.update(EURING2020_TEST_DATA)
9098
separator = "|"
9199
else:
92100
raise ValueError(f"Unknown format: {format}")
93-
record_dict = {key: value for key, value in DEFAULT_TEST_VALUES.items() if key in keys}
94101
for key, value in data.items():
95102
assert key in keys, f"Invalid key: {key}"
96-
record_dict[key] = value
97-
return separator.join(record_dict.values())
103+
record[key] = value
104+
return separator.join(record.get(key, "") for key in keys)
98105

99106

100107
def _make_euring2000_record(**kwargs) -> str:

tests/test_rules.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
"""Tests for record_rules helpers."""
22

3-
from euring.rules import (
3+
from euring.fields import (
44
EURING2000_KEYS,
55
EURING2000PLUS_KEYS,
66
EURING2020_KEYS,
77
EURING2020_ONLY_KEYS,
88
NON_EURING2000_KEYS,
9+
)
10+
from euring.rules import (
911
matches_euring2000,
1012
record_rule_errors,
1113
requires_euring2000plus,

0 commit comments

Comments
 (0)