Trivial: pep8 compliance tweaks

Change-Id: I3f6bf173cd46bd52f5723fec9792fe419b740df9
This commit is contained in:
Peter Balland 2014-01-09 09:37:26 -08:00
parent 61cf8aa973
commit 0340392fae
16 changed files with 875 additions and 683 deletions

View File

@ -16,4 +16,4 @@ import pbr.version
__version__ = pbr.version.VersionInfo(
'congress').version_string()
'congress').version_string()

View File

@ -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

View File

@ -15,8 +15,6 @@
import unittest
from policy import CongressParser
class TestCompiler(unittest.TestCase):

File diff suppressed because it is too large Load Diff

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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__)

View File

@ -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.

View File

@ -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())

View File

@ -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

View File

@ -25,4 +25,4 @@ from congress.tests import base
class TestCongress(base.TestCase):
def test_something(self):
pass
pass

View File

@ -19,4 +19,4 @@ import setuptools
setuptools.setup(
setup_requires=['pbr>=0.5.21,<1.0'],
pbr=True)
pbr=True)

View File

@ -18,9 +18,7 @@ deps = -r{toxinidir}/requirements.txt
commands = true
[testenv:pep8]
# TODO(pjb): reenable tests once cleaned up
#commands = flake8
commands = true
commands = flake8
[testenv:venv]
commands = {posargs}