Trivial: pep8 compliance tweaks
Change-Id: I3f6bf173cd46bd52f5723fec9792fe419b740df9
This commit is contained in:
parent
61cf8aa973
commit
0340392fae
|
@ -16,4 +16,4 @@ import pbr.version
|
|||
|
||||
|
||||
__version__ = pbr.version.VersionInfo(
|
||||
'congress').version_string()
|
||||
'congress').version_string()
|
||||
|
|
|
@ -15,16 +15,17 @@
|
|||
# under the License.
|
||||
#
|
||||
|
||||
import sys
|
||||
import copy
|
||||
import optparse
|
||||
import sys
|
||||
|
||||
import antlr3
|
||||
|
||||
import CongressLexer
|
||||
import CongressParser
|
||||
import antlr3
|
||||
import logging
|
||||
import copy
|
||||
|
||||
import runtime
|
||||
|
||||
|
||||
class CongressException (Exception):
|
||||
def __init__(self, msg, obj=None, line=None, col=None):
|
||||
Exception.__init__(self, msg)
|
||||
|
@ -37,12 +38,14 @@ class CongressException (Exception):
|
|||
s = " at" + s
|
||||
return Exception.__str__(self) + s
|
||||
|
||||
|
||||
##############################################################################
|
||||
## Internal representation of policy language
|
||||
##############################################################################
|
||||
|
||||
class Location (object):
|
||||
""" A location in the program source code. """
|
||||
"""A location in the program source code.
|
||||
"""
|
||||
def __init__(self, line=None, col=None, obj=None):
|
||||
self.line = None
|
||||
self.col = None
|
||||
|
@ -69,16 +72,19 @@ class Location (object):
|
|||
def __hash__(self):
|
||||
return hash(self.__repr__())
|
||||
|
||||
|
||||
class Term(object):
|
||||
""" Represents the union of Variable and ObjectConstant. Should
|
||||
only be instantiated via factory method. """
|
||||
"""Represents the union of Variable and ObjectConstant. Should
|
||||
only be instantiated via factory method.
|
||||
"""
|
||||
def __init__(self):
|
||||
assert False, "Cannot instantiate Term directly--use factory method"
|
||||
|
||||
@classmethod
|
||||
def create_from_python(cls, value, force_var=False):
|
||||
""" To create variable, FORCE_VAR needs to be true. There is currently
|
||||
no way to avoid this since variables are strings. """
|
||||
"""To create variable, FORCE_VAR needs to be true. There is currently
|
||||
no way to avoid this since variables are strings.
|
||||
"""
|
||||
if isinstance(value, Term):
|
||||
return value
|
||||
elif force_var:
|
||||
|
@ -92,8 +98,10 @@ class Term(object):
|
|||
else:
|
||||
assert False, "No Term corresponding to {}".format(repr(value))
|
||||
|
||||
|
||||
class Variable (Term):
|
||||
""" Represents a term without a fixed value. """
|
||||
"""Represents a term without a fixed value.
|
||||
"""
|
||||
def __init__(self, name, location=None):
|
||||
self.name = name
|
||||
self.location = location
|
||||
|
@ -120,8 +128,10 @@ class Variable (Term):
|
|||
def is_object(self):
|
||||
return False
|
||||
|
||||
|
||||
class ObjectConstant (Term):
|
||||
""" Represents a term with a fixed value. """
|
||||
"""Represents a term with a fixed value.
|
||||
"""
|
||||
STRING = 'STRING'
|
||||
FLOAT = 'FLOAT'
|
||||
INTEGER = 'INTEGER'
|
||||
|
@ -160,8 +170,10 @@ class ObjectConstant (Term):
|
|||
def is_object(self):
|
||||
return True
|
||||
|
||||
|
||||
class Atom (object):
|
||||
""" Represents an atomic statement, e.g. p(a, 17, b) """
|
||||
"""Represents an atomic statement, e.g. p(a, 17, b)
|
||||
"""
|
||||
def __init__(self, table, arguments, location=None):
|
||||
self.table = table
|
||||
self.arguments = arguments
|
||||
|
@ -169,14 +181,16 @@ class Atom (object):
|
|||
|
||||
@classmethod
|
||||
def create_from_table_tuple(cls, table, tuple):
|
||||
""" LIST is a python list representing an atom, e.g.
|
||||
['p', 17, "string", 3.14]. Returns the corresponding Atom. """
|
||||
"""LIST is a python list representing an atom, e.g.
|
||||
['p', 17, "string", 3.14]. Returns the corresponding Atom.
|
||||
"""
|
||||
return cls(table, [Term.create_from_python(x) for x in tuple])
|
||||
|
||||
@classmethod
|
||||
def create_from_iter(cls, list):
|
||||
""" LIST is a python list representing an atom, e.g.
|
||||
['p', 17, "string", 3.14]. Returns the corresponding Atom. """
|
||||
"""LIST is a python list representing an atom, e.g.
|
||||
['p', 17, "string", 3.14]. Returns the corresponding Atom.
|
||||
"""
|
||||
arguments = []
|
||||
for i in xrange(1, len(list)):
|
||||
arguments.append(Term.create_from_python(list[i]))
|
||||
|
@ -184,14 +198,14 @@ class Atom (object):
|
|||
|
||||
def __str__(self):
|
||||
return "{}({})".format(self.table,
|
||||
", ".join([str(x) for x in self.arguments]))
|
||||
", ".join([str(x) for x in self.arguments]))
|
||||
|
||||
def __eq__(self, other):
|
||||
return (isinstance(other, Atom) and
|
||||
self.table == other.table and
|
||||
len(self.arguments) == len(other.arguments) and
|
||||
all(self.arguments[i] == other.arguments[i]
|
||||
for i in xrange(0, len(self.arguments))))
|
||||
for i in xrange(0, len(self.arguments))))
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
|
@ -238,7 +252,7 @@ class Atom (object):
|
|||
return new
|
||||
else:
|
||||
args = [Term.create_from_python(binding.apply(arg, caller))
|
||||
for arg in self.arguments]
|
||||
for arg in self.arguments]
|
||||
new.arguments = args
|
||||
return new
|
||||
|
||||
|
@ -246,13 +260,14 @@ class Atom (object):
|
|||
return tuple([arg.name for arg in self.arguments])
|
||||
|
||||
def make_positive(self):
|
||||
""" Does NOT make copy """
|
||||
"""Does NOT make copy."""
|
||||
return self
|
||||
|
||||
def invert_update(self):
|
||||
""" If end of table name is + or -, return a copy after switching
|
||||
the copy's sign.
|
||||
Does not make a copy if table name does not end in + or -. """
|
||||
"""If end of table name is + or -, return a copy after switching
|
||||
the copy's sign.
|
||||
Does not make a copy if table name does not end in + or -.
|
||||
"""
|
||||
if self.table.endswith('+'):
|
||||
suffix = '-'
|
||||
elif self.table.endswith('-'):
|
||||
|
@ -268,8 +283,9 @@ class Atom (object):
|
|||
return new
|
||||
|
||||
def drop_update(self):
|
||||
""" If end of table name is + or -, return a copy without the sign.
|
||||
If table name does not end in + or -, make no copy. """
|
||||
"""If end of table name is + or -, return a copy without the sign.
|
||||
If table name does not end in + or -, make no copy.
|
||||
"""
|
||||
if self.table.endswith('+') or self.table.endswith('-'):
|
||||
new = copy.copy(self)
|
||||
new.table = new.table[:-1]
|
||||
|
@ -288,8 +304,10 @@ class Atom (object):
|
|||
def tablename(self):
|
||||
return self.table
|
||||
|
||||
|
||||
class Literal(Atom):
|
||||
""" Represents either a negated atom or an atom. """
|
||||
"""Represents either a negated atom or an atom.
|
||||
"""
|
||||
def __init__(self, table, arguments, negated=False, location=None):
|
||||
Atom.__init__(self, table, arguments, location=location)
|
||||
self.negated = negated
|
||||
|
@ -326,19 +344,20 @@ class Literal(Atom):
|
|||
return False
|
||||
|
||||
def complement(self):
|
||||
""" Copies SELF and inverts is_negated. """
|
||||
"""Copies SELF and inverts is_negated."""
|
||||
new = copy.copy(self)
|
||||
new.negated = not new.negated
|
||||
return new
|
||||
|
||||
def make_positive(self):
|
||||
""" Copies SELF and makes is_negated False. """
|
||||
"""Copies SELF and makes is_negated False."""
|
||||
new = copy.copy(self)
|
||||
new.negated = False
|
||||
return new
|
||||
|
||||
|
||||
class Rule (object):
|
||||
""" Represents a rule, e.g. p(x) :- q(x). """
|
||||
"""Represents a rule, e.g. p(x) :- q(x)."""
|
||||
def __init__(self, head, body, location=None):
|
||||
# self.head is self.heads[0]
|
||||
# Keep self.head around since a rule with multiple
|
||||
|
@ -435,15 +454,17 @@ class Rule (object):
|
|||
|
||||
|
||||
def formulas_to_string(formulas):
|
||||
""" Takes an iterable of compiler sentence objects and returns a
|
||||
"""Takes an iterable of compiler sentence objects and returns a
|
||||
string representing that iterable, which the compiler will parse
|
||||
into the original iterable. """
|
||||
into the original iterable.
|
||||
"""
|
||||
if formulas is None:
|
||||
return "None"
|
||||
return " ".join([str(formula) for formula in formulas])
|
||||
|
||||
|
||||
def is_update(x):
|
||||
""" Returns T iff x is a formula or tablename representing an update. """
|
||||
"""Returns T iff x is a formula or tablename representing an update."""
|
||||
if isinstance(x, basestring):
|
||||
return x.endswith('+') or x.endswith('-')
|
||||
elif isinstance(x, Atom):
|
||||
|
@ -453,9 +474,11 @@ def is_update(x):
|
|||
else:
|
||||
return False
|
||||
|
||||
|
||||
def is_result(x):
|
||||
""" Returns T iff x is a formula or tablename representing the result of
|
||||
an action invocation. """
|
||||
"""Returns T iff x is a formula or tablename representing the result of
|
||||
an action invocation.
|
||||
"""
|
||||
if isinstance(x, basestring):
|
||||
return x == 'result'
|
||||
elif isinstance(x, Atom):
|
||||
|
@ -471,14 +494,14 @@ def is_result(x):
|
|||
##############################################################################
|
||||
|
||||
class Compiler (object):
|
||||
""" Process Congress policy file. """
|
||||
"""Process Congress policy file."""
|
||||
def __init__(self):
|
||||
self.raw_syntax_tree = None
|
||||
self.theory = []
|
||||
self.errors = []
|
||||
self.warnings = []
|
||||
|
||||
def __str__ (self):
|
||||
def __str__(self):
|
||||
s = ""
|
||||
s += '**Theory**\n'
|
||||
if self.theory is not None:
|
||||
|
@ -489,8 +512,8 @@ class Compiler (object):
|
|||
|
||||
def read_source(self, input, input_string=False):
|
||||
# parse input file and convert to internal representation
|
||||
self.raw_syntax_tree = CongressSyntax.parse_file(input,
|
||||
input_string=input_string)
|
||||
self.raw_syntax_tree = CongressSyntax.parse_file(
|
||||
input, input_string=input_string)
|
||||
# self.print_parse_result()
|
||||
self.theory = CongressSyntax.create(self.raw_syntax_tree)
|
||||
# print str(self)
|
||||
|
@ -511,14 +534,16 @@ class Compiler (object):
|
|||
def raise_errors(self):
|
||||
if len(self.errors) > 0:
|
||||
errors = [str(err) for err in self.errors]
|
||||
raise CongressException('Compiler found errors:' + '\n'.join(errors))
|
||||
raise CongressException(
|
||||
'Compiler found errors:' + '\n'.join(errors))
|
||||
|
||||
|
||||
##############################################################################
|
||||
## External syntax: datalog
|
||||
##############################################################################
|
||||
|
||||
class CongressSyntax (object):
|
||||
""" External syntax and converting it into internal representation. """
|
||||
class CongressSyntax(object):
|
||||
"""External syntax and converting it into internal representation."""
|
||||
|
||||
class Lexer(CongressLexer.CongressLexer):
|
||||
def __init__(self, char_stream, state=None):
|
||||
|
@ -560,10 +585,10 @@ class CongressSyntax (object):
|
|||
result = parser.prog()
|
||||
if len(lexer.error_list) > 0:
|
||||
raise CongressException("Lex failure.\n" +
|
||||
"\n".join(lexer.error_list))
|
||||
"\n".join(lexer.error_list))
|
||||
if len(parser.error_list) > 0:
|
||||
raise CongressException("Parse failure.\n" + \
|
||||
"\n".join(parser.error_list))
|
||||
raise CongressException("Parse failure.\n" +
|
||||
"\n".join(parser.error_list))
|
||||
return result.tree
|
||||
|
||||
@classmethod
|
||||
|
@ -589,7 +614,7 @@ class CongressSyntax (object):
|
|||
heads = cls.create_and(antlr.children[0])
|
||||
body = cls.create_and(antlr.children[1])
|
||||
loc = Location(line=antlr.children[0].token.line,
|
||||
col=antlr.children[0].token.charPositionInLine)
|
||||
col=antlr.children[0].token.charPositionInLine)
|
||||
return Rule(heads, body, location=loc)
|
||||
|
||||
@classmethod
|
||||
|
@ -624,7 +649,7 @@ class CongressSyntax (object):
|
|||
for i in xrange(1, len(antlr.children)):
|
||||
args.append(cls.create_term(antlr.children[i]))
|
||||
loc = Location(line=antlr.children[0].token.line,
|
||||
col=antlr.children[0].token.charPositionInLine)
|
||||
col=antlr.children[0].token.charPositionInLine)
|
||||
return (table, args, loc)
|
||||
|
||||
@classmethod
|
||||
|
@ -641,10 +666,10 @@ class CongressSyntax (object):
|
|||
# (TYPE (VALUE))
|
||||
op = antlr.getText()
|
||||
loc = Location(line=antlr.children[0].token.line,
|
||||
col=antlr.children[0].token.charPositionInLine)
|
||||
col=antlr.children[0].token.charPositionInLine)
|
||||
if op == 'STRING_OBJ':
|
||||
value = antlr.children[0].getText()
|
||||
return ObjectConstant(value[1:len(value) - 1], # prune quotes
|
||||
return ObjectConstant(value[1:len(value) - 1], # prune quotes
|
||||
ObjectConstant.STRING,
|
||||
location=loc)
|
||||
elif op == 'INTEGER_OBJ':
|
||||
|
@ -663,9 +688,10 @@ class CongressSyntax (object):
|
|||
|
||||
|
||||
def print_tree(tree, text, kids, ind=0):
|
||||
""" Print out TREE using function TEXT to extract node description and
|
||||
function KIDS to compute the children of a given node.
|
||||
IND is a number representing the indentation level. """
|
||||
"""Print out TREE using function TEXT to extract node description and
|
||||
function KIDS to compute the children of a given node.
|
||||
IND is a number representing the indentation level.
|
||||
"""
|
||||
print "|" * ind,
|
||||
print "{}".format(str(text(tree)))
|
||||
children = kids(tree)
|
||||
|
@ -673,29 +699,36 @@ def print_tree(tree, text, kids, ind=0):
|
|||
for child in children:
|
||||
print_tree(child, text, kids, ind + 1)
|
||||
|
||||
|
||||
##############################################################################
|
||||
## Mains
|
||||
##############################################################################
|
||||
|
||||
def parse(policy_string):
|
||||
""" Run compiler on policy string and return the parsed formulas. """
|
||||
"""Run compiler on policy string and return the parsed formulas."""
|
||||
compiler = get_compiler([policy_string, '--input_string'])
|
||||
return compiler.theory
|
||||
|
||||
|
||||
def parse1(policy_string):
|
||||
""" Run compiler on policy string and return 1st parsed formula. """
|
||||
"""Run compiler on policy string and return 1st parsed formula."""
|
||||
return parse(policy_string)[0]
|
||||
|
||||
|
||||
def parse_file(filename):
|
||||
""" Run compiler on policy stored in FILENAME and return the parsed formulas. """
|
||||
"""Run compiler on policy stored in FILENAME and return the parsed
|
||||
formulas.
|
||||
"""
|
||||
compiler = get_compiler([filename])
|
||||
return compiler.theory
|
||||
|
||||
|
||||
def get_compiler(args):
|
||||
""" Run compiler as per ARGS and return the compiler object. """
|
||||
"""Run compiler as per ARGS and return the compiler object."""
|
||||
# assumes script name is not passed
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option("--input_string", dest="input_string", default=False,
|
||||
parser.add_option(
|
||||
"--input_string", dest="input_string", default=False,
|
||||
action="store_true",
|
||||
help="Indicates that inputs should be treated not as file names but "
|
||||
"as the contents to compile")
|
||||
|
@ -707,8 +740,9 @@ def get_compiler(args):
|
|||
|
||||
|
||||
def get_runtime(args):
|
||||
""" Create runtime by running compiler as per ARGS and initializing runtime
|
||||
with result of compilation. """
|
||||
"""Create runtime by running compiler as per ARGS and initializing runtime
|
||||
with result of compilation.
|
||||
"""
|
||||
comp = get_compiler(args)
|
||||
run = runtime.Runtime(comp.delta_rules)
|
||||
tracer = runtime.Tracer()
|
||||
|
@ -717,12 +751,12 @@ def get_runtime(args):
|
|||
run.database.tracer = tracer
|
||||
return run
|
||||
|
||||
|
||||
def main(args):
|
||||
c = get_compiler(args)
|
||||
for formula in c.theory:
|
||||
print str(c)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
||||
|
||||
|
||||
main(sys.argv[1:])
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,8 +15,6 @@
|
|||
|
||||
import unittest
|
||||
|
||||
from policy import CongressParser
|
||||
|
||||
|
||||
class TestCompiler(unittest.TestCase):
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -16,21 +16,24 @@
|
|||
#
|
||||
|
||||
import logging
|
||||
import compile
|
||||
import uuid
|
||||
|
||||
import compile
|
||||
|
||||
|
||||
# A unifier designed for the bi_unify_atoms routine
|
||||
# which is used by a backward-chaining style datalog implementation.
|
||||
# Main goal: minimize memory allocation by manipulating only unifiers
|
||||
# to keep variable namespaces separate.
|
||||
|
||||
class BiUnifier(object):
|
||||
""" A unifier designed for bi_unify_atoms. Recursive
|
||||
datastructure. When adding a binding variable u to
|
||||
variable v, keeps a reference to the unifier for v.
|
||||
A variable's identity is its name plus its unification context.
|
||||
This enables a variable with the same name but from two
|
||||
different atoms to be treated as different variables. """
|
||||
"""A unifier designed for bi_unify_atoms. Recursive
|
||||
datastructure. When adding a binding variable u to
|
||||
variable v, keeps a reference to the unifier for v.
|
||||
A variable's identity is its name plus its unification context.
|
||||
This enables a variable with the same name but from two
|
||||
different atoms to be treated as different variables.
|
||||
"""
|
||||
class Value(object):
|
||||
def __init__(self, value, unifier):
|
||||
# actual value
|
||||
|
@ -97,10 +100,11 @@ class BiUnifier(object):
|
|||
return self.apply_full(term, caller=caller)[0]
|
||||
|
||||
def apply_full(self, term, caller=None):
|
||||
""" Recursively apply unifiers to TERM and return
|
||||
(i) the final value and (ii) the final unifier.
|
||||
If the final value is a variable, instantiate
|
||||
with a new variable if not in KEEP_VARS """
|
||||
"""Recursively apply unifiers to TERM and return
|
||||
(i) the final value and (ii) the final unifier.
|
||||
If the final value is a variable, instantiate
|
||||
with a new variable if not in KEEP_VARS
|
||||
"""
|
||||
# logging.debug("apply_full({}, {})".format(str(term), str(self)))
|
||||
val = self.value(term)
|
||||
if val is None:
|
||||
|
@ -139,7 +143,7 @@ class BiUnifier(object):
|
|||
s = repr(self)
|
||||
s += "={"
|
||||
s += ",".join(["{}:{}".format(str(var), str(val))
|
||||
for var, val in self.contents.iteritems()])
|
||||
for var, val in self.contents.iteritems()])
|
||||
s += "}"
|
||||
return s
|
||||
|
||||
|
@ -147,15 +151,16 @@ class BiUnifier(object):
|
|||
s = repr(self)
|
||||
s += "={"
|
||||
s += ",".join(["{}:{}".format(var, val.recur_str())
|
||||
for var, val in self.contents.iteritems()])
|
||||
for var, val in self.contents.iteritems()])
|
||||
s += "}"
|
||||
return s
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.contents == other.contents
|
||||
|
||||
|
||||
def binding_str(binding):
|
||||
""" Handles string conversion of either dictionary or Unifier. """
|
||||
"""Handles string conversion of either dictionary or Unifier."""
|
||||
if isinstance(binding, dict):
|
||||
s = ",".join(["{}: {}".format(str(var), str(val))
|
||||
for var, val in binding.iteritems()])
|
||||
|
@ -163,20 +168,23 @@ def binding_str(binding):
|
|||
else:
|
||||
return str(binding)
|
||||
|
||||
|
||||
def undo_all(changes):
|
||||
""" Undo all the changes in CHANGES. """
|
||||
"""Undo all the changes in CHANGES."""
|
||||
# logging.debug("undo_all({})".format(
|
||||
# "[" + ",".join([str(x) for x in changes]) + "]"))
|
||||
for change in changes:
|
||||
if change.unifier is not None:
|
||||
change.unifier.delete(change.var)
|
||||
|
||||
|
||||
def bi_unify_atoms(atom1, unifier1, atom2, unifier2):
|
||||
""" If possible, modify BiUnifier UNIFIER1 and BiUnifier UNIFIER2 so that
|
||||
ATOM1.plug(UNIFIER1) == ATOM2.plug(UNIFIER2).
|
||||
Returns None if not possible; otherwise, returns
|
||||
a list of changes to unifiers that can be undone
|
||||
with undo-all. May alter unifiers besides UNIFIER1 and UNIFIER2. """
|
||||
"""If possible, modify BiUnifier UNIFIER1 and BiUnifier UNIFIER2 so that
|
||||
ATOM1.plug(UNIFIER1) == ATOM2.plug(UNIFIER2).
|
||||
Returns None if not possible; otherwise, returns
|
||||
a list of changes to unifiers that can be undone
|
||||
with undo-all. May alter unifiers besides UNIFIER1 and UNIFIER2.
|
||||
"""
|
||||
# logging.debug("Unifying {} under {} and {} under {}".format(
|
||||
# str(atom1), str(unifier1), str(atom2), str(unifier2)))
|
||||
if atom1.table != atom2.table:
|
||||
|
@ -214,6 +222,7 @@ def bi_unify_atoms(atom1, unifier1, atom2, unifier2):
|
|||
return None
|
||||
return changes
|
||||
|
||||
|
||||
# def plug(atom, binding, withtable=False):
|
||||
# """ Returns a tuple representing the arguments to ATOM after having
|
||||
# applied BINDING to the variables in ATOM. """
|
||||
|
@ -222,15 +231,18 @@ def bi_unify_atoms(atom1, unifier1, atom2, unifier2):
|
|||
# else:
|
||||
# result = []
|
||||
# for i in xrange(0, len(atom.arguments)):
|
||||
# if atom.arguments[i].is_variable() and atom.arguments[i].name in binding:
|
||||
# if (atom.arguments[i].is_variable() and
|
||||
# atom.arguments[i].name in binding):
|
||||
# result.append(binding[atom.arguments[i].name])
|
||||
# else:
|
||||
# result.append(atom.arguments[i].name)
|
||||
# return tuple(result)
|
||||
|
||||
|
||||
def match_tuple_atom(tuple, atom):
|
||||
""" Returns a binding dictionary that when applied to ATOM's arguments
|
||||
gives exactly TUPLE, or returns None if no such binding exists. """
|
||||
"""Returns a binding dictionary that when applied to ATOM's arguments
|
||||
gives exactly TUPLE, or returns None if no such binding exists.
|
||||
"""
|
||||
if len(tuple) != len(atom.arguments):
|
||||
return None
|
||||
binding = {}
|
||||
|
@ -245,15 +257,19 @@ def match_tuple_atom(tuple, atom):
|
|||
binding[arg.name] = tuple[i]
|
||||
return binding
|
||||
|
||||
|
||||
def bi_var_equal(var1, unifier1, var2, unifier2):
|
||||
""" Returns True iff variable VAR1 in unifier UNIFIER1 is the same
|
||||
variable as VAR2 in UNIFIER2. """
|
||||
"""Returns True iff variable VAR1 in unifier UNIFIER1 is the same
|
||||
variable as VAR2 in UNIFIER2.
|
||||
"""
|
||||
return (var1 == var2 and unifier1 is unifier2)
|
||||
|
||||
|
||||
def same(formula1, formula2):
|
||||
""" Determine if FORMULA1 and FORMULA2 are the same up to a variable
|
||||
renaming. Treats FORMULA1 and FORMULA2 as having different
|
||||
variable namespaces. Returns None or the pair of unifiers. """
|
||||
"""Determine if FORMULA1 and FORMULA2 are the same up to a variable
|
||||
renaming. Treats FORMULA1 and FORMULA2 as having different
|
||||
variable namespaces. Returns None or the pair of unifiers.
|
||||
"""
|
||||
logging.debug("same({}, {})".format(str(formula1), str(formula2)))
|
||||
if isinstance(formula1, compile.Atom):
|
||||
if isinstance(formula2, compile.Rule):
|
||||
|
@ -285,11 +301,13 @@ def same(formula1, formula2):
|
|||
else:
|
||||
return None
|
||||
|
||||
|
||||
def same_atoms(atom1, unifier1, atom2, unifier2, bound2):
|
||||
""" Modifies UNIFIER1 and UNIFIER2 to demonstrate
|
||||
"""Modifies UNIFIER1 and UNIFIER2 to demonstrate
|
||||
that ATOM1 and ATOM2 are identical up to a variable renaming.
|
||||
Returns None if not possible or the list of changes if it is.
|
||||
BOUND2 is the set of variables already bound in UNIFIER2 """
|
||||
BOUND2 is the set of variables already bound in UNIFIER2
|
||||
"""
|
||||
def die():
|
||||
undo_all(changes)
|
||||
return None
|
||||
|
@ -332,10 +350,12 @@ def same_atoms(atom1, unifier1, atom2, unifier2, bound2):
|
|||
return die()
|
||||
return changes
|
||||
|
||||
|
||||
def instance(formula1, formula2):
|
||||
""" Determine if FORMULA1 is an instance of FORMULA2, i.e. if there is
|
||||
some binding that when applied to FORMULA1 results in FORMULA2.
|
||||
Returns None or a unifier. """
|
||||
"""Determine if FORMULA1 is an instance of FORMULA2, i.e. if there is
|
||||
some binding that when applied to FORMULA1 results in FORMULA2.
|
||||
Returns None or a unifier.
|
||||
"""
|
||||
logging.debug("instance({}, {})".format(str(formula1), str(formula2)))
|
||||
if isinstance(formula1, compile.Atom):
|
||||
if isinstance(formula2, compile.Rule):
|
||||
|
@ -364,10 +384,12 @@ def instance(formula1, formula2):
|
|||
else:
|
||||
return None
|
||||
|
||||
|
||||
def instance_atoms(atom1, atom2, unifier2):
|
||||
""" Adds bindings to UNIFIER2 to make ATOM1 equal to ATOM2
|
||||
after applying UNIFIER2 to ATOM2 only. Returns None if
|
||||
no such bindings make equality hold. """
|
||||
"""Adds bindings to UNIFIER2 to make ATOM1 equal to ATOM2
|
||||
after applying UNIFIER2 to ATOM2 only. Returns None if
|
||||
no such bindings make equality hold.
|
||||
"""
|
||||
def die():
|
||||
undo_all(changes)
|
||||
return None
|
||||
|
@ -408,8 +430,9 @@ def instance_atoms(atom1, atom2, unifier2):
|
|||
|
||||
|
||||
def skolemize(formulas):
|
||||
""" Given a list of formulas, instantiate all variables
|
||||
consistently with UUIDs. """
|
||||
"""Given a list of formulas, instantiate all variables
|
||||
consistently with UUIDs.
|
||||
"""
|
||||
# create binding then plug it in.
|
||||
variables = set()
|
||||
for formula in formulas:
|
||||
|
|
|
@ -66,7 +66,7 @@ class UserGroupDataModel(object):
|
|||
ldap.INVALID_CREDENTIALS
|
||||
XXX: probably a bunch of ther ldap exceptions
|
||||
"""
|
||||
# TODO: rewrite to be scalable, robust
|
||||
# TODO(pjb): rewrite to be scalable, robust
|
||||
#vlog.dbg('Updating users from AD')
|
||||
l = ldap.initialize(LDAP_URI)
|
||||
l.simple_bind_s(BIND_USER, BIND_PW)
|
||||
|
@ -107,7 +107,6 @@ class UserGroupDataModel(object):
|
|||
self.items[new_id] = (user, group)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
ovs.vlog.add_args(parser)
|
||||
|
@ -122,13 +121,12 @@ def main():
|
|||
time.sleep(3)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
main()
|
||||
except SystemExit:
|
||||
# Let system.exit() calls complete normally
|
||||
raise
|
||||
except:
|
||||
except Exception:
|
||||
vlog.exception("traceback")
|
||||
sys.exit(ovs.daemon.RESTART_EXIT_CODE)
|
||||
|
|
|
@ -62,13 +62,13 @@ def main():
|
|||
api.register_handler(table_element_handler)
|
||||
|
||||
rows_model = SimpleDataModel()
|
||||
#TODO: scope model per table
|
||||
#TODO(pjb): scope model per table
|
||||
rows_collection_handler = RowCollectionHandler('/tables/([^/]+)/rows',
|
||||
rows_model)
|
||||
api.register_handler(rows_collection_handler)
|
||||
rows_element_handler = RowElementHandler(
|
||||
'/tables/([^/]+)/rows/([^/]+)', rows_model,
|
||||
rows_collection_handler)
|
||||
'/tables/([^/]+)/rows/([^/]+)', rows_model,
|
||||
rows_collection_handler)
|
||||
api.register_handler(rows_element_handler)
|
||||
|
||||
policy_model = PolicyDataModel()
|
||||
|
@ -76,24 +76,25 @@ def main():
|
|||
api.register_handler(policy_element_handler)
|
||||
|
||||
ad_model = UserGroupDataModel()
|
||||
|
||||
def ad_update_thread():
|
||||
while True:
|
||||
ad_model.update_from_ad() # XXX: blocks eventlet
|
||||
time.sleep(3)
|
||||
|
||||
wsgi_server.pool.spawn_n(ad_update_thread)
|
||||
|
||||
ad_row_handler = CollectionHandler( '/tables/ad-groups/rows', ad_model)
|
||||
ad_row_handler = CollectionHandler('/tables/ad-groups/rows', ad_model)
|
||||
api.register_handler(ad_row_handler, 0)
|
||||
# Add static tables to model
|
||||
tables_model.add_item({'sample': 'schema', 'id': 'ad-groups'}, 'ad-groups')
|
||||
|
||||
|
||||
vlog.info("Starting congress server")
|
||||
wsgi_server.start(api, args.http_listen_port,
|
||||
args.http_listen_addr)
|
||||
wsgi_server.wait()
|
||||
|
||||
#TODO: trigger watcher for policy outputs
|
||||
#TODO(pjb): trigger watcher for policy outputs
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -102,6 +103,6 @@ if __name__ == '__main__':
|
|||
except SystemExit:
|
||||
# Let system.exit() calls complete normally
|
||||
raise
|
||||
except:
|
||||
except Exception:
|
||||
vlog.exception("traceback")
|
||||
sys.exit(ovs.daemon.RESTART_EXIT_CODE)
|
||||
|
|
|
@ -116,7 +116,7 @@ class AbstractApiHandler(object):
|
|||
class ElementHandler(AbstractApiHandler):
|
||||
"""API handler for REST element resources.
|
||||
"""
|
||||
#TODO: validation
|
||||
#TODO(pjb): validation
|
||||
|
||||
def __init__(self, path_regex, model, collection_handler=None):
|
||||
"""Initialize an element handler.
|
||||
|
@ -138,7 +138,7 @@ class ElementHandler(AbstractApiHandler):
|
|||
def _get_element_id(self, request):
|
||||
m = self.path_re.match(request.path)
|
||||
if m.groups():
|
||||
return m.groups()[-1] #TODO: make robust
|
||||
return m.groups()[-1] # TODO(pjb): make robust
|
||||
return None
|
||||
|
||||
def handle_request(self, request):
|
||||
|
@ -220,7 +220,7 @@ class ElementHandler(AbstractApiHandler):
|
|||
class CollectionHandler(AbstractApiHandler):
|
||||
"""API handler for REST collection resources.
|
||||
"""
|
||||
#TODO: validation
|
||||
#TODO(pjb): validation
|
||||
|
||||
def __init__(self, path_regex, model, allow_named_create=True):
|
||||
"""Initialize a collection handler.
|
||||
|
@ -267,7 +267,7 @@ class CollectionHandler(AbstractApiHandler):
|
|||
|
||||
return webob.Response(body=json.dumps(item), status=httplib.CREATED,
|
||||
content_type='application/json',
|
||||
location="%s/%s" %(request.path, id_))
|
||||
location="%s/%s" % (request.path, id_))
|
||||
|
||||
|
||||
class RowCollectionHandler(CollectionHandler):
|
||||
|
@ -282,11 +282,10 @@ class RowElementHandler(ElementHandler):
|
|||
m = self.path_re.match(request.path)
|
||||
print 'groups', m.groups()
|
||||
if m.groups():
|
||||
return m.groups()[-1] #TODO: make robust
|
||||
return m.groups()[-1] # TODO(pjb): make robust
|
||||
return None
|
||||
|
||||
|
||||
|
||||
class SimpleDataModel(object):
|
||||
"""An in-memory data model.
|
||||
"""
|
||||
|
@ -369,8 +368,6 @@ class SimpleDataModel(object):
|
|||
return ret
|
||||
|
||||
|
||||
|
||||
|
||||
class PolicyDataModel(object):
|
||||
"""An in-memory policy data model.
|
||||
"""
|
||||
|
@ -384,5 +381,3 @@ class PolicyDataModel(object):
|
|||
def update_item(self, id_, item):
|
||||
self.rules = item['rules']
|
||||
return self.get_item(None)
|
||||
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@ import time
|
|||
|
||||
import eventlet.wsgi
|
||||
eventlet.patcher.monkey_patch(all=False, socket=True)
|
||||
import webob.dec
|
||||
|
||||
import ovs.vlog
|
||||
vlog = ovs.vlog.Vlog(__name__)
|
||||
|
|
|
@ -10,4 +10,4 @@
|
|||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
# under the License.
|
||||
|
|
|
@ -50,4 +50,4 @@ class TestCase(testtools.TestCase):
|
|||
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
|
||||
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
|
||||
|
||||
self.log_fixture = self.useFixture(fixtures.FakeLogger())
|
||||
self.log_fixture = self.useFixture(fixtures.FakeLogger())
|
||||
|
|
|
@ -182,8 +182,8 @@ class TestTablesApi(AbstractApiTest):
|
|||
def test_read_invalid(self):
|
||||
self.hconn.request('GET', '/tables/%s' % uuid.uuid4())
|
||||
r = self.hconn.getresponse()
|
||||
body = self.check_json_response(r, 'Read missing table',
|
||||
status=httplib.NOT_FOUND)
|
||||
self.check_json_response(r, 'Read missing table',
|
||||
status=httplib.NOT_FOUND)
|
||||
|
||||
def test_replace(self):
|
||||
id = None
|
||||
|
|
|
@ -25,4 +25,4 @@ from congress.tests import base
|
|||
class TestCongress(base.TestCase):
|
||||
|
||||
def test_something(self):
|
||||
pass
|
||||
pass
|
||||
|
|
2
setup.py
2
setup.py
|
@ -19,4 +19,4 @@ import setuptools
|
|||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr>=0.5.21,<1.0'],
|
||||
pbr=True)
|
||||
pbr=True)
|
||||
|
|
Loading…
Reference in New Issue