aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElena ``of Valhalla'' Grandi <valhalla@trueelena.org>2020-10-01 16:38:13 +0200
committerElena ``of Valhalla'' Grandi <valhalla@trueelena.org>2020-10-01 16:38:13 +0200
commit83b92c51a863c09946c3da55b0b53490027bf723 (patch)
tree53222958999df5728607b06cc0b2a1d3e1de75cb
parent06eeed552b34fb5f60401c1536db3f2cbf868a89 (diff)
Start using types to validate/load entry fields
-rw-r--r--lesana/collection.py77
-rw-r--r--lesana/types.py10
-rw-r--r--tests/test_types.py15
3 files changed, 57 insertions, 45 deletions
diff --git a/lesana/collection.py b/lesana/collection.py
index b265b4d..4b3e964 100644
--- a/lesana/collection.py
+++ b/lesana/collection.py
@@ -1,4 +1,3 @@
-import decimal
import logging
import os
import uuid
@@ -8,6 +7,7 @@ import xapian
import jinja2
from pkg_resources import resource_string
+from . import types
try:
import git
@@ -72,7 +72,14 @@ class Entry(object):
@property
def yaml_data(self):
- return ruamel.yaml.dump(self.data, Dumper=ruamel.yaml.RoundTripDumper)
+ to_dump = self.data.copy()
+ # Decimal fields can't be represented by
+ # ruamel.yaml.RoundTripDumper, but transforming them to strings
+ # should be enough for all cases that we need.
+ for field in self.collection.settings['fields']:
+ if field['type'] == 'decimal':
+ to_dump[field['name']] = str(to_dump.get(field['name'], ''))
+ return ruamel.yaml.dump(to_dump, Dumper=ruamel.yaml.RoundTripDumper)
@property
def idterm(self):
@@ -88,51 +95,26 @@ class Entry(object):
for field in self.collection.settings['fields']:
value = self.data.get(field['name'], None)
t = field['type']
+ try:
+ self.data[field['name']] = self.collection.types[t].load(value)
+ except KeyError:
+ errors.append(
+ {
+ 'field': field['name'],
+ 'error': "No such type {}".format(t),
+ }
+ )
+ except types.LesanaValueError as e:
+ errors.append(
+ {
+ 'field': field['name'],
+ 'error': e,
+ }
+ )
+
if t != 'list' and not value:
# empty fields are always fine except for lists
continue
- if t == 'integer':
- try:
- int(value)
- except ValueError:
- valid = False
- errors.append(
- {
- 'field': field['name'],
- 'error':
- 'Invalid value for integer field: {}'.format(
- value
- ),
- }
- )
- elif t == 'float':
- try:
- float(value)
- except ValueError:
- valid = False
- errors.append(
- {
- 'field': field['name'],
- 'error':
- 'Invalid value for float field: {}'.format(
- value
- ),
- }
- )
- elif t == 'decimal':
- try:
- decimal.Decimal(value)
- except decimal.InvalidOperation:
- valid = False
- errors.append(
- {
- 'field': field['name'],
- 'error':
- 'Invalid value for decimal field: {}'.format(
- value
- ),
- }
- )
elif t == 'list':
if not hasattr(value, '__iter__'):
valid = False
@@ -168,6 +150,7 @@ 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(
@@ -193,6 +176,12 @@ class Collection(object):
self.safe = False
self.entry_class = Entry
+ def _load_types(self):
+ type_loaders = {}
+ for t in types.LesanaType.__subclasses__():
+ type_loaders[t.name] = t()
+ return type_loaders
+
def _index_file(self, fname, cache):
with open(os.path.join(self.itemdir, fname)) as fp:
if self.safe:
diff --git a/lesana/types.py b/lesana/types.py
index e093c9f..db6b661 100644
--- a/lesana/types.py
+++ b/lesana/types.py
@@ -25,6 +25,8 @@ class LesanaString(LesanaType):
name = 'string'
def load(self, data):
+ if not data:
+ return data
return str(data)
def empty(self):
@@ -45,6 +47,8 @@ class LesanaInt(LesanaType):
name = "integer"
def load(self, data):
+ if not data:
+ return data
try:
return int(data)
except ValueError:
@@ -63,6 +67,8 @@ class LesanaFloat(LesanaType):
name = "float"
def load(self, data):
+ if not data:
+ return data
try:
return float(data)
except ValueError:
@@ -78,9 +84,11 @@ class LesanaDecimal(LesanaType):
"""
A floating point number
"""
- name = "float"
+ name = "decimal"
def load(self, data):
+ if not data:
+ return data
try:
return decimal.Decimal(data)
except decimal.InvalidOperation:
diff --git a/tests/test_types.py b/tests/test_types.py
index 907be20..7aff73f 100644
--- a/tests/test_types.py
+++ b/tests/test_types.py
@@ -20,6 +20,9 @@ class testTypes(unittest.TestCase):
s = checker.load("Hello World!")
self.assertEqual(s, "Hello World!")
+ s = checker.load(None)
+ self.assertEqual(s, None)
+
def test_text(self):
checker = types.LesanaText()
@@ -29,6 +32,9 @@ class testTypes(unittest.TestCase):
s = checker.load("Hello World!")
self.assertEqual(s, "Hello World!")
+ s = checker.load(None)
+ self.assertEqual(s, None)
+
def test_int(self):
checker = types.LesanaInt()
@@ -45,6 +51,9 @@ class testTypes(unittest.TestCase):
with self.assertRaises(types.LesanaValueError):
checker.load(d)
+ v = checker.load(None)
+ self.assertEqual(v, None)
+
def test_float(self):
checker = types.LesanaFloat()
@@ -64,6 +73,9 @@ class testTypes(unittest.TestCase):
with self.assertRaises(types.LesanaValueError):
checker.load(d)
+ v = checker.load(None)
+ self.assertEqual(v, None)
+
def test_decimal(self):
checker = types.LesanaDecimal()
@@ -83,6 +95,9 @@ class testTypes(unittest.TestCase):
with self.assertRaises(types.LesanaValueError):
checker.load(d)
+ v = checker.load(None)
+ self.assertEqual(v, None)
+
if __name__ == '__main__':
unittest.main()