Commit 95919d11 authored by Mehrdad's avatar Mehrdad

added rulemall and solved initiation error

parent 5ece5fc8
from app.main import main
from app.main.utils.common import response_message
from flask import request
from rulemall import RulesGroup, Rule
from app.rulemall import RulesGroup, Rule
from app.main.utils.db_util import add_obj, return_obj, rm_obj, return_all_objs, return_project_rules
......
from app.main import main
from app.main.utils.common import response_message, read_data, read_rules, write_validations
from rulemall import RulesGroup
from app.rulemall import RulesGroup
import pandas as pd
......
from app.main import main
from app.main.utils.common import response_message
from flask import json
from rulemall.validators import *
from app.rulemall.validators import *
@main.route('/validators', methods=['GET', 'POST'])
......@@ -9,7 +9,7 @@ def validators():
vals = []
for val in [Range, Length, Category, Regex, Missing, Unique, Empty, Logic]:
v = val()
vals.append(json.loads(str(v)))
vals.append(json.loads(v.__repr__()))
return response_message(vals)
......
from .rules import *
import pandas as pd
from app.rulemall.validators import *
import json
class RuleSet:
def __init__(self, data, rule_groups=[]):
self.data = data
self.rule_groups = rule_groups
def to_dict(self):
output = []
for rule_group in self.rule_groups:
output.append(rule_group.to_dict())
return output
def from_dict(self, rule_groups):
self.rule_groups = []
for rule_group in rule_groups:
rg = RulesGroup()
rg.from_dict(rule_group)
rg.reset_data(self.data)
self.rule_groups.append(rg)
class RulesGroup:
def __init__(self, name='', data=None, rules=None, filters=None, by=None):
self.name = name
self.data = data
self.by = by
self.rules = rules
self.filters = filters
def __add__(self, rule):
self.rules = AndOperator([self.rules, rule])
def reset_data(self, data=None):
self.data = data
def validate(self):
if self.data is not None:
data = self.data
if self.filters:
filters, _ = self.filters.validate(data)
data = data.loc[filters]
if self.rules:
return self.rules.validate(data)
return None
def get_target(self):
if self.rules:
return self.rules.get_target()
def to_dict(self):
d = {'name': self.name, 'rules': [], 'filters': []}
for rule in self.rules:
d['rules'].append(rule.to_dict())
for f in self.filters:
d['filters'].append(f.to_dict())
return d
def reset_rules(self, rules):
self.rules = None
if 'AND' in rules:
a = AndOperator(operands=[])
elif 'OR' in rules:
a = OrOperator(operands=[])
else:
try:
a = Rule()
except Exception as e:
print(e)
raise TypeError(str(e))
try:
a.from_dict(rules.copy())
except Exception as e:
print(e)
raise TypeError(str(e))
self.rules = a
def reset_filters(self, filters):
self.filters = None
if 'AND' in filters:
a = AndOperator()
elif 'OR' in filters:
a = OrOperator()
else:
a = Rule()
try:
a.from_dict(filters.copy())
self.filters = a
except Exception as e:
print(e)
raise TypeError(str(e))
def from_dict(self, dct):
self.name = dct['name']
rules = dct['rules']
filters = dct.get('filters')
self.reset_rules(rules)
try:
self.reset_filters(filters)
except Exception:
self.filters = None
# TODO: complete from config method
# TODO: Add a method to return the names of all rules withing the object
# TODO: Get rule applicator from factory of adaptor
class Rule:
def __init__(self, name=None, target=None, validator=None, invert=False, orient='column'):
self.name = name
self.target = target
self.validator = validator
self.orient = orient
self.invert = invert
self.vdf = pd.DataFrame()
def validate(self, s):
if self.orient == 'column':
if self.invert:
self.vdf[self.name] = ~self.validator.validate(s[self.target])
self.vdf['responsible'] = self.vdf[self.name].apply(lambda x: [] if x else [self.name])
else:
self.vdf[self.name] = self.validator.validate(s[self.target])
self.vdf['responsible'] = self.vdf[self.name].apply(lambda x: [] if x else [self.name])
elif self.orient == 'record':
if self.invert:
self.vdf[self.name] = ~self.validator.validate(s)
self.vdf['responsible'] = self.vdf[self.name].apply(lambda x: [] if x else [self.name])
else:
self.vdf[self.name] = self.validator.validate(s)
self.vdf['responsible'] = self.vdf[self.name].apply(lambda x: [] if x else [self.name])
return self.vdf[self.name], self.vdf['responsible']
def get_target(self):
return self.target
def to_dict(self):
d = self.validator.to_dict()
d['rule_attributes'] = {"name": self.name, "target": self.target, "orient": self.orient, "invert": self.invert}
return d
def from_dict(self, dct):
rule_type = dct['rule_type']
if rule_type == 'Range':
validator = Range(**dct['validator_parameters'])
elif rule_type == 'Regex':
validator = Regex(**dct['validator_parameters'])
elif rule_type == 'Length':
validator = Length(**dct['validator_parameters'])
elif rule_type == 'Unique':
validator = Unique(**dct['validator_parameters'])
elif rule_type == 'Category':
validator = Category(**dct['validator_parameters'])
elif rule_type == 'Compare':
validator = Compare(**dct['validator_parameters'])
elif rule_type == 'Empty':
validator = Empty()
elif rule_type == 'Logic':
validator = Logic(**dct['validator_parameters'])
else:
raise NotImplementedError
self.validator = validator
self.name = dct['rule_attributes']['name']
self.target = dct['rule_attributes']['target']
self.invert = dct['rule_attributes'].get('invert', False)
self.orient = dct['rule_attributes'].get('orient', 'column')
if isinstance(self.invert, str):
self.invert = json.loads(self.invert)
class OperatorBaseClass(metaclass=ABCMeta):
def __init__(self, operands=[]):
self.operands = operands
@staticmethod
def operation(data, other):
raise NotImplementedError
def get_target(self):
columns = []
for op in self.operands:
a = op.get_target()
if isinstance(a, list):
columns.extend(a)
else:
columns.append(a)
return columns
def validate(self, data):
if self.operands:
t, r = self.operands[0].validate(data)
for op in self.operands[1:]:
v1, v2 = op.validate(data)
r = pd.concat([r, v2.rename('r')], axis=1)
t = self.operation(t, v1)
r.loc[t, 'responsible'] = r.loc[t, 'responsible'].apply(lambda x: [])
r.loc[~t].apply(lambda x: x['responsible'].extend(x['r']), axis=1)
r.loc[~t, 'responsible'] = r.loc[~t, 'responsible'].apply(lambda x: list(set(x)))
r = r['responsible']
return t, r
else:
return None, None
def _to_dict(self):
res = []
for op in self.operands:
res.append(op.to_dict())
return res
def _from_dict(self, dct):
for op in dct:
if 'AND' in op:
a = AndOperator([])
elif 'OR' in op:
a = OrOperator([])
else:
try:
a = Rule()
except Exception as e:
print(e)
raise TypeError('Not a Rule!')
a.from_dict(op.copy())
self.operands.append(a)
class OrOperator(OperatorBaseClass):
@staticmethod
def operation(data, other):
return data | other
def to_dict(self):
return {'OR': self._to_dict()}
def from_dict(self, dct):
dct = dct['OR'].copy()
self._from_dict(dct)
class AndOperator(OperatorBaseClass):
@staticmethod
def operation(data, other):
return data & other
def to_dict(self):
return {'AND': self._to_dict()}
def from_dict(self, dct):
dct = dct['AND'].copy()
self._from_dict(dct)
from functools import wraps
from time import time
def timing(f):
@wraps(f)
def wrap(*args, **kwargs):
ts = time()
result = f(*args, **kwargs)
te = time()
print(f'func: {f.__name__} took {te-ts} seconds.')
return result
return wrap
from rulemall.validators import Range, Unique, Regex, Length, Category
from rulemall.rules import Rule
import json
import yaml
def rule_builder(configs):
if isinstance(configs, list):
output = []
for config in configs:
output.append(config_reader(config))
elif isinstance(configs, dict):
return config_reader(configs)
else:
return TypeError
def config_reader(configs):
name = configs.get('name')
rules = list(map(define_rule, [config for config in configs['rules']]))
rules = list(filter(lambda rule: rule is not None, rules))
return {'rules': rules, 'name': name}
def define_rule(config):
rule_type = config['rule_type']
if rule_type == 'Range':
validator = Range(**config['validator_parameters'])
elif rule_type == 'Regex':
validator = Regex(**config['validator_parameters'])
elif rule_type == 'Length':
validator = Length(**config['validator_parameters'])
elif rule_type == 'Unique':
validator = Unique(**config['validator_parameters'])
elif rule_type == 'Category':
validator = Category(**config['validator_parameters'])
else:
return None
rule = Rule(validator=validator, **config['rule_attributes'])
return rule
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment