From cce080cbd33a36e88347f20708616eccd9d00be3 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Mon, 30 Sep 2013 21:21:47 +0200 Subject: [PATCH] add FileOption --- test/test_config_api.py | 17 ++++++++++++++++- test/test_slots.py | 30 ++++++++++++++++++++++++++---- tiramisu/option.py | 13 +++++++++++++ 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/test/test_config_api.py b/test/test_config_api.py index ab4b484..c0cc9a7 100644 --- a/test/test_config_api.py +++ b/test/test_config_api.py @@ -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'") diff --git a/test/test_slots.py b/test/test_slots.py index 1f2aee6..1f65f6d 100644 --- a/test/test_slots.py +++ b/test/test_slots.py @@ -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(): diff --git a/tiramisu/option.py b/tiramisu/option.py index dec7b02..2bb9328 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -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`.