sphinx / sphinx / util /

# -*- coding: utf-8 -*-

    :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
    :license: BSD, see LICENSE for details.

import warnings
# jinja2.sandbox imports the sets module on purpose
warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,

# (ab)use the Jinja parser for parsing our boolean expressions
from jinja2 import nodes
from jinja2.parser import Parser
from jinja2.environment import Environment

env = Environment()

class BooleanParser(Parser):
    Only allow condition exprs and/or/not operations.

    def parse_compare(self):
        token =
        if token.type == 'name':
            if token.value in ('true', 'false', 'True', 'False'):
                node = nodes.Const(token.value in ('true', 'True'),
            elif token.value in ('none', 'None'):
                node = nodes.Const(None, lineno=token.lineno)
                node = nodes.Name(token.value, 'load', lineno=token.lineno)
        elif token.type == 'lparen':
            node = self.parse_expression()
  "unexpected token '%s'" % (token,), token.lineno)
        return node

class Tags(object):
    def __init__(self, tags=None):
        self.tags = dict.fromkeys(tags or [], True)

    def has(self, tag):
        return tag in self.tags

    __contains__ = has

    def __iter__(self):
        return iter(self.tags)

    def add(self, tag):
        self.tags[tag] = True

    def remove(self, tag):
        self.tags.pop(tag, None)

    def eval_condition(self, condition):
        # exceptions are handled by the caller
        parser = BooleanParser(env, condition, state='variable')
        expr = parser.parse_expression()
        if not
            raise ValueError('chunk after expression')

        def eval_node(node):
            if isinstance(node, nodes.CondExpr):
                if eval_node(node.test):
                    return eval_node(node.expr1)
                    return eval_node(node.expr2)
            elif isinstance(node, nodes.And):
                return eval_node(node.left) and eval_node(node.right)
            elif isinstance(node, nodes.Or):
                return eval_node(node.left) or eval_node(node.right)
            elif isinstance(node, nodes.Not):
                return not eval_node(node.node)
            elif isinstance(node, nodes.Name):
                return self.tags.get(, False)
                raise ValueError('invalid node, check parsing')

        return eval_node(expr)