There are quite many hardcoded constants (e.g. “[…] one of ``file``, ``lvm-pv`` or ``lvm-vg`` […]). By using constants it'll be easier to identify these.
With such lists of values it's also easy to miss some when extending/changing something. By adding assertions inlined with reST, these can also be detected. Signed-off-by: Michael Hanselmann <[email protected]> --- lib/build/sphinx_ext.py | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 59 insertions(+), 0 deletions(-) diff --git a/lib/build/sphinx_ext.py b/lib/build/sphinx_ext.py index 18fbe1d..0af8ff8 100644 --- a/lib/build/sphinx_ext.py +++ b/lib/build/sphinx_ext.py @@ -27,10 +27,15 @@ import operator from cStringIO import StringIO import docutils.statemachine +import docutils.nodes +import docutils.utils import sphinx.errors import sphinx.util.compat +from ganeti import constants +from ganeti import compat +from ganeti import errors from ganeti import utils from ganeti import opcodes from ganeti import ht @@ -38,6 +43,9 @@ from ganeti import ht COMMON_PARAM_NAMES = map(operator.itemgetter(0), opcodes.OpCode.OP_PARAMS) +#: Namespace for evaluating expressions +EVAL_NS = dict(compat=compat, constants=constants, utils=utils, errors=errors) + class OpcodeError(sphinx.errors.SphinxError): category = "Opcode error" @@ -150,8 +158,59 @@ class OpcodeParams(sphinx.util.compat.Directive): return [] +def PythonEvalRole(role, rawtext, text, lineno, inliner, + options={}, content=[]): + """Custom role to evaluate Python expressions. + + The expression's result is included as a literal. + + """ + code = docutils.utils.unescape(text, restore_backslashes=True) + + try: + result = eval(code, EVAL_NS) + except Exception, err: + msg = inliner.reporter.error("Failed to evaluate %r: %s" % (code, err), + line=lineno) + return ([inliner.problematic(rawtext, rawtext, msg)], [msg]) + + node = docutils.nodes.literal("", unicode(result), **options) + + return ([node], []) + + +class PythonAssert(sphinx.util.compat.Directive): + """Custom directive for writing assertions. + + The content must be a valid Python expression. If its result does not + evaluate to C{True}, the assertion fails. + + """ + has_content = True + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = False + + def run(self): + self.assert_has_content() + + code = "\n".join(self.content) + + try: + result = eval(code, EVAL_NS) + except Exception, err: + raise self.error("Failed to evaluate %r: %s" % (code, err)) + + if not result: + raise self.error("Assertion failed: %s" % (code, )) + + return [] + + def setup(app): """Sphinx extension callback. """ app.add_directive("opcode_params", OpcodeParams) + app.add_directive("pyassert", PythonAssert) + app.add_role("pyeval", PythonEvalRole) -- 1.7.3.5
