[Pyple-commits] SF.net SVN: pyple: [1]
Status: Pre-Alpha
Brought to you by:
anseljh
From: <an...@us...> - 2006-04-11 01:41:28
|
Revision: 1 Author: anseljh Date: 2006-04-10 18:41:15 -0700 (Mon, 10 Apr 2006) ViewCVS: http://svn.sourceforge.net/pyple/?rev=1&view=rev Log Message: ----------- initial commit of all pre-SF code Added Paths: ----------- db/ db/mysql/ db/mysql/pyple_dev.sql src/ src/Code.py src/Element.py src/Expression.py src/Operator.py src/PyPLE.py src/PyPLEType.py src/__init__.py src/setup.py www/ Added: db/mysql/pyple_dev.sql =================================================================== --- db/mysql/pyple_dev.sql (rev 0) +++ db/mysql/pyple_dev.sql 2006-04-11 01:41:15 UTC (rev 1) @@ -0,0 +1,190 @@ +-- phpMyAdmin SQL Dump +-- version 2.6.0-pl2 +-- http://www.phpmyadmin.net +-- +-- Host: localhost +-- Generation Time: Apr 10, 2006 at 05:51 PM +-- Server version: 4.0.20 +-- PHP Version: 5.0.3 +-- +-- Database: `pyple_dev` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `blobs` +-- + +CREATE TABLE `blobs` ( + `id` int(7) NOT NULL auto_increment, + `content` blob NOT NULL, + PRIMARY KEY (`id`) +) TYPE=MyISAM COMMENT='Binary blobs (e.g. for code)' AUTO_INCREMENT=1 ; + +-- +-- Dumping data for table `blobs` +-- + + +-- -------------------------------------------------------- + +-- +-- Table structure for table `code` +-- + +CREATE TABLE `code` ( + `id` int(7) NOT NULL auto_increment, + `name` varchar(200) NOT NULL default '', + `content` text, + `type` enum('interpreted','binary','pickled') NOT NULL default 'interpreted', + `engine_id` int(7) NOT NULL default '0', + PRIMARY KEY (`id`) +) TYPE=MyISAM COMMENT='Code for running operators' AUTO_INCREMENT=6 ; + +-- +-- Dumping data for table `code` +-- + +INSERT INTO `code` VALUES (1, 'always_true', 'lambda LHS, RHS: True', 'interpreted', 2); +INSERT INTO `code` VALUES (2, 'multiply', 'lambda LHS, RHS: LHS * RHS', 'interpreted', 2); +INSERT INTO `code` VALUES (3, 'py_greater_than', 'lambda x, y: x > y', 'interpreted', 2); +INSERT INTO `code` VALUES (4, 'pi', 'def get_pi():\r\n import math\r\n return math.pi\r\nlambda x, y: get_pi()', 'interpreted', 2); +INSERT INTO `code` VALUES (5, 'magic_pi', 'def get_pi():\r\n import math\r\n return math.pi\r\nlambda: get_pi()', 'interpreted', 2); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `element` +-- + +CREATE TABLE `element` ( + `id` int(7) NOT NULL auto_increment, + `type_id` int(7) NOT NULL default '0', + `value` text NOT NULL, + `magic_code_id` int(7) default NULL, + `comment` varchar(250) NOT NULL default '', + PRIMARY KEY (`id`) +) TYPE=MyISAM COMMENT='Singular element of expression (e.g A in "(A and B)")' AUTO_INCREMENT=8 ; + +-- +-- Dumping data for table `element` +-- + +INSERT INTO `element` VALUES (1, 2, '1', NULL, 'True'); +INSERT INTO `element` VALUES (2, 2, '0', NULL, 'False'); +INSERT INTO `element` VALUES (3, 3, '2', NULL, '2'); +INSERT INTO `element` VALUES (4, 3, '3', NULL, '3'); +INSERT INTO `element` VALUES (5, 8, '', 5, 'pi'); +INSERT INTO `element` VALUES (6, 3, '1', NULL, '1'); +INSERT INTO `element` VALUES (7, 8, '4.5', NULL, '4.5'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `engine` +-- + +CREATE TABLE `engine` ( + `id` int(7) NOT NULL auto_increment, + `name` varchar(200) NOT NULL default '', + PRIMARY KEY (`id`) +) TYPE=MyISAM COMMENT='Engines for evaluating operators' AUTO_INCREMENT=5 ; + +-- +-- Dumping data for table `engine` +-- + +INSERT INTO `engine` VALUES (1, 'INTERNAL'); +INSERT INTO `engine` VALUES (2, 'python'); +INSERT INTO `engine` VALUES (3, 'shell'); +INSERT INTO `engine` VALUES (4, 'perl'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `expression` +-- + +CREATE TABLE `expression` ( + `id` int(7) NOT NULL auto_increment, + `op_id` int(7) NOT NULL default '0', + `lhs_id` int(7) NOT NULL default '0', + `lhs_type` int(7) NOT NULL default '0', + `rhs_id` int(7) NOT NULL default '0', + `rhs_type` int(7) NOT NULL default '0', + `output_type_id` int(7) NOT NULL default '0', + `comment` varchar(250) default NULL, + PRIMARY KEY (`id`) +) TYPE=MyISAM COMMENT='Simple 2-element expressions (e.g. (A not B))' AUTO_INCREMENT=8 ; + +-- +-- Dumping data for table `expression` +-- + +INSERT INTO `expression` VALUES (1, 1, 1, 2, 2, 2, 2, '(True and False)'); +INSERT INTO `expression` VALUES (2, 7, 2, 2, 2, 2, 2, 'always_true(False, False)'); +INSERT INTO `expression` VALUES (3, 6, 4, 3, 3, 3, 3, '(3 * 2)'); +INSERT INTO `expression` VALUES (4, 10, 0, 6, 0, 6, 8, 'pi(null, null)'); +INSERT INTO `expression` VALUES (5, 11, 5, 8, 6, 8, 8, '(pi * 1)'); +INSERT INTO `expression` VALUES (6, 11, 7, 8, 7, 8, 8, '(4.5^2)'); +INSERT INTO `expression` VALUES (7, 11, 5, 8, 6, 1, 8, '(pi * (4.5^2))'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `op` +-- + +CREATE TABLE `op` ( + `id` int(7) NOT NULL auto_increment, + `name` varchar(200) NOT NULL default '', + `engine_id` int(7) NOT NULL default '0', + `code_id` int(7) NOT NULL default '0', + `rhs_type_id` int(7) NOT NULL default '0', + `lhs_type_id` int(7) NOT NULL default '0', + `output_type_id` int(7) NOT NULL default '0', + PRIMARY KEY (`id`) +) TYPE=MyISAM COMMENT='Operators' AUTO_INCREMENT=12 ; + +-- +-- Dumping data for table `op` +-- + +INSERT INTO `op` VALUES (1, 'and', 1, 0, 2, 2, 2); +INSERT INTO `op` VALUES (2, 'or', 1, 0, 2, 2, 2); +INSERT INTO `op` VALUES (3, 'not', 1, 0, 2, 2, 2); +INSERT INTO `op` VALUES (4, 'xor', 1, 0, 2, 2, 2); +INSERT INTO `op` VALUES (5, 'nand', 1, 0, 2, 2, 2); +INSERT INTO `op` VALUES (6, 'multiply_integers', 2, 2, 3, 3, 3); +INSERT INTO `op` VALUES (7, 'always_true', 2, 1, 2, 2, 2); +INSERT INTO `op` VALUES (8, 'py_greater_than_int', 2, 3, 3, 3, 3); +INSERT INTO `op` VALUES (9, 'py_greater_than_float', 2, 3, 8, 8, 8); +INSERT INTO `op` VALUES (10, 'pi', 2, 4, 6, 6, 8); +INSERT INTO `op` VALUES (11, 'multiply_float', 2, 2, 8, 8, 8); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `type` +-- + +CREATE TABLE `type` ( + `id` int(7) NOT NULL auto_increment, + `name` varchar(100) NOT NULL default '', + PRIMARY KEY (`id`) +) TYPE=MyISAM COMMENT='Element types' AUTO_INCREMENT=10 ; + +-- +-- Dumping data for table `type` +-- + +INSERT INTO `type` VALUES (1, 'expression'); +INSERT INTO `type` VALUES (2, 'bool'); +INSERT INTO `type` VALUES (3, 'int'); +INSERT INTO `type` VALUES (4, 'str'); +INSERT INTO `type` VALUES (5, 'datetime'); +INSERT INTO `type` VALUES (6, 'null'); +INSERT INTO `type` VALUES (7, 'pickle'); +INSERT INTO `type` VALUES (8, 'float'); +INSERT INTO `type` VALUES (9, 'magic'); Added: src/Code.py =================================================================== --- src/Code.py (rev 0) +++ src/Code.py 2006-04-11 01:41:15 UTC (rev 1) @@ -0,0 +1,38 @@ +#!/usr/bin/env python +""" +PyPLE (say "pipple") -- the Python Persistent Logic Engine + +Code.py: Class representing arbitrary code for Operators + +Copyright (C) 2006 Ansel Halliburton. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the PyPLE Project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +class Code: + def __init__(self, p, pid): + """Construct a Code object from DB with pid""" + self.pyple = p + self.pid = pid + raise NotImplementedError Added: src/Element.py =================================================================== --- src/Element.py (rev 0) +++ src/Element.py 2006-04-11 01:41:15 UTC (rev 1) @@ -0,0 +1,74 @@ +#!/usr/bin/env python +""" +PyPLE (say "pipple") -- the Python Persistent Logic Engine + +Element.py: Class representing elements of expressions + +Copyright (C) 2006 Ansel Halliburton. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the PyPLE Project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +import PyPLEType +import Expression +import Code + +class Element: + def __init__(self, p, value): + self.pyple = p + print ":: Element constructor 2" + self.pid = None + self.magic = False + self.magic_code = None + self.type = PyPLEType(value) + + def __init__(self, value, magic_code_pid=None, pid=None): + print ":: Element constructor 1" + self.type = PyPLEType.PyPLEType.make_from_object(value) + self.value = value + self.magic = False + if magic_code_pid is not None: + self.magic = True + self.magic_code = Code.Code(magic_code_pid) + #TODO: figure out the magic + raise NotImplementedError("no magic handling yet") + if pid is not None: + self.pid = pid + + def eval(self): + if self.magic: + #TODO: figure out how to do magic element evaluation + pass + if self.type.name == 'str': + return str(self.value) + if self.type.name == 'int': + return int(self.value) + if self.type.name == 'expression': + return Expression.Expression(pid) + if self.type.name == 'int': + return int(self.value) + + def __str__(self): + """Return string representation of Element""" + return "Element of type " + str(self.type) + "; value = " + str(self.value) Added: src/Expression.py =================================================================== --- src/Expression.py (rev 0) +++ src/Expression.py 2006-04-11 01:41:15 UTC (rev 1) @@ -0,0 +1,78 @@ +#!/usr/bin/env python +""" +PyPLE (say "pipple") -- the Python Persistent Logic Engine + +Expression.py: Class representing simple expressions (comprised of two + Elements and one Operator) + +Copyright (C) 2006 Ansel Halliburton. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the PyPLE Project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +import Element +import types + +class Expression: + def __init__(self, op, LHS, RHS, pid=None): + self.op = op + self.LHS = LHS + self.RHS = RHS + self.pid = pid + + def __str__(self): + """ + Return string representation of an Expression + """ + return "Expression" #TODO: meaningful string representation + + def eval(self): + #define temp vars + L = None + R = None + + #check if expression; if so, evaluate recursively to reduce to Element + if type(self.LHS) is Expression: + L = self.LHS.eval() + else: + L = self.LHS + #reduce Element to bare datatype + if type(L) is Element.Element: + L = L.eval() + + #check if expression; if so, evaluate recursively to reduce to Element + if type(self.RHS) is Expression: + #if type(self.RHS) is types.InstanceType and self.RHS.__class__ is Expression: + print "!! found an expression" + R = self.RHS.eval() + else: + R = self.RHS + #reduce Element to bare datatype + #if type(R) is Element: + if type(R) is Element.Element: + print "!! found an Element" + R = R.eval() + + #perform operation and return Element + return self.op.eval(L, R) Added: src/Operator.py =================================================================== --- src/Operator.py (rev 0) +++ src/Operator.py 2006-04-11 01:41:15 UTC (rev 1) @@ -0,0 +1,84 @@ +#!/usr/bin/env python +""" +PyPLE (say "pipple") -- the Python Persistent Logic Engine + +Operator.py: Class representing Operators for evaluating Expressions + +Copyright (C) 2006 Ansel Halliburton. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the PyPLE Project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +import Element + +ENGINE_INTERNAL = 1 +ENGINE_PYTHON = 2 +ENGINE_SHELL = 3 +ENGINE_PERL = 4 + +class Operator: + + def __init__(self, p, name, engine, fn=None, code=None): + self.pyple = p + self.name = name + self.engine = engine + self.fn = fn + self.code = code + self.foo = 2 + self.bar = fn + + if self.engine == ENGINE_INTERNAL: + print "**", name, "is type internal" + self.fn = self.pyple.functions['name'][self.name] + elif self.engine == ENGINE_PYTHON: + print "**", name, "is type Python" + if self.code is not None: + print "** about to eval() Python code: ", code + self.fn = eval(code, {}, {}) #run Python eval() on code (in sandbox) + self.pyple.add_op_function(self.name, self.fn) + else: + raise ValueError("no code provided!") + else: + raise NotImplementedError("Perl, shell, and other types of operators not yet implemented") + print "** function: ", self.fn + self.pyple.add_operator(self.name, self) + + @staticmethod + def fetch(self, pid): + """Fetch an op from the DB by pid""" + raise NotImplementedError + + def eval(self, LHS, RHS): + """ + Perform an operation on LHS and RHS + Note: LHS and RHS are guaranteed to be Elements! + Returns: Element + """ + print "**Operator.eval() called." + if self.fn is None: + raise Exception("no function set!") + else: + fn = self.fn + val = fn(LHS.eval(), RHS.eval()) #reduce elements to bare datatypes + return Element.Element(val) Added: src/PyPLE.py =================================================================== --- src/PyPLE.py (rev 0) +++ src/PyPLE.py 2006-04-11 01:41:15 UTC (rev 1) @@ -0,0 +1,284 @@ +#!/usr/bin/env python +""" +PyPLE (say "pipple") -- the Python Persistent Logic Engine + +PyPLE.py: Main PyPLE class and simple test script + +Copyright (C) 2006 Ansel Halliburton. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the PyPLE Project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +NOTES +* PyPLE is lean and mean. Just say no to complexity! +* You can run this file to do some simple testing: python PyPLE.py + +HISTORY +v0.0.1 PyPLE was born in a flash of inspiration at L & L Hawaiian Barbecue in + Palo Alto, California on April 7, 2006. Version 0.1 was thrown together + more or less that night with the assistance of Nine Inch Nails and the + Komodo IDE. + +""" + +# Interesting tokens to look for in this source code: +# +# #TODO: Items that need doing +# #BUG: Identified bug +# #NOTE: Note by author + +#TODO: Should it be called something else? Ideas: +# PyPLE: Python Persistent Logic Engine +# PYLE: Python Logic Engine +# PYSLE: Python Simple Logic Engine +# PYRE: Python Rules Engine + +__revision__ = "$Id: SpamScalpelServer.py 52 2006-03-10 05:35:58Z anseljh $" +__author__ = 'Ansel Halliburton (pyple at anseljh dot com)' +#TODO: set up py...@an... +__date__ = '$Date: 2006-03-09 21:35:58 -0800 (Thu, 09 Mar 2006) $'.split()[1].replace('/', '-') +__version__ = '$Revision: 52 $' +__release__ = (0,1,0,'alpha',0) +#TODO: check into SVN to update these +#TODO: add SVN keywords (svn:keywords) + +PYPLE_TAGLINE = "PyPLE (say \"pipple\") -- the Python Persistent Logic Engine" +PYPLE_COPYRIGHT = "Copyright (c) 2006 Ansel Halliburton. All rights reserved." +ASTERISKS = 40 # number of asterisks to use as separator in debug/test output + +from datetime import datetime +import pickle +import types + +#import PyPLE classes +import Expression, Element, Operator, PyPLEType, Code + +TYPES = { PyPLEType.TYPE_EXPRESSION:'expression', PyPLEType.TYPE_BOOLEAN:'boolean', PyPLEType.TYPE_INTEGER:'integer', + PyPLEType.TYPE_STRING:'string', PyPLEType.TYPE_DATETIME:'datetime', PyPLEType.TYPE_NULL:'null', + PyPLEType.TYPE_FLOAT:'float' } + +TYPES_MAPPING = { \ +# TYPE_EXPRESSION: Expression, \ + PyPLEType.TYPE_BOOLEAN: types.BooleanType, \ + PyPLEType.TYPE_INTEGER: types.IntType, \ + PyPLEType.TYPE_STRING: types.StringType, \ + PyPLEType.TYPE_DATETIME: datetime, \ + PyPLEType.TYPE_NULL: types.NoneType, \ + PyPLEType.TYPE_FLOAT: types.FloatType \ + } +#TODO: Deal with TYPE_PICKLE and TYPE_MAGIC? (or not - just check if in mapping and if not special-case it.) + +#reverse mapping +TYPES_MAPPING_REVERSE = {} +for key in TYPES_MAPPING.keys(): + TYPES_MAPPING_REVERSE[TYPES_MAPPING[key]] = key + +########################################################################################## + +class PyPLE: + """ + PyPLE base class. + """ + + #TODO: write code to import/export from DB (i.e. make it persistent) + + def __init__(self): + """ + PyPLE constructor + """ + self.next_f_id = 1 + self.functions = {'id':{}, 'name':{}, 'pid':{} } # dictionaries of functions + self.operators = {'id':{}, 'name':{}, 'pid':{} } # dictionaries of operators + + #add functions for internal operators + self.add_op_function('and', self.op_and) + self.add_op_function('or', self.op_or) + self.add_op_function('not', self.op_not) + self.add_op_function('xor', self.op_xor) + self.add_op_function('nand', self.op_nand) + + #add internal operators + for q in ('and','or','not','xor','nand'): + o = Operator.Operator(self, q, Operator.ENGINE_INTERNAL) + self.operators['name'][q] = o + + + def add_op_function(self, name, f, pid=None): + """ + Adds an operator based on an already extant function (no eval call) + Parameters: + name Name of operator (NOTE: Must be unique!) (string) + f Function implementing logic of operator (method) + [pid] Persistent ID used in database (int; mostly likely None if called directly) + """ + if name in self.functions['name']: + raise Exception("Function with name '" + str(name) + "' already exists!") + fid = self.next_f_id + self.next_f_id = self.next_f_id + 1 + self.functions['id'][fid] = f + self.functions['name'][name] = f + if pid is not None: self.functions['pid'][pid] = f + + def add_operator(self, name, o, pid=None): + """Adds an operator to internal index""" + self.operators['name'][name] = o + if pid is not None: + self.operators['pid'][pid] = o + + def evaluate_by_id(self, fid, LHS, RHS): + """ + MANUALLY evaluates an expression, looking up the function by id. + Parameters: + fid id of function (looked up in self.functions['id']) + LHS left hand side of expression to be evaluated + RHS right hand side of expression to be evaluated + Returns: 2-tuple + type Type of value returned (instance of Python built-in class Type) + val Value of expression + """ + f = self.functions['id'][fid] + val = f(LHS, RHS) + return (type(val), val) + + def evaluate_by_name(self, name, LHS, RHS): + """ + MANUALLY evaluates an expression, looking up the function by name. + Parameters: same as evaluate_by_id, except using name (string) instead of id (int) + Returns: same as evaluate_by_id + """ + f = self.functions['name'][name] + val = f(LHS, RHS) + return (type(val), val) + + ###################################################################################### + #INTERNAL OPERATORS + #NOTE: Internal operators are in DB with engine id 1 (INTERNAL) and names e.g. 'and', 'or', etc. + #This is important because it allows expressions using internal operators to be made persistent! + #The logic here should (1) notice an internal operator's use, and then (2) look it up by name, **NOT** pid. + ###################################################################################### + + def op_and(self, LHS, RHS): + """Internal AND operator""" + print "** Internal AND operator called. LHS=",LHS,"; RHS=",RHS + return (LHS and RHS) + + def op_or(self, LHS, RHS): + """Internal OR operator""" + return (LHS or RHS) + + def op_not(self, LHS, RHS): + """Internal NOT operator""" + return (LHS and not RHS) + + def op_xor(self, LHS, RHS): + """Internal XOR operator""" + return ( (LHS and not RHS) or (RHS and not LHS) ) + + def op_nand(self, LHS, RHS): + """Internal NAND operator""" + #TODO: is this really what NAND is supposed to do? + if (LHS and RHS): + return False + else: + return True + +########################################################################################## + +if __name__ == "__main__": + print PYPLE_TAGLINE + print PYPLE_COPYRIGHT + print + print "Instantiating: ", + P = PyPLE() + print "Done." + + print "*" * ASTERISKS + print "Testing 1: " + code1 = "lambda LHS, RHS: True" + l1 = 2 + r1 = False + o_at = Operator.Operator(P, 'always_true', Operator.ENGINE_PYTHON, None, code1) + result1 = P.evaluate_by_name('always_true', l1, r1) + print result1 + + print "*" * ASTERISKS + print "Testing 2: " + code2 = "lambda LHS, RHS: int(LHS) * int(RHS)" + l2 = 2 + r2 = 3 + o_mul = Operator.Operator(P, 'multiply_integers', Operator.ENGINE_PYTHON, None, code2) + result2 = P.evaluate_by_name('multiply_integers', l2, r2) + print result2 + + print "*" * ASTERISKS + print "Testing AND: " + print P.evaluate_by_name('and', True, False) + + print "*" * ASTERISKS + print "Testing OR: " + print P.evaluate_by_name('or', True, False) + + print "*" * ASTERISKS + print "Testing NOT: " + print P.evaluate_by_name('not', True, False) + + print "*" * ASTERISKS + print "Testing XOR: " + print P.evaluate_by_name('xor', True, False) + + print "*" * ASTERISKS + print "Testing NAND(T,F): " + print P.evaluate_by_name('nand', True, False) + print "*" * ASTERISKS + print "Testing NAND(T,T): ", + print P.evaluate_by_name('nand', True, True) + + print "*" * ASTERISKS + print "Testing Expression.eval() [multiply_integers]" + op_multiply = P.operators['name']['multiply_integers'] + e1 = Element.Element(10) + print e1 + e2 = Element.Element(5) + print e2 + x = Expression.Expression(op_multiply, e1, e2) + rx = x.eval() + print rx + + print "*" * ASTERISKS + print "Testing Expression.eval() [and]" + op_and = P.operators['name']['and'] + e2_1 = Element.Element(True) + print e2_1 + e2_2 = Element.Element(False) + print e2_2 + x2 = Expression.Expression(op_and, e2_1, e2_2) + rx2 = x2.eval() + print rx2 + + print "*" * ASTERISKS + from pprint import pprint + pprint(P.operators) + + print "*" * ASTERISKS + + print "The End." Added: src/PyPLEType.py =================================================================== --- src/PyPLEType.py (rev 0) +++ src/PyPLEType.py 2006-04-11 01:41:15 UTC (rev 1) @@ -0,0 +1,107 @@ +#!/usr/bin/env python +""" +PyPLE (say "pipple") -- the Python Persistent Logic Engine + +PyPLEType.py: Helper class for mapping between persistent PyPLE types and Python native types + +Copyright (C) 2006 Ansel Halliburton. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the PyPLE Project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +import types +import Expression +import datetime + +TYPE_EXPRESSION = 1 +TYPE_BOOLEAN = 2 +TYPE_INTEGER = 3 +TYPE_STRING = 4 +TYPE_DATETIME = 5 +TYPE_NULL = 6 +TYPE_FLOAT = 8 + +class PyPLEType: + """ + Utility class for mapping PyPLE types to Python types + """ + + def __init__(self, id): + """Construct from id""" + + #check that id is an int + if type(id) is not types.IntType: + raise TypeError("expected an int") + + if id == TYPE_EXPRESSION: + self.name = 'expression' + if id == TYPE_BOOLEAN: + self.name = 'bool' + if id == TYPE_INTEGER: + self.name = 'int' + if id == TYPE_STRING: + self.name = 'string' + if id == TYPE_DATETIME: + self.name = 'datetime' + if id == TYPE_NULL: + self.name = 'null' + if id == TYPE_FLOAT: + self.name = 'float' + + @staticmethod + def make_from_object(o): + if type(o) is Expression: + return PyPLEType(TYPE_EXPRESSION) + elif type(o) is types.BooleanType: + return PyPLEType(TYPE_BOOLEAN) + elif type(o) is types.IntType: + return PyPLEType(TYPE_INTEGER) + elif type(o) is types.StringType: + return PyPLEType(TYPE_STRING) + elif type(o) is datetime: + return PyPLEType(TYPE_DATETIME) + elif type(o) is types.NoneType: + return PyPLEType(TYPE_NULL) + elif type(o) is types.FloatType: + return PyPLEType(TYPE_FLOAT) + else: + raise Exception("couldn't recognize/map type: " + str(type(o))) + + def __repr__(self): + return str(self) + + def __str__(self): + return str(self.name) + + def get_name(self): + print ":: PyPLEType.get_name() called" + return self.name + + def get_id(self): + print ":: PyPLEType.get_id() called" + return self.id + + def get_py_type(self): + print ":: PyPLEType.get_py_type() called" + return TYPES_MAPPING[self.id] Added: src/__init__.py =================================================================== Added: src/setup.py =================================================================== --- src/setup.py (rev 0) +++ src/setup.py 2006-04-11 01:41:15 UTC (rev 1) @@ -0,0 +1,42 @@ +#!/usr/bin/env python +""" +PyPLE (say "pipple") -- the Python Persistent Logic Engine + +setup.py: Distutils script + +Copyright (C) 2006 Ansel Halliburton. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the PyPLE Project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +""" + +from distutils.core import setup + +setup(name='PyPLE', + version='0.0.1', + description='Python Persistent Logic Engine', + author='Ansel Halliburton', + author_email='an...@us...', + url='http://www.anseljh/code/pyple/', + py_modules=['PyPLE', 'Expression', 'Operator', 'PyPLEType', 'Element', 'Code'], + ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |