Skip to content
Snippets Groups Projects
Commit ae8f0895 authored by Michiel Cottaar's avatar Michiel Cottaar
Browse files

ENH: allow setting of variables to None to explicitly unset them

parent 53589fb3
No related branches found
No related tags found
No related merge requests found
......@@ -20,7 +20,7 @@ class FileTree(object):
Properties
- ``templates``: dictionary mapping short names to filename templates
- ``variables``: dictionary mapping variables in the templates to specific values
- ``variables``: dictionary mapping variables in the templates to specific values (variables set to None are explicitly unset)
- ``sub_trees``: filename trees describing specific sub-directories
- ``parent``: parent FileTree, of which this sub-tree is a sub-directory
"""
......@@ -182,6 +182,7 @@ class FileTree(object):
Creates a new filetree with updated variables
:arg variables: new values for the variables
Setting variables to None will explicitly unset them
"""
new_tree = deepcopy(self)
new_tree.variables.update(variables)
......@@ -194,6 +195,7 @@ class FileTree(object):
:param short_name: short name of the path template
:param filename: filename matching the template
:return: variables needed to get to the given filename
Variables with None value are optional variables in the template that were not used
"""
text, _ = self.get_template(short_name)
return utils.extract_variables(text, filename, self.variables)
......
......@@ -65,14 +65,18 @@ def fill_known(template, variables):
Fills in the known variables filling the other variables with {<variable_name>}
:param template: template
:param variables: mapping of variable names to values
:param variables: mapping of variable names to values (ignoring any None)
:return: cleaned string
"""
prev = ''
while prev != template:
prev = template
settings = {name: variables[name] if name in variables else '{' + name + '}'
for name in set(find_variables(template))}
settings = {}
for name in set(find_variables(template)):
if name in variables and variables[name] is not None:
settings[name] = variables[name]
else:
settings[name] = '{' + name + '}'
template = template.format(**settings)
return template
......@@ -135,7 +139,7 @@ def extract_variables(template, filename, known_vars=None):
:param template: template matching the given filename
:param filename: filename
:param known_vars: already known variables
:return: dictionary from variable names to string representations
:return: dictionary from variable names to string representations (unused variables set to None)
"""
if known_vars is None:
known_vars = {}
......@@ -166,6 +170,9 @@ def extract_variables(template, filename, known_vars=None):
raise ValueError('Multiple values found for {}'.format(var))
else:
extracted_value[var] = value
for name in find_variables(template):
if name not in extracted_value:
extracted_value[name] = None
extracted_value.update(known_vars)
return extracted_value
raise ValueError("{} did not match {}".format(filename, template))
......@@ -76,6 +76,9 @@ def test_custom_tree():
assert len(tree.get_all('sub_file', glob_vars=['opt'])) == 2
assert len(tree.get_all('sub_file', glob_vars='all')) == 2
assert len(tree.get_all('sub_file')) == 1
assert len(tree.update(opt=None).get_all('sub_file')) == 1
assert len(tree.update(opt=None).get_all('sub_file', glob_vars=['opt'])) == 1
assert len(tree.update(opt=None).get_all('sub_file', glob_vars='all')) == 1
for fn, settings in zip(tree.get_all('sub_file', glob_vars='all'),
tree.get_all_vars('sub_file', glob_vars='all')):
......@@ -87,9 +90,10 @@ def test_custom_tree():
tree.get_all('opt_file')
assert len(tree.get_all('opt_file', glob_vars=['opt'])) == 1
for vars in ({}, {'opt': 'test'}):
for vars in ({'opt': None}, {'opt': 'test'}):
filename = tree.update(**vars).get('sub_file')
assert vars == tree.extract_variables('sub_file', filename)
assert {'opt': None} == tree.extract_variables('sub_file', tree.get('sub_file'))
assert tree.exists(('sub_file', 'opt_file'), error=True, on_disk=True, glob_vars=['opt'])
assert tree.exists(('sub_file', 'opt_file'), on_disk=True, glob_vars=['opt'])
......
......@@ -11,10 +11,10 @@ def test_variables():
def test_get_variables():
assert {'var': 'test'} == utils.extract_variables('{var}', 'test')
assert {'var': 'test'} == utils.extract_variables('2{var}', '2test')
assert {'var': 'test'} == utils.extract_variables('{var}[_{other_var}]', 'test')
assert {'var': 'test', 'other_var': None} == utils.extract_variables('{var}[_{other_var}]', 'test')
assert {'var': 'test', 'other_var': 'foo'} == utils.extract_variables('{var}[_{other_var}]', 'test_foo')
assert {'var': 'test', 'other_var': 'foo'} == utils.extract_variables('{var}[_{other_var}]_{var}', 'test_foo_test')
assert {'var': 'test'} == utils.extract_variables('{var}[_{other_var}]_{var}', 'test_test')
assert {'var': 'test', 'other_var': None} == utils.extract_variables('{var}[_{other_var}]_{var}', 'test_test')
with pytest.raises(ValueError):
utils.extract_variables('{var}[_{other_var}]_{var}', 'test_foo')
with pytest.raises(ValueError):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment