add FileOption
authorEmmanuel Garette <egarette@cadoles.com>
Mon, 30 Sep 2013 19:21:47 +0000 (21:21 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Mon, 30 Sep 2013 19:21:47 +0000 (21:21 +0200)
test/test_config_api.py
test/test_slots.py
tiramisu/option.py

index ab4b484..c0cc9a7 100644 (file)
@@ -4,7 +4,7 @@ from py.test import raises
 
 from tiramisu.config import Config
 from tiramisu.option import IntOption, FloatOption, StrOption, ChoiceOption, \
-    BoolOption, OptionDescription
+    BoolOption, FileOption, OptionDescription
 
 
 def make_description():
@@ -137,3 +137,18 @@ def test_does_not_find_in_config():
     descr = make_description()
     conf = Config(descr)
     raises(AttributeError, "conf.find(byname='IDontExist')")
+
+
+def test_file():
+    a = FileOption('a', '')
+    o = OptionDescription('o', '', [a])
+    c = Config(o)
+    c.a = u'/'
+    c.a = u'/tmp'
+    c.a = u'/tmp/'
+    c.a = u'/tmp/text.txt'
+    c.a = u'tmp'
+    c.a = u'tmp/'
+    c.a = u'tmp/text.txt'
+    raises(ValueError, "c.a = u'/tmp/with space.txt'")
+    raises(ValueError, "c.a = u'/tmp/with$.txt'")
index 1f2aee6..1f65f6d 100644 (file)
@@ -3,9 +3,10 @@ import autopath
 from py.test import raises
 
 from tiramisu.config import Config, SubConfig
-from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
+from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption,\
     StrOption, SymLinkOption, UnicodeOption, IPOption, OptionDescription, \
-    PortOption, NetworkOption, NetmaskOption, DomainnameOption
+    PortOption, NetworkOption, NetmaskOption, DomainnameOption, EmailOption, \
+    URLOption, FileOption
 
 
 def test_slots_option():
@@ -35,6 +36,12 @@ def test_slots_option():
     raises(AttributeError, "c.x = 1")
     c = DomainnameOption('a', '')
     raises(AttributeError, "c.x = 1")
+    c = EmailOption('a', '')
+    raises(AttributeError, "c.x = 1")
+    c = URLOption('a', '')
+    raises(AttributeError, "c.x = 1")
+    c = FileOption('a', '')
+    raises(AttributeError, "c.x = 1")
 
 
 def test_slots_option_readonly():
@@ -49,7 +56,10 @@ def test_slots_option_readonly():
     j = NetworkOption('j', '')
     k = NetmaskOption('k', '')
     l = DomainnameOption('l', '')
-    m = OptionDescription('m', '', [a, b, c, d, e, g, h, i, j, k, l])
+    o = EmailOption('o', '')
+    p = URLOption('p', '')
+    q = FileOption('q', '')
+    m = OptionDescription('m', '', [a, b, c, d, e, g, h, i, j, k, l, o, p, q])
     a._requires = 'a'
     b._requires = 'b'
     c._requires = 'c'
@@ -62,6 +72,9 @@ def test_slots_option_readonly():
     k._requires = 'k'
     l._requires = 'l'
     m._requires = 'm'
+    o._requires = 'o'
+    p._requires = 'p'
+    q._requires = 'q'
     Config(m)
     raises(AttributeError, "a._requires = 'a'")
     raises(AttributeError, "b._requires = 'b'")
@@ -75,6 +88,9 @@ def test_slots_option_readonly():
     raises(AttributeError, "k._requires = 'k'")
     raises(AttributeError, "l._requires = 'l'")
     raises(AttributeError, "m._requires = 'm'")
+    raises(AttributeError, "o._requires = 'o'")
+    raises(AttributeError, "p._requires = 'p'")
+    raises(AttributeError, "q._requires = 'q'")
 
 
 def test_slots_option_readonly_name():
@@ -90,7 +106,10 @@ def test_slots_option_readonly_name():
     j = NetworkOption('j', '')
     k = NetmaskOption('k', '')
     l = DomainnameOption('l', '')
-    m = OptionDescription('m', '', [a, b, c, d, e, f, g, h, i, j, k, l])
+    o = DomainnameOption('o', '')
+    p = DomainnameOption('p', '')
+    q = DomainnameOption('q', '')
+    m = OptionDescription('m', '', [a, b, c, d, e, f, g, h, i, j, k, l, o, p, q])
     raises(AttributeError, "a._name = 'a'")
     raises(AttributeError, "b._name = 'b'")
     raises(AttributeError, "c._name = 'c'")
@@ -104,6 +123,9 @@ def test_slots_option_readonly_name():
     raises(AttributeError, "k._name = 'k'")
     raises(AttributeError, "l._name = 'l'")
     raises(AttributeError, "m._name = 'm'")
+    raises(AttributeError, "o._name = 'o'")
+    raises(AttributeError, "p._name = 'p'")
+    raises(AttributeError, "q._name = 'q'")
 
 
 def test_slots_description():
index dec7b02..2bb9328 100644 (file)
@@ -1031,6 +1031,7 @@ class DomainnameOption(Option):
 
 class EmailOption(DomainnameOption):
     __slots__ = tuple()
+    _opt_type = 'email'
     username_re = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$")
 
     def __init__(self, *args, **kwargs):
@@ -1053,6 +1054,7 @@ class EmailOption(DomainnameOption):
 
 class URLOption(DomainnameOption):
     __slots__ = tuple()
+    _opt_type = 'url'
     proto_re = re.compile(r'(http|https)://')
     path_re = re.compile(r"^[a-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
 
@@ -1093,6 +1095,17 @@ class URLOption(DomainnameOption):
                                ' {0}').format(self._name))
 
 
+class FileOption(Option):
+    __slots__ = tuple()
+    _opt_type = 'file'
+    path_re = re.compile(r"^[a-zA-Z0-9\-\._~/+]+$")
+
+    def _validate(self, value):
+        match = self.path_re.search(value)
+        if not match:
+            raise ValueError(_('invalid filename for {0}').format(self._name))
+
+
 class OptionDescription(BaseOption):
     """Config's schema (organisation, group) and container of Options
     The `OptionsDescription` objects lives in the `tiramisu.config.Config`.