Source code for ssg.boolean_expression

from ssg.ext.boolean import boolean
from ssg import requirement_specs

# We don't support ~= to avoid confusion with boolean operator NOT (~)
SPEC_SYMBOLS = ['<', '>', '=', '!', ',', '[', ']']
VERSION_SYMBOLS = ['.', '-', '_', ":"]


[docs] class Function(boolean.Function): """ Base class for boolean functions Subclass it and pass to the `Algebra` as `function_cls` to enrich expression elements with domain-specific methods. Provides `is_and`, `is_or` and `is_not` methods to distinguish instances between different boolean functions. The `as_id` method will generate a unique string identifier usable as an XML id based on the properties of the entity. """
[docs] def is_and(self): return isinstance(self, boolean.AND)
[docs] def is_or(self): return isinstance(self, boolean.OR)
[docs] def is_not(self): return isinstance(self, boolean.NOT)
[docs] def as_id(self): if self.is_not(): return 'not_{0}'.format(self.args[0].as_id()) op = 'unknown_bool_op' if self.is_and(): op = 'and' if self.is_or(): op = 'or' return '_{0}_'.format(op).join([arg.as_id() for arg in self.args])
[docs] class Symbol(boolean.Symbol): """ Base class for boolean symbols Subclass it and pass to the `Algebra` as `symbol_cls` to enrich expression elements with domain-specific methods. The `as_id` method will generate a unique string identifier usable as an XML id based on the properties of the entity. """ def __init__(self, obj): super(Symbol, self).__init__(obj) self.requirement = requirement_specs.Requirement(obj) self.obj = self.requirement def __call__(self, **kwargs): full_name = self.name if self.arg: full_name += '[' + self.arg + ']' val = kwargs.get(full_name, False) if self.requirement.has_version_specs(): if type(val) is str: return val in self.requirement return False return bool(val) def __hash__(self): return hash(self.as_id()) def __eq__(self, other): return hash(self) == hash(other) def __lt__(self, other): return self.as_id() < other.as_id()
[docs] def as_id(self): id_str = self.name if self.arg: id_str += '_' + self.arg if self.requirement.has_version_specs(): id_str += '_' + self.requirement.ver_specs.oval_id return id_str
[docs] def as_dict(self): res = { 'id': self.as_id(), 'name': self.name, 'arg': self.arg, 'ver_specs': [], 'ver_specs_id': '', 'ver_specs_cpe': '', 'ver_specs_title': '', } if self.requirement.has_version_specs(): for ver_spec in sorted(self.requirement.ver_specs): res['ver_specs'].append({ 'id': ver_spec.oval_id, 'op': ver_spec.op, 'ver': ver_spec.ver, 'evr_op': ver_spec.evr_op, 'evr_ver': ver_spec.evr_ver, 'ev_ver': ver_spec.ev_ver }) res['ver_specs_id'] = self.requirement.ver_specs.oval_id res['ver_specs_cpe'] = self.requirement.ver_specs.cpe_id res['ver_specs_title'] = self.requirement.ver_specs.title return res
[docs] def has_version_specs(self): return self.requirement.has_version_specs()
@property def arg(self): return self.requirement.arg or '' @property def name(self): return self.requirement.name
[docs] @staticmethod def is_parametrized(name): return requirement_specs.Requirement.is_parametrized(name)
[docs] @staticmethod def get_base_of_parametrized_name(name): return requirement_specs.Requirement.get_base_for_parametrized(name)
[docs] class Algebra(boolean.BooleanAlgebra): """ Base class for boolean algebra Algebra class will parse and evaluate boolean expressions, where operators could be any combination of "~, &, |, !, *, +, not, and, or" and variable symbols could contain version specifiers as described in PEP440 and PEP508. Limitations: - no white space is allowed inside specifier expressions; - ~= specifier operator is not supported. For example: "(oranges>=2.0.8,<=5 | fried[banana]) and !pie[apple]" """ def __init__(self, symbol_cls, function_cls): not_cls = type('FunctionNOT', (function_cls, boolean.NOT), {}) and_cls = type('FunctionAND', (function_cls, boolean.AND), {}) or_cls = type('FunctionOR', (function_cls, boolean.OR), {}) super(Algebra, self).__init__(allowed_in_token=VERSION_SYMBOLS+SPEC_SYMBOLS, Symbol_class=symbol_cls, NOT_class=not_cls, AND_class=and_cls, OR_class=or_cls)