Add check command, remove _ast import

- The check command checks to see if there is anything missing from the
  specified output file.

- All types in the `_ast' module are also exported from the `ast'
  module, so there is no need to use `_ast' explicitly.

- Don't raise an exception when a value from the specification doesn't
  match a predicate, the `check' command will take care of this.

- Place some functions outside of their previous classes. These are used
  by several classes/methods and they need no state from these classes.
This commit is contained in:
Tom Willemse 2013-12-15 22:45:06 +01:00
parent ea8763fd0d
commit 0988389972

View file

@ -1,6 +1,5 @@
from __future__ import print_function from __future__ import print_function
import _ast
import ast import ast
import os import os
import os.path import os.path
@ -21,12 +20,34 @@ def write_settings(specs, out, values=None):
.format(file=specs.OUTPUT_FILE), file=out) .format(file=specs.OUTPUT_FILE), file=out)
for key, spec in specs.SETTINGS: for key, spec in specs.SETTINGS:
value = values.get(key, spec['initial']) value = values.get(key, spec[1])
print(key, repr(value), sep=' = ', file=out)
if (spec['predicate'](value)):
print(key, repr(value), sep=' = ', file=out) def get_node_value(node):
else: if isinstance(node, ast.Name):
raise RuntimeError('Invalid type for %s: %s' % (key, repr(value))) return ast.literal_eval(node.id)
elif isinstance(node, ast.Str):
return node.s
elif isinstance(node, ast.Num):
return node.n
else:
return node
def get_settings_from(filename):
res = {}
with open(filename, 'r') as f:
tree = ast.parse('\n'.join(f.readlines()), filename)
for node in ast.iter_child_nodes(tree):
if isinstance(node, ast.Assign):
for target in node.targets:
res[target.id] = get_node_value(node.value)
else:
print(node, node._fields)
return res
class PreviewMixin(object): class PreviewMixin(object):
@ -62,35 +83,29 @@ class Generate(pycommand.CommandBase, PreviewMixin):
class Update(pycommand.CommandBase, PreviewMixin): class Update(pycommand.CommandBase, PreviewMixin):
usagestr = 'usage: topple update [--preview|-p]' usagestr = 'usage: topple update [--preview|-p]'
def _get_value(self, node): def run(self):
if isinstance(node, _ast.Name): sys.path.insert(0, os.getcwd())
return eval(node.id) filename = 'settings_local.py'
elif isinstance(node, _ast.Str): res = get_settings_from(filename)
return node.s specs = get_setting_specs(self.parentFlags['module'] or 'toppler')
elif isinstance(node, _ast.Num): self.write(specs.OUTPUT_FILE, specs, res)
return node.n
else:
return node
def _get_values(self, filename):
res = {}
with open(filename, 'r') as f: class Check(pycommand.CommandBase):
tree = ast.parse('\n'.join(f.readlines()), filename) usagestr = 'usage: topple check'
for node in ast.iter_child_nodes(tree):
if isinstance(node, _ast.Assign):
res[node.targets[0].id] = self._get_value(node.value)
else:
print(node, node._fields)
return res
def run(self): def run(self):
sys.path.insert(0, os.getcwd()) sys.path.insert(0, os.getcwd())
filename = 'settings_local.py' filename = 'settings_local.py'
res = self._get_values(filename) res = get_settings_from(filename)
specs = get_setting_specs(self.parentFlags['module'] or 'toppler') specs = get_setting_specs(self.parentFlags['module'] or 'toppler')
self.write(specs.OUTPUT_FILE, specs, res)
for key, spec in specs.SETTINGS:
if key not in res:
print('Missing setting:', key)
elif not spec[0](res[key]):
print('Value "%s" for %s does not pass predicate `%s\''
% (res[key], key, spec[0].func_name))
class Topple(pycommand.CommandBase): class Topple(pycommand.CommandBase):
@ -99,6 +114,7 @@ class Topple(pycommand.CommandBase):
'Commands:\n' 'Commands:\n'
' generate Generate a new settings file.\n' ' generate Generate a new settings file.\n'
' update Update an existing settings file.\n' ' update Update an existing settings file.\n'
' check Check the validity of an existing settings file.'
) )
optionList = (('module', ('m', '<modulename>', optionList = (('module', ('m', '<modulename>',
'Use specified python module.')),) 'Use specified python module.')),)
@ -117,6 +133,8 @@ class Topple(pycommand.CommandBase):
cmd = Generate(argv=self.args[1:]) cmd = Generate(argv=self.args[1:])
elif self.args[0] == 'update': elif self.args[0] == 'update':
cmd = Update(argv=self.args[1:]) cmd = Update(argv=self.args[1:])
elif self.args[0] == 'check':
cmd = Check(argv=self.args[1:])
else: else:
print('Undefined command: {cmd}'.format(cmd=self.args[0])) print('Undefined command: {cmd}'.format(cmd=self.args[0]))
return 1 return 1