wc_rules/utils/validate.py
from collections import Counter, deque
from .collections import all_unique
from keyword import iskeyword
def validate_class(_obj,classes,prefix):
err = "{0} must be an instance of {1}"
assert isinstance(_obj,classes), err.format(prefix,classes)
def validate_dict(_dict,classes,prefix):
for k,v in _dict.items():
validate_class(v,classes,'{0} {1}'.format(prefix,k))
def validate_list(_list,classes,prefix):
for elem in _list:
validate_class(elem,classes,'{0} {1}'.format(prefix,elem))
def validate_set(_list,prefix):
err = "{0} must be unique."
assert len(_list) == len(set(_list)), err.format(prefix)
def validate_unique(master,child,prefix):
for x in child:
err = "Cannot use `{0}` for {1} as it already exists in the namespace."
assert x not in master, err.format(x,prefix)
def validate_contains(master,child,prefix):
for x in child:
err = "{0} named `{1}` does not exist."
assert x in master, err.format(prefix,x)
def validate_acyclic(kwdeps):
cycle = check_cycle(kwdeps)
err = "Cyclical dependency found: {0}."
assert len(cycle)==0, err.format(cycle)
def validate_keywords(_list,prefix):
for x in _list:
err = "`{0}` is not a valid {1} name."
assert isinstance(x,str) and x.isidentifier() and not iskeyword(x), err.format(x,prefix)
def validate_literal_attribute(node,attr):
node.__class__.Meta.attributes[attr].check_value(node.get(attr))
def validate_literal_attributes(node):
for attr in node.get_literal_attributes(ignore_id=False,ignore_None=True):
validate_literal_attribute(node,attr)
def validate_related_attribute(node,attr):
x = node.__class__.Meta.local_attributes[attr]
classes = node.get_related_class(attr)
targets = node.listget(attr)
for target in targets:
validate_class(target,classes,'Target of related attribute {0} of class {1}'.format(attr,node.__class__))
# validate only max
if x.is_primary:
max_related = node.__class__.Meta.attributes[attr].max_related
else:
max_related = targets[0].__class__.Meta.attributes[node.get_related_name(attr)].max_related_rev
err = 'Targets of related attribute {0} of class {1} exceed max_related value {2}'
assert len(node.listget(attr)) <= max_related, err.format(attr,node.__class__,max_related)
def validate_related_attributes(node):
for attr in node.get_related_attributes(ignore_None=True):
validate_related_attribute(node,attr)
def validate_namespace(*args):
c = Counter()
for arg in args:
c.update(arg)
duplicates = [x for x in c if c[x]>1]
assert len(duplicates) == 0, 'Duplicates found: {0}'.format(duplicates)
def check_cycle(gdict):
# gdict is a directed graph represented as a dict
# node0: [node1, node2]
# node3: [node4]
nodes,paths = deque(gdict), deque()
while nodes or paths:
if not paths:
paths.append([nodes.popleft()])
path = paths.popleft()
if len(path)>1 and path[0]==path[-1]:
pathstr = '->'.join(path)
return pathstr
next_steps = gdict.get(path[-1],[])
if len(next_steps)>0:
paths.extend([path + [x] for x in next_steps])
return ''