Skip to content

Commit

Permalink
Starting to put some framework in place.
Browse files Browse the repository at this point in the history
  • Loading branch information
petrilli committed May 20, 2017
1 parent 7c10c8b commit 6daa726
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 13 deletions.
6 changes: 5 additions & 1 deletion pyrules/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# -*- coding: utf-8 -*-

__author__ = """Christopher Petrilli"""
__email__ = 'petrilli@amber.org'
__version__ = '0.1.0'
__all__ = [
'engine',
'memory',
'rules',
]
1 change: 1 addition & 0 deletions pyrules/engine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# -*- coding: utf-8 -*-
47 changes: 36 additions & 11 deletions pyrules/memory.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,40 @@
# -*- coding: utf-8 -*-
"""Working Memory
From the OPS5 design: Working memory is a global, dynamic user workspace that contains
information about a problem and the current state of its solution.
Information is stored in working memory as objects that are organized by
class. Each working memory object (WMO) has a class
name and a list of associated attributes and their values. The class name
classifies the object according to the type of information it contains. The
attributes and their values describe the object's characteristics. (In
database terms, object classes are like tables and attributes are like
fields).
This is structured slightly differently as a
From the OPS5 design: Working memory is a global, dynamic user workspace
that contains information about a problem and the current state of its
solution. Information is stored in working memory as objects that are
organized by class. Each working memory object (WMO) has a class name and a
list of associated attributes and their values. The class name classifies
the object according to the type of information it contains. The attributes
and their values describe the object's characteristics. (In database terms,
object classes are like tables and attributes are like fields).
This is structured slightly differently as it leverages the attrs package
to provide a more transparent way to store data through attribute access.
"""
from copy import copy


class WorkingMemory(object):
"""Working memory is the placeholder for all things.
When initialized, it makes a copy of any provided ruleset and keeps its
own copy.
Attributes:
__rules (list): List of rules we are going to be working
with. This is done through a copy when initialized so we don't
end up having to deal with rules being modified on the fly.
"""
def __init__(self, rules):
"""Initialize the working memory for a run.
Args:
rules (List[Rule]): all of the Rule objects to deal with
"""
# Make a copy so we don't have to deal with potentially mutable
# rule sets.
self.__rules = copy(rules)
54 changes: 54 additions & 0 deletions pyrules/rules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
"""Rule definitions
Rules are the core of the system. They express specifically what we want
to happen as data is processed. The RuleEngine runs in a slightly modified
version of the OPS5 model, but Rules generally follow.
"""
from weakref import proxy
from .memory import WorkingMemory


class Rule(object):
"""Foundational rule object.
A Rule has a name, and it consists of a conditional test, often called
the left-hand side (LHS), and an action, often called the right-hand
side (RHS). The conditional test examines the WorkingMemory, and
decides whether it may need to take an action. The RuleEngine will
then execute the action of the Rule that it selects.
"""
__name__ = "Name of the Rule"

def __init__(self, working_memory):
"""Instantiate the rule.
We keep a weak-ref proxy to the WorkingMemory so that we don't create
any non-GCable garbage.
Args:
working_memory (WorkingMemory): In-flight work for this Rule
"""
self.__wm = proxy(working_memory)
super(Rule, self).__init__()


def condition(self):
"""Predicate to decide if this rule needs to be applied.
To do this, it should examine the in-flight instance of
WorkingMemory.
Returns:
bool: True if action should be taken, False otherwise
"""
raise NotImplemented

def action(self):
"""Take action on the working memory.
Returns:
bool: True if action succeeded and rule should be kept in, False
if the rule should be removed from consideration.
"""
raise NotImplemented
2 changes: 1 addition & 1 deletion requirements_dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ flake8==3.3.0
tox==2.7.0
coverage==4.4.1
Sphinx==1.6.1

twine~=1.8
pytest==3.0.7

0 comments on commit 6daa726

Please sign in to comment.