[SEBA-126] Adding xproto support for min and max validators
Change-Id: I6141c678d88a894db2a86132bdbad4e9c6b31b2f
diff --git a/lib/xos-genx/xos-genx-tests/test_django_generator.py b/lib/xos-genx/xos-genx-tests/test_django_generator.py
index c3ffef5..d2b3c8a 100644
--- a/lib/xos-genx/xos-genx-tests/test_django_generator.py
+++ b/lib/xos-genx/xos-genx-tests/test_django_generator.py
@@ -95,10 +95,30 @@
args.target = 'django.xtarget'
output = XOSProcessor.process(args)
- print output
-
self.assertIn("feedback_state_fields = ['parent_name', 'name']", output)
+ def test_min_max_validators(self):
+ """
+ [XOS-GenX] Use django validors for min and max values
+ """
+ xproto = \
+ """
+ option app_label = "test";
+
+ message Foo (ParentFoo) {
+ required int32 val = 1 [min_value = 1, max_value = 10];
+ }
+ """
+
+ args = FakeArgs()
+ args.inputs = xproto
+ args.target = 'django.xtarget'
+ output = XOSProcessor.process(args)
+
+ self.assertIn("validators=[", output)
+ self.assertIn("MinValueValidator(1)", output)
+ self.assertIn("MaxValueValidator(10)", output)
+
if __name__ == '__main__':
unittest.main()
diff --git a/lib/xos-genx/xos-genx-tests/test_jinja2_django.py b/lib/xos-genx/xos-genx-tests/test_jinja2_django.py
index ea8738e..ab47443 100644
--- a/lib/xos-genx/xos-genx-tests/test_jinja2_django.py
+++ b/lib/xos-genx/xos-genx-tests/test_jinja2_django.py
@@ -44,6 +44,75 @@
res = xproto_optioned_fields_to_list(fields, 'feedback_state', 'True')
self.assertEqual(res, ["has_feedback_1", "has_feedback_2"])
+ def test_xproto_required_to_django(self):
+ field = {
+ 'name': 'foo',
+ 'options': {
+ 'modifier': 'required'
+ }
+ }
+
+ res = map_xproto_to_django(field)
+ self.assertEqual(res, {'blank': False, 'null': False})
+
+ def test_xproto_optional_to_django(self):
+ field = {
+ 'name': 'foo',
+ 'options': {
+ 'modifier': 'optional'
+ }
+ }
+
+ res = map_xproto_to_django(field)
+ self.assertEqual(res, {'blank': True, 'null': True})
+
+
+ def test_map_xproto_to_django(self):
+
+ options = {
+ 'help_text': 'bar',
+ 'default': 'default_value',
+ 'null': True,
+ 'db_index': False,
+ 'blank': False,
+ 'min_value': 16,
+ 'max_value': 16
+ }
+
+ field = {
+ 'name': 'foo',
+ 'options': options
+ }
+
+ res = map_xproto_to_django(field)
+ self.assertEqual(res, options)
+
+ def test_format_options_string(self):
+
+ options = {
+ 'null': True,
+ 'min_value': 16,
+ 'max_value': 16
+ }
+
+ res = format_options_string(options)
+ self.assertEqual(res, "null = True, validators=[MaxValueValidator(16), MinValueValidator(16)]")
+
+ options = {
+ 'min_value': 16,
+ 'max_value': 16
+ }
+
+ res = format_options_string(options)
+ self.assertEqual(res, "validators=[MaxValueValidator(16), MinValueValidator(16)]")
+
+ options = {
+ 'null': True,
+ }
+
+ res = format_options_string(options)
+ self.assertEqual(res, "null = True")
+
if __name__ == '__main__':
unittest.main()
diff --git a/lib/xos-genx/xosgenx/jinja2_extensions/django.py b/lib/xos-genx/xosgenx/jinja2_extensions/django.py
index 464172a..64ab51a 100644
--- a/lib/xos-genx/xosgenx/jinja2_extensions/django.py
+++ b/lib/xos-genx/xosgenx/jinja2_extensions/django.py
@@ -79,18 +79,22 @@
return 'GenericRelation'
def map_xproto_to_django(f):
- allowed_keys=['help_text','default','max_length','modifier','blank','choices','db_index','null','editable','on_delete','verbose_name', 'auto_now_add', 'unique']
+ allowed_keys=['help_text','default','max_length','modifier','blank','choices','db_index','null','editable','on_delete','verbose_name', 'auto_now_add', 'unique', 'min_value', 'max_value']
- m = {'modifier':{'optional':True, 'required':False, '_target':'null'}}
+ # TODO evaluate if setting Null = False for all strings
+ m = {'modifier':{'optional':True, 'required':False, '_targets': ['null', 'blank']}}
out = {}
for k,v in f['options'].items():
- if (k in allowed_keys):
+ if k in allowed_keys:
try:
+ # NOTE this will be used to parse xproto optional/required field prefix and apply it to the null and blank fields
kv2 = m[k]
- out[kv2['_target']] = kv2[v]
+ for t in kv2['_targets']:
+ out[t] = kv2[v]
except:
out[k] = v
+
return out
def xproto_django_link_options_str(field, dport=None):
@@ -121,17 +125,33 @@
return format_options_string(output_dict)
+def use_native_django_validators(k, v):
+
+ validators_map = {
+ 'min_value': 'MinValueValidator',
+ 'max_value': 'MaxValueValidator'
+ }
+
+ return "%s(%s)" % (validators_map[k], v)
+
def format_options_string(d):
+
+ known_validators = ['min_value', 'max_value']
+ validator_lst = []
+
if (not d):
return ''
else:
lst = []
for k,v in d.items():
- if (type(v)==str and k=='default' and v.endswith('()"')):
+ if k in known_validators:
+ validator_lst.append(use_native_django_validators(k, v))
+ elif (type(v)==str and k=='default' and v.endswith('()"')):
lst.append('%s = %s'%(k,v[1:-3]))
elif (type(v)==str and v.startswith('"')):
try:
+ # unquote the value if necessary
tup = eval(v[1:-1])
if (type(tup)==tuple):
lst.append('%s = %r'%(k,tup))
@@ -146,8 +166,14 @@
lst.append('%s = %r'%(k,int(v)))
except ValueError:
lst.append('%s = %s'%(k,v))
-
- return ', '.join(lst)
+ validator_string = "validators=[%s]" % ', '.join(validator_lst)
+ option_string = ', '.join(lst)
+ if len(validator_lst) == 0:
+ return option_string
+ elif len(lst) == 0:
+ return validator_string
+ else:
+ return option_string + ", " + validator_string
def xproto_django_options_str(field, dport=None):
output_dict = map_xproto_to_django(field)
diff --git a/lib/xos-genx/xosgenx/targets/django.xtarget b/lib/xos-genx/xosgenx/targets/django.xtarget
index 631e8cd..ab67936 100644
--- a/lib/xos-genx/xosgenx/targets/django.xtarget
+++ b/lib/xos-genx/xosgenx/targets/django.xtarget
@@ -99,6 +99,8 @@
except AttributeError:
pass
+ self.full_clean()
+
{% for policy,error in xproto_validations(m.options) %}
policy_{{policy}}_validator(self, None)
{% endfor %}
diff --git a/lib/xos-genx/xosgenx/targets/service.xtarget b/lib/xos-genx/xosgenx/targets/service.xtarget
index e5816ab..1e83747 100644
--- a/lib/xos-genx/xosgenx/targets/service.xtarget
+++ b/lib/xos-genx/xosgenx/targets/service.xtarget
@@ -91,6 +91,8 @@
except AttributeError:
base_save_in_attic = False
+ self.full_clean()
+
if not base_save_in_attic:
super({{ m.name }}{{ legacy_tag }}, self).save(*args, **kwds)