Skip to content

Commit

Permalink
Validate method calls on variables
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsekar committed Feb 12, 2019
1 parent 3d80ce6 commit 2c01d52
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 15 deletions.
1 change: 1 addition & 0 deletions wc_rules/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,5 @@ def outer(self_obj,**kwargs):
kwargs[var] = getattr(self_obj,var)
return fn(**kwargs)
outer._isdynamic = True
outer._vars = fnvars
return outer
3 changes: 3 additions & 0 deletions wc_rules/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ def listget_all_related(self):
def get_related_name(self,attr):
return self.__class__.Meta.local_attributes[attr].related_name

def get_dynamic_methods(self):
return {x:getattr(self,x) for x in dir(self) if hasattr(getattr(self,x),'_isdynamic')}

def duplicate(self,id=None,preserve_id=False,attrlist=None):
''' duplicates node up to scalar attributes '''
new_node = self.__class__()
Expand Down
13 changes: 7 additions & 6 deletions wc_rules/expr2.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,13 @@ def get_dependencies(tree):
elif function_call_type == ('variable','function_name'):
var,func = [node_to_str(x) for x in ch]
deps['variables'].add(var)
deps['varfunctions'].add( (var,func,None) )
deps['varmethods'].add( (var,func,None) )
elif function_call_type == ('variable','function_name','kwargs'):
var,func,_ = [node_to_str(x) for x in ch]
kwargs = ch[2].children
kws = tuple(sorted([node_to_str(x.children[0]) for x in kwargs]))
deps['variables'].add(var)
deps['varfunctions'].add( (var,func,kws) )
deps['varmethods'].add( (var,func,kws) )
elif function_call_type in [('function_name','args'),('function_name',)]:
function_name = node_to_str(ch[0])
deps['builtins'].add(function_name)
Expand All @@ -257,6 +257,7 @@ def get_dependencies(tree):
deps['patterns'].add(pattern)
varpairs = node.children[0].children
pvars = []
lvars = []
for varpair in varpairs:
pvars.append(node_to_str(varpair.children[0]))
deps['patternvars'].add( tuple([pattern,tuple(pvars)]))
Expand All @@ -266,15 +267,15 @@ def get_dependencies(tree):
class BuiltinHook(object):
# this class holds the builtin functions accessible to expressions constraining patterns

allowed_functions = [
allowed_functions = set([
'abs', 'ceil', 'factorial', 'floor', 'exp', 'expm1', 'log', 'log1p', 'log2', 'log10',
'pow', 'sqrt', 'acos', 'asin', 'atan', 'atan2', 'cos', 'hypot', 'sin', 'tan', 'degrees', 'radians',
'max', 'min', 'sum', 'any', 'all', 'not',
]
])

allowed_constants = [
allowed_constants = set([
'pi','tau','avo',
]
])

abs = math.fabs
ceil = math.ceil
Expand Down
45 changes: 36 additions & 9 deletions wc_rules/pattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import random
import pprint
from collections import deque,defaultdict
from .graph_utils import build_simple_graph
from . import graph_utils as gr

class Pattern(DictLike):
def __init__(self,idx,nodelist=None,recurse=True):
Expand Down Expand Up @@ -53,17 +53,39 @@ def validate_dependencies(self):
final_deps = defaultdict(set)
final_deps['variables'] = set([x.id for x in self])

constants = BuiltinHook.allowed_constants
builtins = BuiltinHook.allowed_functions

for dep in deps:
print(dep)
# check variables
for var in sorted(dep['variables']):
if var not in final_deps['variables'] | final_deps['assignments']:
if var not in final_deps['variables'] | final_deps['assignments'] | constants:
raise ValidateError('Variable ' + var + ' not found in pattern ' + self.id)
for var,attr in sorted(dep['attributes']):
if attr not in self[var].get_literal_attributes():
raise ValidateError('Attribute ' + attr + ' not found in variable ' + var)
if var in final_deps['variables']:
if attr not in self[var].get_literal_attributes():
raise ValidateError('Attribute ' + attr + ' not found in variable ' + var)
for var, fname, kws in sorted(dep['varmethods']):
if var in final_deps['variables']:
fns_dict = self[var].get_dynamic_methods()
if fname not in fns_dict:
raise ValidateError('Method ' + fname + ' not found in variable ' + var)
fn = fns_dict[fname]
if kws is not None:
for kw in kws:
if kw not in fn._vars:
raise ValidateError('Keyword ' + kw + ' not found in method ' + var + '.' + fname)
for var in dep['assignments']:
final_deps['assignments'].add(var)
for fn in dep['builtins']:
if fn not in builtins:
raise ValidateError('Builtin function ' + fn + ' not found')


return final_deps

def finalize(self):
def validate_pattern_connectivity(self):
# ensure there are no neighbour nodes not in pattern
examined = set()

Expand All @@ -78,22 +100,27 @@ def finalize(self):

# ensure pattern is fully connected
assert sorted([x.id for x in examined])==sorted(self.keys())
return self

# ensure constraints can be parsed
def parse_constraints(self):
tree = parser.parse(self._constraints)
tree = prune_tree(tree)
modified = True
# simplify constraints as much as possible
while modified:
tree,modified = simplify_tree(tree)
# assign tree
self._tree = tree
return tree

def finalize(self):

self.validate_pattern_connectivity()
self._tree = self.parse_constraints()

# get reference & defined dependencies
compiled_deps = self.validate_dependencies()

# here we build a networkx graph to evaluate symmetry
g,helper = build_simple_graph(self)
g,helper = gr.build_simple_graph(self)

# use get dependencies to attach nodes referring to attributes & functions

Expand Down

0 comments on commit 2c01d52

Please sign in to comment.