summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElena ``of Valhalla'' Grandi <valhalla@trueelena.org>2020-10-03 16:27:42 +0200
committerElena ``of Valhalla'' Grandi <valhalla@trueelena.org>2020-10-03 16:27:42 +0200
commitb445258f28708bf5c709e3db7dc2c0363b41a99f (patch)
tree3efb70f2f6c24da86c2d925d6d02651574acf7c5
parent8a79adda4b254dca7bc10122e6f3e809a64a8c90 (diff)
Load one type checker per field
-rw-r--r--lesana/collection.py48
-rw-r--r--lesana/types.py11
-rw-r--r--tests/data/wrong/settings.yaml3
-rw-r--r--tests/test_collection.py24
4 files changed, 64 insertions, 22 deletions
diff --git a/lesana/collection.py b/lesana/collection.py
index 4b3e964..5b7b809 100644
--- a/lesana/collection.py
+++ b/lesana/collection.py
@@ -92,22 +92,15 @@ class Entry(object):
def validate(self):
errors = []
valid = True
- for field in self.collection.settings['fields']:
- value = self.data.get(field['name'], None)
- t = field['type']
+ for name, field in self.collection.fields.items():
+ value = self.data.get(name, None)
+ t = field.name
try:
- self.data[field['name']] = self.collection.types[t].load(value)
- except KeyError:
- errors.append(
- {
- 'field': field['name'],
- 'error': "No such type {}".format(t),
- }
- )
+ self.data[name] = field.load(value)
except types.LesanaValueError as e:
errors.append(
{
- 'field': field['name'],
+ 'field': name,
'error': e,
}
)
@@ -120,7 +113,7 @@ class Entry(object):
valid = False
errors.append(
{
- 'field': field['name'],
+ 'field': name,
'error': 'Invalid value for list field: {}'.format(
value
),
@@ -150,7 +143,6 @@ class Collection(object):
def __init__(self, directory=None, itemdir='items'):
self.basedir = directory or os.getcwd()
self.itemdir = os.path.join(self.basedir, itemdir)
- self.types = self._load_types()
try:
with open(os.path.join(self.basedir, 'settings.yaml')) as fp:
self.settings = ruamel.yaml.load(
@@ -158,6 +150,7 @@ class Collection(object):
)
except FileNotFoundError:
self.settings = ruamel.yaml.safe_load("{}")
+ self.fields = self.load_field_types()
os.makedirs(os.path.join(self.basedir, '.lesana'), exist_ok=True)
if 'lang' in self.settings:
try:
@@ -176,11 +169,30 @@ class Collection(object):
self.safe = False
self.entry_class = Entry
- def _load_types(self):
+ def _get_subsubclasses(self, cls):
+ for c in cls.__subclasses__():
+ yield c
+ yield from self._get_subsubclasses(c)
+
+ def load_field_types(self):
type_loaders = {}
- for t in types.LesanaType.__subclasses__():
- type_loaders[t.name] = t()
- return type_loaders
+ for t in self._get_subsubclasses(types.LesanaType):
+ type_loaders[t.name] = t
+ fields = {}
+ for field in self.settings.get('fields', []):
+ try:
+ fields[field['name']] = type_loaders[field['type']]()
+ except KeyError:
+ # unknown fields are treated as if they were
+ # (unvalidated) generic YAML to support working with
+ # collections based on lesana derivatives
+ logging.warning(
+ "Unknown field type %s in field %s",
+ field['type'],
+ field['name'],
+ )
+ fields[field['name']] = types.LesanaYAML()
+ return fields
def _index_file(self, fname, cache):
with open(os.path.join(self.itemdir, fname)) as fp:
diff --git a/lesana/types.py b/lesana/types.py
index 565d1b2..a252830 100644
--- a/lesana/types.py
+++ b/lesana/types.py
@@ -221,6 +221,17 @@ class LesanaYAML(LesanaType):
return None
+class LesanaList(LesanaYAML):
+ """
+ A list of other values
+ """
+
+ name = 'list'
+
+ # Temporary definition so that tests aren't broken in the current
+ # commit
+
+
class LesanaValueError(ValueError):
"""
Raised in case of validation errors.
diff --git a/tests/data/wrong/settings.yaml b/tests/data/wrong/settings.yaml
index 83a542b..bf79572 100644
--- a/tests/data/wrong/settings.yaml
+++ b/tests/data/wrong/settings.yaml
@@ -23,3 +23,6 @@ fields:
type: list
list: string
index: field
+ - name: cloud
+ type: cloud
+ help: 'There is no cloud type'
diff --git a/tests/test_collection.py b/tests/test_collection.py
index 832f421..f7ddf6d 100644
--- a/tests/test_collection.py
+++ b/tests/test_collection.py
@@ -305,6 +305,22 @@ class testComplexCollection(unittest.TestCase):
self.assertIn('with_default', entry.yaml_data)
self.assertIn('amount: 0', entry.yaml_data)
+ def test_load_field_loaders(self):
+ # Check that all fields have been loaded, with the right types
+ to_test = (
+ ('name', lesana.types.LesanaString),
+ ('description', lesana.types.LesanaText),
+ ('position', lesana.types.LesanaString),
+ ('something', lesana.types.LesanaYAML),
+ ('tags', lesana.types.LesanaList),
+ ('keywords', lesana.types.LesanaList),
+ ('exists', lesana.types.LesanaBoolean),
+ ('with_default', lesana.types.LesanaString),
+ ('amount', lesana.types.LesanaInt),
+ )
+ for f in to_test:
+ self.assertIsInstance(self.collection.fields[f[0]], f[1])
+
class testCollectionWithErrors(unittest.TestCase):
def setUp(self):
@@ -320,8 +336,8 @@ class testCollectionWithErrors(unittest.TestCase):
# check that the log contains a warning.
with self.assertLogs(level=logging.WARNING) as cm:
self.collection = lesana.Collection(self.tmpdir)
- self.assertEqual(len(cm.output), 1)
- self.assertIn("Invalid language", cm.output[0])
+ self.assertEqual(len(cm.output), 2)
+ self.assertIn("Invalid language", cm.output[1])
# The collection will default to english, but should still work.
self.collection.update_cache()
self.assertIsNotNone(self.collection.settings)
@@ -334,7 +350,7 @@ class testCollectionWithErrors(unittest.TestCase):
self.assertIsNotNone(self.collection.settings)
self.assertIsNotNone(self.collection.stemmer)
# Fields with no "index" entry are not indexed
- self.assertEqual(len(self.collection.settings['fields']), 7)
+ self.assertEqual(len(self.collection.settings['fields']), 8)
self.assertEqual(len(self.collection.indexed_fields), 3)
def test_init(self):
@@ -343,7 +359,7 @@ class testCollectionWithErrors(unittest.TestCase):
self.collection.settings['name'],
"Lesana collection with certain errors",
)
- self.assertEqual(len(self.collection.settings['fields']), 7)
+ self.assertEqual(len(self.collection.settings['fields']), 8)
self.assertIsNotNone(self.collection.stemmer)
self.assertEqual(len(self.collection.indexed_fields), 3)