diff --git a/configspec/specification.py b/configspec/specification.py index c30e49c..cb25806 100644 --- a/configspec/specification.py +++ b/configspec/specification.py @@ -83,17 +83,21 @@ class FloatSpec(_ValueSpecification): @preservable class StringSpec(_ValueSpecification): - def __init__(self, regex=None, helptext=""): + def __init__(self, regex=None, allowempty=False, helptext=""): """ Specify a string to be provided. If `regex` is not None, validation requires that the - config value directly matches the supplied regex string (calls `re.fullmatch`) + config value directly matches the supplied regex string (calls `re.fullmatch`). + If `allowempty` is False, validation requires that the string not be an empty or blank. """ super().__init__(helptext) self.regex = regex + self.allowempty = allowempty def validate(self, value): if not isinstance(value, str): raise InvalidConfigError(F"Config value must be a string and is {value}") + if not self.allowempty and (value == ""): + raise InvalidConfigError("Config value cannot be a blank string") if self.regex and (re.fullmatch(self.regex, value) is None): raise InvalidConfigError(F"Config string '{value}' must match regex" F" pattern '{self.regex}'") diff --git a/tests/test_configspec.py b/tests/test_configspec.py index e9dc625..0947af2 100644 --- a/tests/test_configspec.py +++ b/tests/test_configspec.py @@ -15,6 +15,7 @@ def example_spec(): confspec.add_spec("float_a", FloatSpec(-4, 4, helptext="Float A")) confspec.add_spec("floatlist_a", ListSpec(FloatSpec(-4, 4, "Float A"))) confspec.add_spec("string_a", StringSpec(helptext="String A")) + confspec.add_spec("string_a_blank", StringSpec(allowempty=True, helptext="String A Blank")) confspec.add_spec("stringlist_a", ListSpec(StringSpec(), helptext="String List A")) confdictspec = confspec.add_spec("dict_a", DictSpec(helptext="Dict A")) @@ -42,6 +43,7 @@ def example_values(): 'float_a': 1.5, 'floatlist_a': [1.2, 2.1, 3.7, 2.8], 'string_a': 'sometext', + 'string_a_blank': '', 'stringlist_a': ['somemoretext', 'yetmoretext'], 'dict_a': { 'bool_b': False, @@ -100,6 +102,8 @@ def test_invalid_string(): spec.validate(1) with pytest.raises(InvalidConfigError, match="value must be a string"): spec.validate(None) + with pytest.raises(InvalidConfigError, match="value cannot be a blank string"): + spec.validate("") def test_dict_optional():