Skip to content
This repository was archived by the owner on Dec 26, 2025. It is now read-only.

Commit b5323d1

Browse files
committed
Better exception text on ADX validation and option to return list instead of raise exception
1 parent f1711bd commit b5323d1

2 files changed

Lines changed: 56 additions & 15 deletions

File tree

src/adif_file/adx.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,15 @@ def load(file_name: str, validate: bool = False) -> dict:
8181
return loads(adx_data, validate)
8282

8383

84-
def dump(file_name: str, data_dict: dict):
84+
def dump(file_name: str, data_dict: dict, raise_exc=True) -> list[Exception]:
8585
"""Takes a dictionary and stores it to ADX xml file
8686
If 'HEADER' is missing the header fields are filled with defaults.
8787
The XML is validated against the strict XSD
8888
8989
:param file_name: the filename to store the ADX data to
9090
:param data_dict: the dictionary with header and records
91+
:param raise_exc: if the validation exceptions are to be raised immediately
92+
:return: list of validation exception (if not raised immediately)
9193
"""
9294

9395
data_dict = data_dict.copy()
@@ -112,13 +114,23 @@ def dump(file_name: str, data_dict: dict):
112114
rec = data_dict.pop('RECORDS')
113115
data_dict['RECORDS'] = {'RECORD': rec}
114116

115-
try:
116-
et = ADX_EXPORT_SCHEMA.encode(data_dict)
117-
ElementTree(et).write(file_name, xml_declaration=True, encoding='utf-8')
118-
except xmlschema.validators.exceptions.XMLSchemaChildrenValidationError as exc:
119-
raise UndefinedElementException(f'in {exc.elem.tag}') from None
120-
except xmlschema.validators.exceptions.XMLSchemaValidationError as exc:
121-
raise MalformedValueException(f'Field "{exc.elem.tag}": {exc.reason}') from None
117+
exc = []
118+
119+
et, errors = ADX_EXPORT_SCHEMA.encode(data_dict, validation='lax')
120+
for err in errors:
121+
if type(err) is xmlschema.validators.exceptions.XMLSchemaValidationError:
122+
if err.elem.tag == 'RECORD':
123+
exc.append(UndefinedElementException(f'{err.path}: {err.reason}'))
124+
elif err.elem.tag == 'HEADER':
125+
exc.append(UndefinedElementException(f'{err.path}: {err.reason}'))
126+
else:
127+
exc.append(MalformedValueException(f'{err.path}: value "{err.obj}" {err.reason}'))
128+
129+
if raise_exc and exc:
130+
raise exc[0]
131+
132+
ElementTree(et).write(file_name, xml_declaration=True, encoding='utf-8')
133+
return exc
122134

123135

124136
__all__ = ['load', 'loads', 'dump', 'MissingRecordsException', 'UndefinedElementException',

test/test_dumpadx.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import copy
23
import unittest
34

45
import adif_file.adx
@@ -19,21 +20,49 @@ def test_10_dump_exceptions(self):
1920

2021
self.assertRaises(adif_file.adx.MissingRecordsException, adif_file.adx.dump, '', {})
2122

22-
adx_dict2 = adx_dict.copy()
23+
adx_dict2 = copy.deepcopy(adx_dict)
2324
adx_dict2['RECORDS'][0]['MY_QTH'] = 'Test' # MY_QTH is not allowed (MY_CITY)
2425
self.assertRaises(adif_file.adx.UndefinedElementException, adif_file.adx.dump, '', adx_dict2)
2526

26-
adx_dict2 = adx_dict.copy()
27-
adx_dict2['RECORDS'][0]['MY_CITY'] = 123
27+
adx_dict2 = copy.deepcopy(adx_dict)
28+
adx_dict2['RECORDS'][0]['QTH'] = 'Töst' # QTH only allows ASCII chars < 127
2829
self.assertRaises(adif_file.adx.MalformedValueException, adif_file.adx.dump, '', adx_dict2)
2930

30-
adx_dict2 = adx_dict.copy()
31-
adx_dict2['RECORDS'][0]['QTH'] = 'Töst' # QTH ony alows ASCII chars < 127
31+
adx_dict2 = copy.deepcopy(adx_dict)
32+
adx_dict2['RECORDS'][0]['FREQ'] = 'Test'
3233
self.assertRaises(adif_file.adx.MalformedValueException, adif_file.adx.dump, '', adx_dict2)
3334

34-
adx_dict2 = adx_dict.copy()
35+
def test_15_dump_retexc(self):
36+
adx_dict = {
37+
'RECORDS': [{'CALL': 'XX1XXX',
38+
'QSO_DATE': '20231204',
39+
'TIME_ON': '1100',
40+
'QTH': 'Test'}]
41+
}
42+
43+
# Still raises non validation exceptions?
44+
self.assertRaises(adif_file.adx.MissingRecordsException, adif_file.adx.dump, '', {}, raise_exc=False)
45+
46+
temp_file = get_file_path('testdata/~test.adx')
47+
48+
self.assertListEqual([], adif_file.adx.dump(temp_file, adx_dict, raise_exc=False))
49+
50+
adx_dict2 = copy.deepcopy(adx_dict)
51+
adx_dict2['RECORDS'][0]['MY_QTH'] = 'Test' # MY_QTH is not allowed (MY_CITY)
52+
self.assertEqual(adif_file.adx.UndefinedElementException,
53+
type(adif_file.adx.dump(temp_file, adx_dict2, raise_exc=False)[0]))
54+
55+
adx_dict2 = copy.deepcopy(adx_dict)
56+
adx_dict2['RECORDS'][0]['QTH'] = 'Töst' # QTH only allows ASCII chars < 127
57+
self.assertEqual(adif_file.adx.MalformedValueException,
58+
type(adif_file.adx.dump(temp_file, adx_dict2, raise_exc=False)[0]))
59+
60+
adx_dict2 = copy.deepcopy(adx_dict)
3561
adx_dict2['RECORDS'][0]['FREQ'] = 'Test'
36-
self.assertRaises(adif_file.adx.MalformedValueException, adif_file.adx.dump, '', adx_dict2)
62+
self.assertEqual(adif_file.adx.MalformedValueException,
63+
type(adif_file.adx.dump(temp_file, adx_dict2, raise_exc=False)[0]))
64+
65+
os.remove(temp_file)
3766

3867
def test_20_dump(self):
3968
adx_dict = {

0 commit comments

Comments
 (0)