summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lesana/collection.py24
-rw-r--r--lesana/types.py34
-rw-r--r--tests/data/wrong/items/07f079d281f542f88b97aa1c30d72e12.yaml11
-rw-r--r--tests/test_types.py70
4 files changed, 92 insertions, 47 deletions
diff --git a/lesana/collection.py b/lesana/collection.py
index a449de1..ecb3eca 100644
--- a/lesana/collection.py
+++ b/lesana/collection.py
@@ -94,31 +94,16 @@ class Entry(object):
valid = True
for name, field in self.collection.fields.items():
value = self.data.get(name, None)
- t = field.name
try:
self.data[name] = field.load(value)
except types.LesanaValueError as e:
+ valid = False
errors.append(
{
'field': name,
'error': e,
}
)
-
- if t != 'list' and not value:
- # empty fields are always fine except for lists
- continue
- elif t == 'list':
- if not hasattr(value, '__iter__'):
- valid = False
- errors.append(
- {
- 'field': name,
- 'error': 'Invalid value for list field: {}'.format(
- value
- ),
- }
- )
return valid, errors
def render(self, template, searchpath='.'):
@@ -181,7 +166,10 @@ class Collection(object):
fields = {}
for field in self.settings.get('fields', []):
try:
- fields[field['name']] = type_loaders[field['type']](field)
+ fields[field['name']] = type_loaders[field['type']](
+ field,
+ type_loaders,
+ )
except KeyError:
# unknown fields are treated as if they were
# (unvalidated) generic YAML to support working with
@@ -191,7 +179,7 @@ class Collection(object):
field['type'],
field['name'],
)
- fields[field['name']] = types.LesanaYAML(field)
+ fields[field['name']] = types.LesanaYAML(field, type_loaders)
return fields
def _index_file(self, fname, cache):
diff --git a/lesana/types.py b/lesana/types.py
index c4061f2..ccdaf20 100644
--- a/lesana/types.py
+++ b/lesana/types.py
@@ -6,6 +6,7 @@ significantly in a future release.
"""
import datetime
import decimal
+import logging
import dateutil.parser
@@ -14,7 +15,7 @@ class LesanaType:
"""
Base class for lesana field types.
"""
- def __init__(self, field):
+ def __init__(self, field, types):
self.field = field
def load(self, data):
@@ -99,7 +100,7 @@ class LesanaDecimal(LesanaType):
return decimal.Decimal(data)
except decimal.InvalidOperation:
raise LesanaValueError(
- "Invalid value for float field: {}".format(data)
+ "Invalid value for decimal field: {}".format(data)
)
def empty(self):
@@ -224,15 +225,38 @@ class LesanaYAML(LesanaType):
return None
-class LesanaList(LesanaYAML):
+class LesanaList(LesanaType):
"""
A list of other values
"""
name = 'list'
- # Temporary definition so that tests aren't broken in the current
- # commit
+ def __init__(self, field, types):
+ super().__init__(field, types)
+ try:
+ self.sub_type = types[field['list']](field, types)
+ except KeyError:
+ logging.warning(
+ "Unknown field type %s in field %s",
+ field['type'],
+ field['name'],
+ )
+ self.sub_type = types['yaml'](field, types)
+
+ def load(self, data):
+ if data is None:
+ # empty for this type means an empty list
+ return []
+ try:
+ return [self.sub_type.load(x) for x in data]
+ except TypeError:
+ raise LesanaValueError(
+ "Invalid value for list field: {}".format(data)
+ )
+
+ def empty(self):
+ return []
class LesanaValueError(ValueError):
diff --git a/tests/data/wrong/items/07f079d281f542f88b97aa1c30d72e12.yaml b/tests/data/wrong/items/07f079d281f542f88b97aa1c30d72e12.yaml
deleted file mode 100644
index 79fe93f..0000000
--- a/tests/data/wrong/items/07f079d281f542f88b97aa1c30d72e12.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-name: 'bad things'
-description: |
- An entry with bad things (empty instead of an empty list)
-position: ''
-# number (integer): Enter an integer here
-number: 0
-# float (float): Enter a floating point number here
-float: 0.0
-# price (decimal): prices are never float!
-price: 0.00
-things:
diff --git a/tests/test_types.py b/tests/test_types.py
index 363d9a4..9e0c931 100644
--- a/tests/test_types.py
+++ b/tests/test_types.py
@@ -19,7 +19,7 @@ class testTypes(unittest.TestCase):
}
def test_base(self):
- checker = types.LesanaType(self._get_field_def('base'))
+ checker = types.LesanaType(self._get_field_def('base'), {})
# The base class does not implement empty nor load
with self.assertRaises(NotImplementedError):
@@ -29,7 +29,7 @@ class testTypes(unittest.TestCase):
checker.load("")
def test_string(self):
- checker = types.LesanaString(self._get_field_def('string'))
+ checker = types.LesanaString(self._get_field_def('string'), {})
s = checker.empty()
self.assertEqual(s, "")
@@ -41,7 +41,7 @@ class testTypes(unittest.TestCase):
self.assertEqual(s, None)
def test_text(self):
- checker = types.LesanaText(self._get_field_def('text'))
+ checker = types.LesanaText(self._get_field_def('text'), {})
s = checker.empty()
self.assertEqual(s, "")
@@ -53,7 +53,7 @@ class testTypes(unittest.TestCase):
self.assertEqual(s, None)
def test_int(self):
- checker = types.LesanaInt(self._get_field_def('integer'))
+ checker = types.LesanaInt(self._get_field_def('integer'), {})
v = checker.empty()
self.assertEqual(v, 0)
@@ -72,7 +72,7 @@ class testTypes(unittest.TestCase):
self.assertEqual(v, None)
def test_float(self):
- checker = types.LesanaFloat(self._get_field_def('float'))
+ checker = types.LesanaFloat(self._get_field_def('float'), {})
v = checker.empty()
self.assertEqual(v, 0.0)
@@ -94,7 +94,7 @@ class testTypes(unittest.TestCase):
self.assertEqual(v, None)
def test_decimal(self):
- checker = types.LesanaDecimal(self._get_field_def('decimal'))
+ checker = types.LesanaDecimal(self._get_field_def('decimal'), {})
v = checker.empty()
self.assertEqual(v, decimal.Decimal(0))
@@ -116,7 +116,7 @@ class testTypes(unittest.TestCase):
self.assertEqual(v, None)
def test_timestamp(self):
- checker = types.LesanaTimestamp(self._get_field_def('timestamp'))
+ checker = types.LesanaTimestamp(self._get_field_def('timestamp'), {})
v = checker.empty()
self.assertEqual(v, None)
@@ -142,7 +142,7 @@ class testTypes(unittest.TestCase):
self.assertEqual(v, None)
def test_datetime(self):
- checker = types.LesanaDatetime(self._get_field_def('datetime'))
+ checker = types.LesanaDatetime(self._get_field_def('datetime'), {})
v = checker.empty()
self.assertEqual(v, None)
@@ -171,7 +171,7 @@ class testTypes(unittest.TestCase):
self.assertEqual(v, None)
def test_date(self):
- checker = types.LesanaDate(self._get_field_def('date'))
+ checker = types.LesanaDate(self._get_field_def('date'), {})
v = checker.empty()
self.assertEqual(v, None)
@@ -200,7 +200,7 @@ class testTypes(unittest.TestCase):
self.assertEqual(v, None)
def test_boolean(self):
- checker = types.LesanaBoolean(self._get_field_def('boolean'))
+ checker = types.LesanaBoolean(self._get_field_def('boolean'), {})
v = checker.empty()
self.assertEqual(v, None)
@@ -216,7 +216,7 @@ class testTypes(unittest.TestCase):
self.assertEqual(v, None)
def test_file(self):
- checker = types.LesanaFile(self._get_field_def('file'))
+ checker = types.LesanaFile(self._get_field_def('file'), {})
v = checker.empty()
self.assertEqual(v, "")
@@ -230,7 +230,7 @@ class testTypes(unittest.TestCase):
# TODO: check for invalid file paths
def test_url(self):
- checker = types.LesanaURL(self._get_field_def('url'))
+ checker = types.LesanaURL(self._get_field_def('url'), {})
v = checker.empty()
self.assertEqual(v, "")
@@ -244,7 +244,7 @@ class testTypes(unittest.TestCase):
# TODO: check for invalid URLs
def test_yaml(self):
- checker = types.LesanaYAML(self._get_field_def('yaml'))
+ checker = types.LesanaYAML(self._get_field_def('yaml'), {})
v = checker.empty()
self.assertEqual(v, None)
@@ -259,6 +259,50 @@ class testTypes(unittest.TestCase):
v = checker.load(None)
self.assertEqual(v, None)
+ def test_list(self):
+ field_def = self._get_field_def('yaml')
+ # we use one type that is easy to check for correct validation
+ field_def['list'] = 'int'
+ checker = types.LesanaList(field_def, {'int': types.LesanaInt})
+
+ v = checker.empty()
+ self.assertEqual(v, [])
+
+ some_data = [1, 2, 3]
+ v = checker.load(some_data)
+ self.assertEqual(v, some_data)
+
+ v = checker.load(None)
+ self.assertEqual(v, [])
+
+ for d in (['hello'], 1):
+ with self.assertRaises(types.LesanaValueError):
+ checker.load(d)
+
+ def test_list_unknown_subtype(self):
+ field_def = self._get_field_def('yaml')
+ # we use one type that is easy to check for correct validation
+ field_def['list'] = 'int'
+ checker = types.LesanaList(field_def, {'yaml': types.LesanaYAML})
+
+ v = checker.empty()
+ self.assertEqual(v, [])
+
+ some_data = [1, 2, 3]
+ v = checker.load(some_data)
+ self.assertEqual(v, some_data)
+
+ some_data = ["hello"]
+ v = checker.load(some_data)
+ self.assertEqual(v, some_data)
+
+ v = checker.load(None)
+ self.assertEqual(v, [])
+
+ for d in (1, 1.0):
+ with self.assertRaises(types.LesanaValueError):
+ checker.load(d)
+
if __name__ == '__main__':
unittest.main()