pyple-commits Mailing List for PyPLE
Status: Pre-Alpha
Brought to you by:
anseljh
You can subscribe to this list here.
2006 |
Jan
|
Feb
|
Mar
|
Apr
(10) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
(5) |
Feb
|
Mar
(6) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <an...@us...> - 2007-03-16 17:09:20
|
Revision: 21 http://svn.sourceforge.net/pyple/?rev=21&view=rev Author: anseljh Date: 2007-03-16 10:09:18 -0700 (Fri, 16 Mar 2007) Log Message: ----------- moved setup.py to root; 'python setup.py sdist' works right Added Paths: ----------- setup.py Removed Paths: ------------- src/setup.py Copied: setup.py (from rev 20, src/setup.py) =================================================================== --- setup.py (rev 0) +++ setup.py 2007-03-16 17:09:18 UTC (rev 21) @@ -0,0 +1,49 @@ +#!/usr/bin/env python +""" +PyPLE (say "pipple") -- the Python Persistent Logic Engine + +setup.py: Distutils script + +Copyright (C) 2006-2007 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 +from setuptools import setup, find_packages + +setup( + name='pyple', + version='0.3.0', + description='PyPLE (pronounced "pipple") is the Python Persistent Logic Engine -- a framework for composing, evaluating, and storing logical expressions.', + author='Ansel Halliburton', + author_email='an...@us...', + keywords=['logic','engine','expression','database'], + url='http://pyple.sourceforge.net/', + license='BSD License', + classifiers=['Development Status :: 2 - Pre-Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules'], + py_modules=['pyple'], + package_data = {'':['*.*']}, + packages = find_packages(), +) Deleted: src/setup.py =================================================================== --- src/setup.py 2007-03-16 17:05:51 UTC (rev 20) +++ src/setup.py 2007-03-16 17:09:18 UTC (rev 21) @@ -1,49 +0,0 @@ -#!/usr/bin/env python -""" -PyPLE (say "pipple") -- the Python Persistent Logic Engine - -setup.py: Distutils script - -Copyright (C) 2006-2007 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 -from setuptools import setup, find_packages - -setup( - name='pyple', - version='0.3.0', - description='PyPLE (pronounced "pipple") is the Python Persistent Logic Engine -- a framework for composing, evaluating, and storing logical expressions.', - author='Ansel Halliburton', - author_email='an...@us...', - keywords=['logic','engine','expression','database'], - url='http://pyple.sourceforge.net/', - license='BSD License', - classifiers=['Development Status :: 2 - Pre-Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules'], - py_modules=['pyple'], - package_data = {'':['*.*']}, - packages = find_packages(), -) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2007-03-16 17:05:53
|
Revision: 20 http://svn.sourceforge.net/pyple/?rev=20&view=rev Author: anseljh Date: 2007-03-16 10:05:51 -0700 (Fri, 16 Mar 2007) Log Message: ----------- switch to setuptools Modified Paths: -------------- src/setup.py Modified: src/setup.py =================================================================== --- src/setup.py 2007-03-16 16:56:25 UTC (rev 19) +++ src/setup.py 2007-03-16 17:05:51 UTC (rev 20) @@ -30,7 +30,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ -from distutils.core import setup +#from distutils.core import setup +from setuptools import setup, find_packages setup( name='pyple', @@ -43,4 +44,6 @@ license='BSD License', classifiers=['Development Status :: 2 - Pre-Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules'], py_modules=['pyple'], + package_data = {'':['*.*']}, + packages = find_packages(), ) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2007-03-16 16:56:25
|
Revision: 19 http://svn.sourceforge.net/pyple/?rev=19&view=rev Author: anseljh Date: 2007-03-16 09:56:25 -0700 (Fri, 16 Mar 2007) Log Message: ----------- improved project description; added code example; added SQLObject link; validated XHTML and CSS Modified Paths: -------------- www/index.html Modified: www/index.html =================================================================== --- www/index.html 2007-03-16 16:07:30 UTC (rev 18) +++ www/index.html 2007-03-16 16:56:25 UTC (rev 19) @@ -3,21 +3,104 @@ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>PyPLE</title> + <style type="text/css"> + .code { + background-color: #ddd; + margin-left: 2em; + margin-right: 2em; + border: 1px solid #777; + } + </style> </head> <body> <h1>PyPLE</h1> - <p>PyPLE (pronounced "pipple") is the Python Persistent Logic Engine -- a framework for composing, evaluating, and storing logical expressions.</p> + <p>PyPLE (pronounced "pipple") is the Python Persistent Logic Engine—a framework for composing, evaluating, and storing logical expressions. With PyPLE, you can compose complex chains of simple logical operators and store them in a database. You can then apply those chains of logic to any data you like.</p> + <p>PyPLE now uses <a href="http://www.sqlobject.org/">SQLObject</a> for database connectivity and object-relational mapping. If you are a Python developer and don't know about SQLObject, check it out!</p> + <h2>Code Example</h2> + <div class="code"> + <pre> + >>> import pyple + >>> import yaml # use PyYAML for loading DB connection parameters + >>> + >>> E = pyple.Engine() # instantiate a PyPLE engine + >>> E.connect_to_db(pyple.Engine.build_db_uri(yaml.load(open('pyple-db.yaml').read()))) # Connect to the DB + Connecting to DB with: mysql://pyple:pyple@localhost:3306/pyple2?debug=1 + Connected to DB: <sqlobject.mysql.mysqlconnection.MySQLConnection instance at 0x11e5d50> + >>> + >>> starts_with_foo = pyple.Regex(pattern="^foo") + 1/QueryIns: INSERT INTO operator (name, child_name) VALUES (NULL, 'Regex') + 1/QueryOne: SELECT name, child_name FROM operator WHERE id = (1) + 1/QueryIns: INSERT INTO op_regex (id, pattern, child_name, case_sensitive) VALUES (1, '^foo', NULL, 0) + 1/QueryOne: SELECT pattern, case_sensitive, child_name FROM op_regex WHERE id = (1) + >>> starts_with_foo.eval("foo bar!") + True + >>> starts_with_foo.eval("bar foo!") + False + >>> + >>> always_true = pyple.AlwaysTrueOp() + 1/QueryIns: INSERT INTO operator (name, child_name) VALUES (NULL, 'AlwaysTrueOp') + 1/QueryOne: SELECT name, child_name FROM operator WHERE id = (2) + 1/QueryIns: INSERT INTO always_true_op (id, child_name) VALUES (2, NULL) + 1/QueryOne: SELECT child_name FROM always_true_op WHERE id = (2) + >>> + >>> always_false = pyple.AlwaysFalseOp() + 1/QueryIns: INSERT INTO operator (name, child_name) VALUES (NULL, 'AlwaysFalseOp') + 1/QueryOne: SELECT name, child_name FROM operator WHERE id = (3) + 1/QueryIns: INSERT INTO always_false_op (id, child_name) VALUES (3, NULL) + 1/QueryOne: SELECT child_name FROM always_false_op WHERE id = (3) + >>> + >>> false_and_starts_with_foo = pyple.AND() + 1/QueryIns: INSERT INTO operator (name, child_name) VALUES (NULL, 'AND') + 1/QueryOne: SELECT name, child_name FROM operator WHERE id = (4) + 1/QueryIns: INSERT INTO op_and (id, child_name) VALUES (4, NULL) + 1/QueryOne: SELECT child_name FROM op_and WHERE id = (4) + >>> + >>> false_and_starts_with_foo.addParameter(always_false) + 1/Query : INSERT INTO operator_operator (parameter_id, operator_id) VALUES (4, 3) + >>> + >>> false_and_starts_with_foo.addParameter(starts_with_foo) + 1/Query : INSERT INTO operator_operator (parameter_id, operator_id) VALUES (4, 1) + >>> + >>> false_and_starts_with_foo.eval('foo bar blah blah') + 1/QueryAll: SELECT operator_id FROM operator_operator WHERE parameter_id = (4) + False + >>> + >>> test_or = pyple.OR() + 1/QueryIns: INSERT INTO operator (name, child_name) VALUES (NULL, 'OR') + 1/QueryOne: SELECT name, child_name FROM operator WHERE id = (5) + 1/QueryIns: INSERT INTO op_or (id, child_name) VALUES (5, NULL) + 1/QueryOne: SELECT child_name FROM op_or WHERE id = (5) + >>> + >>> test_or.addParameter(false_and_starts_with_foo) + 1/Query : INSERT INTO operator_operator (parameter_id, operator_id) VALUES (5, 4) + >>> + >>> test_or.addParameter(always_true) + 1/Query : INSERT INTO operator_operator (parameter_id, operator_id) VALUES (5, 2) + >>> + >>> test_or.eval('foo.. spam??') + 1/QueryAll: SELECT operator_id FROM operator_operator WHERE parameter_id = (5) + 1/QueryAll: SELECT operator_id FROM operator_operator WHERE parameter_id = (4) + >>> + >>> test_or.eval('this does not start with foo') + 1/QueryAll: SELECT operator_id FROM operator_operator WHERE parameter_id = (5) + 1/QueryAll: SELECT operator_id FROM operator_operator WHERE parameter_id = (4) + True + >>> + </pre> + </div> + <h2>Links</h2> <ul> - <li><a href="http://sourceforge.net/projects/pyple">SourceForge project page</a></li> - <li><a href="http://svn.sourceforge.net/viewcvs.cgi/pyple/">Browse Subversion code repository</a></li> - <li><a href="http://cia.navi.cx/stats/project/pyple">Stats on CIA</a></li> - <li><a href="http://python.org/pypi/PyPLE/">Info in Python Cheese Shop</a></li> - <li><a href="mailto:anseljh at users dot sourceforge dot net">Email Ansel Halliburton, the founder/maintainer/everything</a></li> + <li><a href="http://sourceforge.net/projects/pyple">SourceForge project page</a></li> + <li><a href="http://svn.sourceforge.net/viewcvs.cgi/pyple/">Browse Subversion code repository</a></li> + <li><a href="http://cia.navi.cx/stats/project/pyple">Stats on CIA</a></li> + <li><a href="http://python.org/pypi/PyPLE/">Info in Python Cheese Shop</a></li> + <li><a href="http://www.sqlobject.org/">SQLObject</a></li> + <li><a href="mailto:anseljh at users dot sourceforge dot net">Email Ansel Halliburton</a>, the founder/maintainer/everything</li> </ul> - <p><a href="http://sourceforge.net/donate/index.php?group_id=164858"><img src="http://images.sourceforge.net/images/project-support.jpg" width="88" height="32" border="0" alt="Support This Project" /></a><a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=164858&type=1" width="88" height="31" border="0" alt="SourceForge.net Logo" /></a></p> + <p><a href="http://sourceforge.net/donate/index.php?group_id=164858"><img src="http://images.sourceforge.net/images/project-support.jpg" width="88" height="32" style="border:none;" alt="Support This Project" /></a><a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=164858&type=1" width="88" height="31" style="border:none;" alt="SourceForge.net Logo" /></a></p> </body> </html> \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2007-03-16 16:11:07
|
Revision: 18 http://svn.sourceforge.net/pyple/?rev=18&view=rev Author: anseljh Date: 2007-03-16 09:07:30 -0700 (Fri, 16 Mar 2007) Log Message: ----------- updated some comments; include sample YAML Modified Paths: -------------- src/pyple.py Modified: src/pyple.py =================================================================== --- src/pyple.py 2007-03-16 04:23:24 UTC (rev 17) +++ src/pyple.py 2007-03-16 16:07:30 UTC (rev 18) @@ -34,7 +34,9 @@ * You can run this file to do some simple testing: python pyple.py * The tests depend on PyYAML, and expect a YAML file called 'pyple-db.yaml' with database connection parameters. (try 'easy_install pyyaml') You - do NOT need PyYAML to import PyPLE. + do NOT need PyYAML to import PyPLE. Here is a sample one-line YAML + configuration file: + {database: pyple, dbtype: mysql, host: localhost, password: xyzzy, port: 3306, username: pyple} * Special thanks to Stanford Law School for allowing me to continue work on PyPLE in 2007! @@ -157,7 +159,7 @@ else: return True -PYPLE_TABLES = [Operator, AlwaysTrueOp, AlwaysFalseOp, Regex, AND, OR, NOT, XOR, NAND] +PYPLE_TABLES = [Operator, AlwaysTrueOp, AlwaysFalseOp, Regex, AND, OR, NOT, XOR, NAND] # Used by Engine to rebuild tables class Engine: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2007-03-16 04:23:26
|
Revision: 17 http://svn.sourceforge.net/pyple/?rev=17&view=rev Author: anseljh Date: 2007-03-15 21:23:24 -0700 (Thu, 15 Mar 2007) Log Message: ----------- 0.3.0 - near-complete rewrite, but it actually works! Modified Paths: -------------- src/pyple.py src/setup.py Modified: src/pyple.py =================================================================== --- src/pyple.py 2007-03-01 02:31:09 UTC (rev 16) +++ src/pyple.py 2007-03-16 04:23:24 UTC (rev 17) @@ -32,6 +32,11 @@ NOTES * PyPLE is lean and mean. Just say no to complexity! * You can run this file to do some simple testing: python pyple.py +* The tests depend on PyYAML, and expect a YAML file called 'pyple-db.yaml' + with database connection parameters. (try 'easy_install pyyaml') You + do NOT need PyYAML to import PyPLE. +* Special thanks to Stanford Law School for allowing me to continue work on + PyPLE in 2007! HISTORY v0.0.1 PyPLE was born in a flash of inspiration at L & L Hawaiian Barbecue in @@ -40,10 +45,10 @@ Komodo IDE. v0.1.0 Port to SQLObject for database persistence begun - 1/22/07 v0.2.0 Complete rewrite of SQLObject version +v0.3.0 Another major rewrite -- simplifying Operator, parameters, etc. 3/15/07. It works! :) """ # Interesting tokens to look for in this source code: -# # #TODO: Items that need doing # #BUG: Identified bug # #NOTE: Note by author @@ -52,188 +57,108 @@ __author__ = 'Ansel Halliburton (anseljh at users dot sourceforge dot net)' #__date__ = '$RevisionDate$'.split()[1].replace('/', '-') __version__ = '$Revision: 7 $' -__release__ = (0,2,0,'alpha',0) +__release__ = (0,3,0,'alpha',0) PYPLE_TAGLINE = "PyPLE (say \"pipple\") -- the Python Persistent Logic Engine" PYPLE_COPYRIGHT = "Copyright (c) 2006-2007 Ansel Halliburton" ASTERISKS = 40 # number of asterisks to use as separator in debug/test output +DEBUG = 1 import re -import types from sqlobject import * # SQLObject ORM from sqlobject.inheritance import InheritableSQLObject -DEBUG = 1 +class Operator(InheritableSQLObject): + + parameters = RelatedJoin('Operator', joinColumn='parameter_id') + name = StringCol(length=255, notNone=False, default=None) -class Parameter(SQLObject): + def eval(self, data=None): + pass # to be overloaded - key = StringCol(length=100, notNone=False, default=None, dbName='param_key') - value = PickleCol(default=None, dbName='param_value') + def addParameter(self, param): + self.addOperator(param) - #def __init__(self, key=None, value=None): - # self.key = key - # self.value = value +class AlwaysTrueOp(Operator): + def eval(self, data=None): + return True -class Operator(InheritableSQLObject): +class AlwaysFalseOp(Operator): + def eval(self, data=None): + return False + +class Regex(Operator): - parameters = MultipleJoin('Parameter') + pattern = StringCol(length=255) + case_sensitive = BoolCol(default=False) - #def __init__(self, parameters): - def _init(self, *args, **kw): - if DEBUG: print "*"*5, "Start of Operator._init" - if DEBUG: print "*"*5, "I'm a", self.sqlmeta.table - if 'params' in kw: - if DEBUG: print "*"*5, "Handling kw:", kw - if isinstance(kw['params'], types.ListType): - if DEBUG: print "*"*5, "It's a list with", len(kw['params']), "elements" - for p in kw['params']: - if DEBUG: print "*"*5, "Element:", p - if isinstance(p, Parameter): - if DEBUG: print "*"*5, "It's a Parameter already" - self.add_parameter(p) - else: - if DEBUG: print "*"*5, "Making it a Parameter..." - self.add_parameter(Parameter(value=p)) - else: - raise TypeError("params must be a list.") - else: - if DEBUG: - print "*"*5, "No params!" - print "*"*5, "KW:", kw - print "*"*5, "ARGS", args - - ##self.parameters = parameters - #self.parameters = [] - #for p in parameters: - # self.parameters.append(Parameter(value=p)) - - self.config = {} # misc storage - if DEBUG: print "*"*5, "End of Operator._init" + class sqlmeta: + table = 'op_regex' - def __getstate__(self): - """ - Allows for pickling of any Operator; stores class type (table) and row ID -- basically a pointer to the object in the DB. - """ - return dict(table=self.sqlmeta.table, id=self.id) - - def __setstate__(self, d): - """ - Unpickler - """ - self = Operator.get(d['id']) - - def eval_fn(self, data): - pass # to be overloaded - def eval(self, data): - #for param in parameters: - # pass - pass # to be overloaded - -class Regex(Operator): - def eval(self, data): - - # JIT regex compilation - if 'regex' not in self.config: - if 'case_sensitive' in self.config and self.config['case_sensitive'] is False: - self.config['regex'] = re.compile(self.parameters[0].value, re.IGNORECASE) - else: - self.config['regex'] = re.compile(self.parameters[0].value) - - # Run regex on data - result = self.config['regex'].search(data) - - # Return True if match; else return False + tmp_re = None + if self.case_sensitive: + tmp_re = re.compile(self.pattern) + else: + tmp_re = re.compile(self.pattern, re.IGNORECASE) + result = tmp_re.search(data) if result: return True - return False - class sqlmeta: - table = 'op_regex' + else: + return False -class CIRegex(Regex): - """Case-insensitive regex""" - #def __init__(self, parameters): - def _init(self, *args, **kw): - #Regex.__init__(self, parameters) - Regex._init(self, *args, **kw) - self.config['case_sensitive'] = False - class sqlmeta: - table = 'op_ci_regex' - class AND(Operator): class sqlmeta: table = 'op_and' - def eval(self, data): + def eval(self, data=None): for param in self.parameters: - if not param.value.eval(data): # - return False # - return True + if not param.eval(data): + return False + return True # implicit else after for loop +class OR(Operator): + class sqlmeta: + table = 'op_or' + def eval(self, data=None): + for param in self.parameters: + if param.eval(data): + return True + return False # implicit else after for loop -class Action(SQLObject): - - # Columns - function = ForeignKey('ActionFunction') - - def invoke(self, data): - self.action_function.invoke(self.get_parameters(data), data) - - def get_parameters(self, data): - """ - Pre-process data and generate list of parameters for invoke() method - """ - #TODO: stub - print "STUB: Action.get_parameters() called" +class NOT(Operator): + class sqlmeta: + table = 'op_not' + def eval(self, data=None): + assert len(self.parameters) == 1, "NOT only works with one Operator parameter" + if self.parameters[0].eval(data): + return False + else: + return True -class ActionFunction(SQLObject): - #TODO: stub - - code = StringCol(notNone=False, default="print 'Default ActionFunction; len(str(data)) =', len(str(data))") - - def invoke(self, parameters, data): - try: - junk = self.evaled_code - except: - print "** about to eval() Python code: ", code - self.evaled_code = eval(code, {}, {}) #run Python eval() on code (in sandbox) +class XOR(Operator): + class sqlmeta: + table = 'op_xor' + def eval(self, data=None): + assert len(self.parameters) == 2, "XOR only works with two Operator parameters" + if self.parameters[0].eval(data) and not self.parameters[1].eval(data): + return True + elif self.parameters[1].eval(data) and not self.parameters[0].eval(data): + return True + else: + return False +class NAND(Operator): + class sqlmeta: + table = 'op_nand' + def eval(self, data=None): + assert len(self.parameters) == 2, "NAND only works with two Operator parameters" + if self.parameters[0].eval(data) and self.parameters[1].eval(data): + return False + else: + return True -class RuleSet(SQLObject): - root_rule = ForeignKey('Operator') # e.g. AND rule at root of rule tree - actions = RelatedJoin('Action') - name = StringCol(length=100) - - def eval(self, data): - """ - Evaluate rules against data; return True/False - """ - return self.root_rule.eval(data) - - def invoke(self, data): - """ - Invoke actions on data (does not evaluate rules) - """ - if root_rule.eval(data): - for action in actions: - action.invoke(data) - - def eval_and_invoke(self, data): - """ - Evaluate rules against data, then invoke actions if result is True - """ - if self.eval(data): - self.invoke(data) - - @staticmethod - def get_by_name(name): - """ - Fetches a single RuleSet instance by name. - """ - return RuleSet.selectBy(name=name)[0] +PYPLE_TABLES = [Operator, AlwaysTrueOp, AlwaysFalseOp, Regex, AND, OR, NOT, XOR, NAND] -PYPLE_TABLES = [Parameter, Operator, Regex, CIRegex, Action, ActionFunction, RuleSet, AND] - - class Engine: def __init__(self, debug=DEBUG): @@ -271,193 +196,80 @@ if __name__ == "__main__": import yaml #PyYAML: YAML parser/emitter - because its easy_install isn't b0rked like PySyck's: see http://pyyaml.org/ticket/44 - E = Engine() - E.connect_to_db(Engine.build_db_uri(yaml.load(open('pyple-db.yaml').read()))) - E.drop_tables() - E.create_tables() - andtf = AND(params=[True, False]) - print "andtf:", andtf - print "andtf.eval():", andtf.eval() + E = Engine() # instantiate the engine + E.connect_to_db(Engine.build_db_uri(yaml.load(open('pyple-db.yaml').read()))) # Connect to the DB + E.drop_tables() # drop all the tables + E.create_tables() # rebuild all the tables + test_true = AlwaysTrueOp() + assert test_true.eval() == True, "AlwaysTrueOp.eval() should always return True" + + test_false = AlwaysFalseOp() + assert test_false.eval() == False, "AlwaysFalseOp.eval() should always return False" + + test_and = AND() + test_and.addParameter(test_true) + test_and.addParameter(test_false) + assert test_and.eval() == False, "AND.eval() of True and False should return False" + + test_or = OR() + test_or.addParameter(test_true) + test_or.addParameter(test_false) + assert test_or.eval() == True, "OR.eval() of True and False should return True" + + test_and_2 = AND() + test_and_2.addParameter(test_and) + test_and_2.addParameter(test_or) + assert test_and_2.eval() == False, "Complex AND should return False" + txt = "ORDER, for the reasons set forth in the related Memoranda Opinions issued in this matter on 06/30/06 and 10/10/06, and for good cause, the final Markman definitions applicable to the disputed claim terms and phrases are as follows: (see Order for details). Signed by Judge T. S. Ellis III on 10/10/06. Copies mailed: yes (pmil) (Entered: 10/12/2006)" - ### Operator tests ### + starts_with_order = Regex(pattern="^ORDER") + assert starts_with_order.eval(txt) == True, "starts_with_order.eval(txt) should be True" - starts_with_order = Regex(params=["^ORDER"]) ### - print "starts_with_order:", starts_with_order.eval(txt) - contains_markman = CIRegex(params=["markman"]) - print "contains_markman:", contains_markman.eval(txt) - both = AND(params=[starts_with_order, contains_markman]) - print "both:", both.eval(txt) - not_matching = CIRegex(params=["foobar"]) - print "not_matching:", not_matching.eval(txt) - false_and = AND(params=[starts_with_order, not_matching]) - print "false_and:", false_and.eval(txt) - print "false_and (alt. data):", false_and.eval("ORDER re: foobar and stuff") + contains_markman = Regex(pattern="markman") + assert contains_markman.eval(txt) == True, "contains_markman.eval(txt) should be True" - ### RuleSet tests ### + both = AND() + both.addParameter(starts_with_order) + both.addParameter(contains_markman) + assert both.eval(txt) == True, "both.eval(txt) should be True" - print "initializing RuleSet" - rs = RuletSet(name="test_ruleset") - rs.root_rule = both - actionfunction1 = ActionFunction() - action1 = Action(function=actionfunction1) - rs.addAction(action1) - print "rs.eval():", rs.eval(txt) - rs.eval_and_invoke(txt) - - -################################################################################################## -# v0.1.0 below... -################################################################################################## - -#class Operator: -# -# def __init__(self, arguments=None): -# if arguments is None: -# self.arguments = [] -# else: -# self.arguments = arguments -# -# def pre_eval(self, data): -# """ -# Runs eval() on any child Operators in arguments -# """ -# evaled_args = [] -# for arg in arguments: -# if isinstance(arg, Operator): -# evaled_args.append(arg.eval(data)) # pass data down the logic stack -# else: -# evaled_args.append(arg) -# return evaled_args -# -# def eval(self, data): -# return self.eval_function(data) -# -# -#class BooleanOperator(Operator): -# def __init__(self, arguments=None): -# Operator.__init__(self, arguments=arguments) -# -#class AND(BooleanOperator): -# def eval_function(self, data): -# for datum in data: -# if not datum: -# return False -# return True -# -#class OR(BooleanOperator): -# def eval_function(self, data): -# for datum in data: -# if datum: -# return True -# return False -# -#class NOT(BooleanOperator): -# def eval_function(self, data): -# if len(data) != 2: -# raise ValueError("wrong size data list (must be 2 elements long") #TODO: refactor to something like check_length(data, 2) -# return data[0] and not data[1] -# -#class XOR(BooleanOperator): -# def eval_function(self, data): -# if len(data) != 2: -# raise ValueError("wrong size data list (must be 2 elements long") #TODO: refactor to something like check_length(data, 2) -# return (data[0] or data[1]) and not (data[0] and data[1]) -# -#class NAND(BooleanOperator): -# def eval_function(self, data): -# if len(data) != 2: -# raise ValueError("wrong size data list (must be 2 elements long") #TODO: refactor to something like check_length(data, 2) -# if data[0] and data[1]: -# return False -# else: -# return True -# -#class MatchRegex(Operator): -# def __init__(self, arguments=None, case_sensitive=True): -# """ -# arguments should be a 1-element list string with the regex pattern as a string -# """ -# Operator.__init__(self, arguments=arguments) -# self.regexes = [] -# for arg in self.arguments: -# if case_sensitive: -# self.regexes.append(re.compile(arg)) -# else: -# self.regexes.append(re.compile(arg, re.IGNORECASE)) -# -# def eval_function(self, data): -# """ -# Data should be a string to match against -# """ -# for expr in self.regexes: -# result = expr.search(data) -# if result: -# return True -# return False -# -#class MatchRegexCI(MatchRegex): # case-insensitive -# def __init__(self, arguments=None): -# MatchRegex.__init__(self, arguments=arguments, case_sensitive=False) -# -# -#class Engine: -# @staticmethod -# def build_db_uri(self, d): -# """ -# Build database connection URI from dictionary of connection parameters -# """ -# uri = "%s://%s:%s@%s:%d/%s" % (d['dbtype'], d['username'], d['password'], d['host'], d['port'], d['database']) -# return uri -# -# def connect_to_db(self, uri): -# if self.debuglevel > 0: -# print "Connecting to DB with: %s" % uri -# -# self.dbconnection = sqlobject.connectionForURI(uri) -# if self.debuglevel > 0: -# print "Connected to DB: %s" % self.dbconnection -# -# def create_tables(self): -# for table in PYPLE_TABLES: -# table.createTable() -# -# -####### TEST CASES ###### -# -#if __name__ == "__main__": -# -# import syck # YAML parser -# dburi = Engine.build_db_uri(syck.load(open("pyple-db.yaml"))) -# E = Engine(debug=1, dburi=dburi) -# -# entries = {} -# entries[300] = "ORDER that Synthon's claims of infringement of the '738 Patent, as set forth in Count Two of its Complaint, are hereby DISMISSED with prejudice (see Order for details). Signed by Judge T. S. Ellis III on 08/31/06. Copies mailed: yes (pmil) (Entered: 09/01/2006)" -# entries[301] = "MEMORANDUM OPINION RE: Post-Verdict Markman Opinion. Signed by Judge T. S. Ellis III on 10/10/06. Copies mailed: yes (pmil) (Entered: 10/12/2006)" -# entries[302] = "ORDER, for the reasons set forth in the related Memoranda Opinions issued in this matter on 06/30/06 and 10/10/06, and for good cause, the final Markman definitions applicable to the disputed claim terms and phrases are as follows: (see Order for details). Signed by Judge T. S. Ellis III on 10/10/06. Copies mailed: yes (pmil) (Entered: 10/12/2006)" -# order_defs = ['order', 'opinion'] -# markman_defs = ['markman', 'claim.{0,3}constr'] -# excl = ['Minute Entry', 'ORDER ENLARGING TIME', 'MARKMAN HEARING', 'hearing is set', 'Motion for Leave', 'Motion to Seal', 'DEFERRING a Markman determination', 'Claim Construction Statement', 'in Limine', 'SCHEDULING ORDER', 'parties shall', 'Docket Control', 'page limit', 'page restriction', 'extend time', 'Show Cause'] -# -# starts_with_order = MatchRegex(["^ORDER"]) -# -# is_order = OR( [ MatchRegexCI([pattern]) for pattern in order_defs ] ) -# is_markman = OR( [ MatchRegexCI([pattern]) for pattern in markman_defs ] ) -# not_excluded = AND( [NOT(MatchRegexCI([pattern])) for pattern in excl] ) -# big_statement = AND([is_order, is_markman, not_excluded]) -# -# for key in entries: -# print "Entry #", key -# swo = starts_with_order.eval(entries[key]) -# if swo: -# print "Starts with 'ORDER'." -# else: -# print "Does not start with 'ORDER'." -# -# result = big_statement.eval([entries[key]]) -# print "Is #", key, "a Markman order???", result -# print "-"*40 -# -# print "The end." \ No newline at end of file + not_matching = Regex(pattern="foobar") + assert not_matching.eval(txt) == False, "not_matching.eval(txt) should be False" + + false_and = AND() + false_and.addParameter(starts_with_order) + false_and.addParameter(not_matching) + assert false_and.eval(txt) == False, "false_and.eval(txt) should be False" + + alt_data = "ORDER re: foobar and stuff" + + assert false_and.eval(alt_data) == True, "false_and.eval(alt_data) should be True" + + test_not = NOT() + test_not.addParameter(test_true) + assert test_not.eval() == False, "NOT.eval() of False should be True" + + test_xor = XOR() + test_xor.addParameter(test_false) + test_xor.addParameter(test_true) + assert test_xor.eval() == True, "XOR.eval() of False, True should be True" + + test_xor2 = XOR() + test_xor2.addParameter(test_true) + test_xor2.addParameter(test_true) + assert test_xor2.eval() == False, "XOR.eval() of True, True should be False" + + test_nand1 = NAND() + test_nand1.addParameter(test_true) + test_nand1.addParameter(test_true) + assert test_nand1.eval() == False, "NAND.eval() of True, True should be False" + + test_nand2 = NAND() + test_nand2.addParameter(test_true) + test_nand2.addParameter(test_false) + assert test_nand2.eval() == True, "NAND.eval() of True, False should be True" + + print "The end!" Modified: src/setup.py =================================================================== --- src/setup.py 2007-03-01 02:31:09 UTC (rev 16) +++ src/setup.py 2007-03-16 04:23:24 UTC (rev 17) @@ -34,7 +34,7 @@ setup( name='pyple', - version='0.2.0', + version='0.3.0', description='PyPLE (pronounced "pipple") is the Python Persistent Logic Engine -- a framework for composing, evaluating, and storing logical expressions.', author='Ansel Halliburton', author_email='an...@us...', This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2007-03-01 02:31:17
|
Revision: 16 http://svn.sourceforge.net/pyple/?rev=16&view=rev Author: anseljh Date: 2007-02-28 18:31:09 -0800 (Wed, 28 Feb 2007) Log Message: ----------- v0.2.0 - complete rewrite w/ SQLObject Modified Paths: -------------- src/pyple.py Modified: src/pyple.py =================================================================== --- src/pyple.py 2007-01-25 01:03:27 UTC (rev 15) +++ src/pyple.py 2007-03-01 02:31:09 UTC (rev 16) @@ -2,7 +2,7 @@ """ PyPLE (say "pipple") -- the Python Persistent Logic Engine -pyple.py: All things PyPLE are in this file! +pyple.py: Main PyPLE class and simple test script Copyright (C) 2006-2007 Ansel Halliburton. All rights reserved. @@ -31,18 +31,19 @@ NOTES * PyPLE is lean and mean. Just say no to complexity! -* You can run this file to do some simple testing: python PyPLE.py +* 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 + Palo Alto, California on April 7, 2006. Version 0.0.1 was thrown together more or less that night with the assistance of Nine Inch Nails and the Komodo IDE. v0.1.0 Port to SQLObject for database persistence begun - 1/22/07 -v0.2.0 SQLObject version merged into one file for simplicity - 1/22/07 +v0.2.0 Complete rewrite of SQLObject version """ # Interesting tokens to look for in this source code: +# # #TODO: Items that need doing # #BUG: Identified bug # #NOTE: Note by author @@ -54,513 +55,409 @@ __release__ = (0,2,0,'alpha',0) PYPLE_TAGLINE = "PyPLE (say \"pipple\") -- the Python Persistent Logic Engine" -PYPLE_COPYRIGHT = "Copyright (c) 2006-2007 Ansel Halliburton." +PYPLE_COPYRIGHT = "Copyright (c) 2006-2007 Ansel Halliburton" ASTERISKS = 40 # number of asterisks to use as separator in debug/test output -RESERVED_OPERATORS = ['AND', 'OR', 'NOT', 'XOR', 'NAND'] -########################################################################################## - -from sqlobject import * # SQLObject ORM -from sqlobject.inheritance import InheritableSQLObject # Inheritance for Element, Expression classes -from datetime import datetime -import types import re +import types +from sqlobject import * # SQLObject ORM +from sqlobject.inheritance import InheritableSQLObject -########################################################################################## +DEBUG = 1 -class BasePyPLEType(InheritableSQLObject): - """ - Base class/interface for Element and Expression persistent types - """ +class Parameter(SQLObject): - # Meta - class sqlmeta: - table = "pyple_base_pyple_type" - - # Methods - def eval(self): - """ - Both Element and Expression should have eval() methods. - """ - pass + key = StringCol(length=100, notNone=False, default=None, dbName='param_key') + value = PickleCol(default=None, dbName='param_value') -########################################################################################## + #def __init__(self, key=None, value=None): + # self.key = key + # self.value = value -class Expression(BasePyPLEType): - """ - Expressions are composed of a left-hand-side (LHS), a right-hand-side (RHS), and - an Operator (op). LHS and RHS can be either an Element or an Expression. - """ +class Operator(InheritableSQLObject): - # Columns - operator = ForeignKey('Operator') - LHS = ForeignKey('BasePyPLEType') # can also be Expression! - RHS = ForeignKey('BasePyPLEType') # can also be Expression! + parameters = MultipleJoin('Parameter') - # Meta - class sqlmeta: - table = "pyple_expression" + #def __init__(self, parameters): + def _init(self, *args, **kw): + if DEBUG: print "*"*5, "Start of Operator._init" + if DEBUG: print "*"*5, "I'm a", self.sqlmeta.table + if 'params' in kw: + if DEBUG: print "*"*5, "Handling kw:", kw + if isinstance(kw['params'], types.ListType): + if DEBUG: print "*"*5, "It's a list with", len(kw['params']), "elements" + for p in kw['params']: + if DEBUG: print "*"*5, "Element:", p + if isinstance(p, Parameter): + if DEBUG: print "*"*5, "It's a Parameter already" + self.add_parameter(p) + else: + if DEBUG: print "*"*5, "Making it a Parameter..." + self.add_parameter(Parameter(value=p)) + else: + raise TypeError("params must be a list.") + else: + if DEBUG: + print "*"*5, "No params!" + print "*"*5, "KW:", kw + print "*"*5, "ARGS", args + + ##self.parameters = parameters + #self.parameters = [] + #for p in parameters: + # self.parameters.append(Parameter(value=p)) + + self.config = {} # misc storage + if DEBUG: print "*"*5, "End of Operator._init" - # Methods - def __str__(self): + def __getstate__(self): """ - Return string representation of an Expression + Allows for pickling of any Operator; stores class type (table) and row ID -- basically a pointer to the object in the DB. """ - return "Expression" #TODO: meaningful string representation + return dict(table=self.sqlmeta.table, id=self.id) - def eval(self): - #define temp vars - L = None - R = None + def __setstate__(self, d): + """ + Unpickler + """ + self = Operator.get(d['id']) + + def eval_fn(self, data): + pass # to be overloaded + + def eval(self, data): + #for param in parameters: + # pass + pass # to be overloaded + +class Regex(Operator): + def eval(self, data): - if type(self.LHS) is Expression: - L = self.LHS.eval() - elif type(self.LHS) is Element: - L = self.LHS - else: - raise TypeError("not an Element: %s" % str(L)) + # JIT regex compilation + if 'regex' not in self.config: + if 'case_sensitive' in self.config and self.config['case_sensitive'] is False: + self.config['regex'] = re.compile(self.parameters[0].value, re.IGNORECASE) + else: + self.config['regex'] = re.compile(self.parameters[0].value) - if type(self.RHS) is Expression: - R = self.RHS.eval() - elif type(self.RHS) is Element: - R = self.RHS - else: - raise TypeError("not an Element: %s" % str(R)) + # Run regex on data + result = self.config['regex'].search(data) - #perform operation and return Element - return self.operator.eval(L, R) + # Return True if match; else return False + if result: + return True + return False + class sqlmeta: + table = 'op_regex' -########################################################################################## +class CIRegex(Regex): + """Case-insensitive regex""" + #def __init__(self, parameters): + def _init(self, *args, **kw): + #Regex.__init__(self, parameters) + Regex._init(self, *args, **kw) + self.config['case_sensitive'] = False + class sqlmeta: + table = 'op_ci_regex' -class Element(BasePyPLEType): +class AND(Operator): + class sqlmeta: + table = 'op_and' + def eval(self, data): + for param in self.parameters: + if not param.value.eval(data): # + return False # + return True + + +class Action(SQLObject): # Columns + function = ForeignKey('ActionFunction') - types = ['element', 'expression', 'boolean', 'integer', 'string', 'datetime', 'null', 'float'] - - type = EnumCol(enumValues=types) - value = PickleCol(length=2**24) - - # Meta - class sqlmeta: - table = "pyple_element" - - # Methods - - def eval(self): + def invoke(self, data): + self.action_function.invoke(self.get_parameters(data), data) + + def get_parameters(self, data): """ - eval() on an Element returns a native Python object. + Pre-process data and generate list of parameters for invoke() method """ - - if self.type == 'expression': - return Expression.Expression(self.value) - elif self.type == 'boolean': - return types.BooleanType(self.value) - elif self.type == 'integer': - return int(self.value) - elif self.type == 'string': - return str(self.value) - elif self.type == 'datetime': - return datetime.datetime(self.value) - elif self.type == 'null': - return None - elif self.type == 'float': - return float(self.value) - else: - raise IndexError("Unknown type: %s" % self.type) - - @staticmethod - def create(o): - temp_t = type(o) - - #TODO: DRY this up: refactor out into to_pyple_type() helper function - if temp_t is Expression: - t = 'expression' - elif temp_t is types.BooleanType: - t = 'boolean' - elif temp_t is types.IntType: - t = 'integer' - elif temp_t is types.StringType: - t = 'string' - elif temp_t is datetime.datetime: - t = 'datetime' - elif temp_t is types.NoneType: - t = 'null' - elif temp_t is types.FloatType: - t = 'float' - else: - raise TypeError("Unknown type: %s" % str(temp_t)) - - return Element(type=t, value=o) - - def __str__(self): - """Return string representation of Element""" - return "PyPLE Element of type " + str(self.type) + "; value = " + str(self.value) + #TODO: stub + print "STUB: Action.get_parameters() called" -########################################################################################## - -class Operator(SQLObject): +class ActionFunction(SQLObject): + #TODO: stub - engines = ['internal', 'python', 'shell', 'perl'] + code = StringCol(notNone=False, default="print 'Default ActionFunction; len(str(data)) =', len(str(data))") - # Columns - name = StringCol(length=200) - engine = EnumCol(enumValues=engines, default='python') - code = ForeignKey('Code') - - # Meta - class sqlmeta: - table = "pyple_operator" - - # Methods - - def _get_function(self): + def invoke(self, parameters, data): try: - if self.fx is not None: - return self.fx - else: # no function set - #print "fx is None" - if self.code is not None: - self.fx = self.code.function - return self.fx - #print "* about to eval() Operator code..." - ##print "self.code is a:", str(type(self.code)) - #self.function = eval(self.code.content, {}, {}) - #return self.fx - else: - raise Exception("No function or Code set; don't know how to continue!") - except AttributeError: - #print "No fx" - if self.code is not None: - #print "* about to eval() Operator code... (no fx)" - #print "self.code is a:", str(type(self.code)) - self.fx = self.code.function - return self.fx + junk = self.evaled_code except: - raise Exception("Error in Operator._get_function()!!") - - #if self.fx is not None: - # return self.fx - #else: # no function set - # if self.code is not None: - # print "* about to eval() Operator code..." - # self.function = eval(self.code, {}, {}) - # else: - # raise Exception("No function or Code set; don't know how to continue!") + print "** about to eval() Python code: ", code + self.evaled_code = eval(code, {}, {}) #run Python eval() on code (in sandbox) + + +class RuleSet(SQLObject): + root_rule = ForeignKey('Operator') # e.g. AND rule at root of rule tree + actions = RelatedJoin('Action') + name = StringCol(length=100) - def _set_function(self, f): - print "Setting function for Operator %s" % self.name - self.fx = f + def eval(self, data): + """ + Evaluate rules against data; return True/False + """ + return self.root_rule.eval(data) - def eval(self, LHS=None, RHS=None): + def invoke(self, data): """ - Perform an operation on LHS and RHS + Invoke actions on data (does not evaluate rules) """ - #print "**Operator.eval() called." - if self.function 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) - #return Element.Element(self.eval_function(LHS.eval(), RHS.eval())) - - left = None - right = None - - if type(LHS) in [Element, Expression]: - left = LHS.eval() - else: - left = LHS - - if type(RHS) in [Element, Expression]: - right = RHS.eval() - else: - right = RHS - - return self.function(left, right) + if root_rule.eval(data): + for action in actions: + action.invoke(data) + def eval_and_invoke(self, data): + """ + Evaluate rules against data, then invoke actions if result is True + """ + if self.eval(data): + self.invoke(data) - # Functions for internal operators - @staticmethod - def op_and(LHS, RHS): - """Internal AND operator""" - #print "** Internal AND operator called. LHS=",LHS,"; RHS=",RHS - return (LHS and RHS) - - @staticmethod - def op_or(LHS, RHS): - """Internal OR operator""" - return (LHS or RHS) - - @staticmethod - def op_not(LHS, RHS): - """Internal NOT operator""" - return (LHS and not RHS) - - @staticmethod - def op_xor(LHS, RHS): - """Internal XOR operator""" - return ( (LHS and not RHS) or (RHS and not LHS) ) - - @staticmethod - def op_nand(LHS, RHS): - """Internal NAND operator""" - #TODO: is this really what NAND is supposed to do? - if (LHS and RHS): - return False - else: - return True - + def get_by_name(name): + """ + Fetches a single RuleSet instance by name. + """ + return RuleSet.selectBy(name=name)[0] -########################################################################################## +PYPLE_TABLES = [Parameter, Operator, Regex, CIRegex, Action, ActionFunction, RuleSet, AND] -class Code(SQLObject): - - """ - Code for running Operators - """ - # Columns - name = StringCol(length=200) - content = StringCol() - type = EnumCol(enumValues=['interpreted','binary','pickled'], default='interpreted') - engine = EnumCol(enumValues=Operator.engines, default='python') #ForeignKey('Engine') - - # Meta - class sqlmeta: - table = "pyple_code" - - # Methods - #TODO: add methods, etc. - - def _get_function(self): - if self.type=='interpreted' and self.engine=='python': - #return eval(self.content, {}, {}) - return eval("lambda LHS, RHS: " + self.content) - else: - raise Exception("Non-Python function generation not yet implemented.") -########################################################################################## - class Engine: - """ - PyPLE engine class. - """ - def operator(self, name): - return list(Operator.selectBy(name=name))[0] - - def __init__(self, debug=0, dburi=None): - """ - PyPLE Engine constructor - """ + def __init__(self, debug=DEBUG): self.debuglevel = debug - self.connect_to_db(dburi) - - # Bind functions to internal operators - internal_operators = list(Operator.selectBy(engine='internal')) - internal_functions = { - 'AND': Operator.op_and, - 'OR': Operator.op_or, - 'NOT': Operator.op_not, - 'XOR': Operator.op_xor, - 'NAND': Operator.op_nand - } - for op in internal_operators: - op.function = internal_functions[op.name] + self.dbconnection = None - #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) - @staticmethod def build_db_uri(d): - """ - Builds a SQLObject database connection URI from dictionary of connection parameters. - The dictionary should have the following keys: - dbtype e.g. 'mysql' - username - password - host - port - database - """ - uri = d['dbtype'] + "://" + d['username'] + ":" + d['password'] + "@" + d['host'] + ":" + str(d['port']) + "/" + d['database'] - return uri + """ + Build database connection URI from dictionary of connection parameters + """ + uri = "%s://%s:%s@%s:%d/%s" % (d['dbtype'], d['username'], d['password'], d['host'], d['port'], d['database']) + if DEBUG: + uri = uri + "?debug=1" + return uri def connect_to_db(self, uri): - if self.debuglevel > 0: - print "Connecting to DB with: %s" % uri - - self.dbconnection = connectionForURI(uri) - sqlhub.processConnection = self.dbconnection - - if self.debuglevel > 0: - print "Connected to DB: %s" % self.dbconnection - -########################################################################################## - -def create_tables(): - """ - Issue CREATE TABLE commands via SQLObject - """ + if self.debuglevel > 0: + print "Connecting to DB with: %s" % uri + + self.dbconnection = connectionForURI(uri) + sqlhub.processConnection = self.dbconnection + if self.debuglevel > 0: + print "Connected to DB: %s" % self.dbconnection - # Connect to DB (must have create table privileges on target DB) - import syck - dburi = Engine.build_db_uri(syck.load(open("root.yaml").read())) - sqlhub.processConnection = connectionForURI(dburi) + def create_tables(self): + for table in PYPLE_TABLES: + table.createTable() - # Create tables - BasePyPLEType.createTable() - Expression.createTable() - Element.createTable() - Operator.createTable() - Code.createTable() - print "CREATE TABLEs done." - - # Add internal operators - for opname in RESERVED_OPERATORS: - o = Operator(name=opname, engine='internal', code=None) - print "Added Operator %s" % o.name + def drop_tables(self): + for table in PYPLE_TABLES: + table.dropTable(ifExists=True) + if __name__ == "__main__": - print PYPLE_TAGLINE - print PYPLE_COPYRIGHT - print - #TODO: handle params; if "--create-tables", do create_tables() + import yaml #PyYAML: YAML parser/emitter - because its easy_install isn't b0rked like PySyck's: see http://pyyaml.org/ticket/44 + E = Engine() + E.connect_to_db(Engine.build_db_uri(yaml.load(open('pyple-db.yaml').read()))) + E.drop_tables() + E.create_tables() - print "-"*40 - print "Instantiating PyPLE Engine object: ", - import syck - dburi = Engine.build_db_uri(syck.load(open("mysql.yaml").read())) - P = Engine(debug=1, dburi=dburi) - print "Done." - print "-"*40 + andtf = AND(params=[True, False]) + print "andtf:", andtf + print "andtf.eval():", andtf.eval() - print "Test 0:" - l1 = Element.create(2) - r1 = Element.create(False) - and_op = P.operator('AND') #selectBy(name='AND') - print "and_op:", and_op - print "function0:", and_op.function - restult0 = and_op.eval(l1, r1) - print "Test 0 result:" - print result0 + txt = "ORDER, for the reasons set forth in the related Memoranda Opinions issued in this matter on 06/30/06 and 10/10/06, and for good cause, the final Markman definitions applicable to the disputed claim terms and phrases are as follows: (see Order for details). Signed by Judge T. S. Ellis III on 10/10/06. Copies mailed: yes (pmil) (Entered: 10/12/2006)" + ### Operator tests ### - print "*" * ASTERISKS - print "Testing 1: " - code1 = Code(name='always_true', content="True") - o_at = Operator(name='always_true', engine='python', code=code1) - print "function:", o_at.function - result1 = o_at.eval(l1, r1) - print "Test 1:", result1 + starts_with_order = Regex(params=["^ORDER"]) ### + print "starts_with_order:", starts_with_order.eval(txt) + contains_markman = CIRegex(params=["markman"]) + print "contains_markman:", contains_markman.eval(txt) + both = AND(params=[starts_with_order, contains_markman]) + print "both:", both.eval(txt) + not_matching = CIRegex(params=["foobar"]) + print "not_matching:", not_matching.eval(txt) + false_and = AND(params=[starts_with_order, not_matching]) + print "false_and:", false_and.eval(txt) + print "false_and (alt. data):", false_and.eval("ORDER re: foobar and stuff") - print "*" * ASTERISKS - print "Testing 2: " - code2 = "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 + ### RuleSet tests ### - 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." + print "initializing RuleSet" + rs = RuletSet(name="test_ruleset") + rs.root_rule = both + actionfunction1 = ActionFunction() + action1 = Action(function=actionfunction1) + rs.addAction(action1) + print "rs.eval():", rs.eval(txt) + rs.eval_and_invoke(txt) -########################################################################################## \ No newline at end of file + +################################################################################################## +# v0.1.0 below... +################################################################################################## + +#class Operator: +# +# def __init__(self, arguments=None): +# if arguments is None: +# self.arguments = [] +# else: +# self.arguments = arguments +# +# def pre_eval(self, data): +# """ +# Runs eval() on any child Operators in arguments +# """ +# evaled_args = [] +# for arg in arguments: +# if isinstance(arg, Operator): +# evaled_args.append(arg.eval(data)) # pass data down the logic stack +# else: +# evaled_args.append(arg) +# return evaled_args +# +# def eval(self, data): +# return self.eval_function(data) +# +# +#class BooleanOperator(Operator): +# def __init__(self, arguments=None): +# Operator.__init__(self, arguments=arguments) +# +#class AND(BooleanOperator): +# def eval_function(self, data): +# for datum in data: +# if not datum: +# return False +# return True +# +#class OR(BooleanOperator): +# def eval_function(self, data): +# for datum in data: +# if datum: +# return True +# return False +# +#class NOT(BooleanOperator): +# def eval_function(self, data): +# if len(data) != 2: +# raise ValueError("wrong size data list (must be 2 elements long") #TODO: refactor to something like check_length(data, 2) +# return data[0] and not data[1] +# +#class XOR(BooleanOperator): +# def eval_function(self, data): +# if len(data) != 2: +# raise ValueError("wrong size data list (must be 2 elements long") #TODO: refactor to something like check_length(data, 2) +# return (data[0] or data[1]) and not (data[0] and data[1]) +# +#class NAND(BooleanOperator): +# def eval_function(self, data): +# if len(data) != 2: +# raise ValueError("wrong size data list (must be 2 elements long") #TODO: refactor to something like check_length(data, 2) +# if data[0] and data[1]: +# return False +# else: +# return True +# +#class MatchRegex(Operator): +# def __init__(self, arguments=None, case_sensitive=True): +# """ +# arguments should be a 1-element list string with the regex pattern as a string +# """ +# Operator.__init__(self, arguments=arguments) +# self.regexes = [] +# for arg in self.arguments: +# if case_sensitive: +# self.regexes.append(re.compile(arg)) +# else: +# self.regexes.append(re.compile(arg, re.IGNORECASE)) +# +# def eval_function(self, data): +# """ +# Data should be a string to match against +# """ +# for expr in self.regexes: +# result = expr.search(data) +# if result: +# return True +# return False +# +#class MatchRegexCI(MatchRegex): # case-insensitive +# def __init__(self, arguments=None): +# MatchRegex.__init__(self, arguments=arguments, case_sensitive=False) +# +# +#class Engine: +# @staticmethod +# def build_db_uri(self, d): +# """ +# Build database connection URI from dictionary of connection parameters +# """ +# uri = "%s://%s:%s@%s:%d/%s" % (d['dbtype'], d['username'], d['password'], d['host'], d['port'], d['database']) +# return uri +# +# def connect_to_db(self, uri): +# if self.debuglevel > 0: +# print "Connecting to DB with: %s" % uri +# +# self.dbconnection = sqlobject.connectionForURI(uri) +# if self.debuglevel > 0: +# print "Connected to DB: %s" % self.dbconnection +# +# def create_tables(self): +# for table in PYPLE_TABLES: +# table.createTable() +# +# +####### TEST CASES ###### +# +#if __name__ == "__main__": +# +# import syck # YAML parser +# dburi = Engine.build_db_uri(syck.load(open("pyple-db.yaml"))) +# E = Engine(debug=1, dburi=dburi) +# +# entries = {} +# entries[300] = "ORDER that Synthon's claims of infringement of the '738 Patent, as set forth in Count Two of its Complaint, are hereby DISMISSED with prejudice (see Order for details). Signed by Judge T. S. Ellis III on 08/31/06. Copies mailed: yes (pmil) (Entered: 09/01/2006)" +# entries[301] = "MEMORANDUM OPINION RE: Post-Verdict Markman Opinion. Signed by Judge T. S. Ellis III on 10/10/06. Copies mailed: yes (pmil) (Entered: 10/12/2006)" +# entries[302] = "ORDER, for the reasons set forth in the related Memoranda Opinions issued in this matter on 06/30/06 and 10/10/06, and for good cause, the final Markman definitions applicable to the disputed claim terms and phrases are as follows: (see Order for details). Signed by Judge T. S. Ellis III on 10/10/06. Copies mailed: yes (pmil) (Entered: 10/12/2006)" +# order_defs = ['order', 'opinion'] +# markman_defs = ['markman', 'claim.{0,3}constr'] +# excl = ['Minute Entry', 'ORDER ENLARGING TIME', 'MARKMAN HEARING', 'hearing is set', 'Motion for Leave', 'Motion to Seal', 'DEFERRING a Markman determination', 'Claim Construction Statement', 'in Limine', 'SCHEDULING ORDER', 'parties shall', 'Docket Control', 'page limit', 'page restriction', 'extend time', 'Show Cause'] +# +# starts_with_order = MatchRegex(["^ORDER"]) +# +# is_order = OR( [ MatchRegexCI([pattern]) for pattern in order_defs ] ) +# is_markman = OR( [ MatchRegexCI([pattern]) for pattern in markman_defs ] ) +# not_excluded = AND( [NOT(MatchRegexCI([pattern])) for pattern in excl] ) +# big_statement = AND([is_order, is_markman, not_excluded]) +# +# for key in entries: +# print "Entry #", key +# swo = starts_with_order.eval(entries[key]) +# if swo: +# print "Starts with 'ORDER'." +# else: +# print "Does not start with 'ORDER'." +# +# result = big_statement.eval([entries[key]]) +# print "Is #", key, "a Markman order???", result +# print "-"*40 +# +# print "The end." \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2007-01-25 01:03:26
|
Revision: 15 http://svn.sourceforge.net/pyple/?rev=15&view=rev Author: anseljh Date: 2007-01-24 17:03:27 -0800 (Wed, 24 Jan 2007) Log Message: ----------- add svn:keywords properties Property Changed: ---------------- src/pyple.py Property changes on: src/pyple.py ___________________________________________________________________ Name: svn:keywords + Date,Revision,Id This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2007-01-25 00:54:13
|
Revision: 14 http://svn.sourceforge.net/pyple/?rev=14&view=rev Author: anseljh Date: 2007-01-24 16:54:13 -0800 (Wed, 24 Jan 2007) Log Message: ----------- add new replacement code Added Paths: ----------- src/pyple.py src/setup.py Added: src/pyple.py =================================================================== --- src/pyple.py (rev 0) +++ src/pyple.py 2007-01-25 00:54:13 UTC (rev 14) @@ -0,0 +1,566 @@ +#!/usr/bin/env python +""" +PyPLE (say "pipple") -- the Python Persistent Logic Engine + +pyple.py: All things PyPLE are in this file! + +Copyright (C) 2006-2007 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. +v0.1.0 Port to SQLObject for database persistence begun - 1/22/07 +v0.2.0 SQLObject version merged into one file for simplicity - 1/22/07 +""" + +# Interesting tokens to look for in this source code: +# #TODO: Items that need doing +# #BUG: Identified bug +# #NOTE: Note by author + +__revision__ = "$Id$" +__author__ = 'Ansel Halliburton (anseljh at users dot sourceforge dot net)' +#__date__ = '$RevisionDate$'.split()[1].replace('/', '-') +__version__ = '$Revision: 7 $' +__release__ = (0,2,0,'alpha',0) + +PYPLE_TAGLINE = "PyPLE (say \"pipple\") -- the Python Persistent Logic Engine" +PYPLE_COPYRIGHT = "Copyright (c) 2006-2007 Ansel Halliburton." +ASTERISKS = 40 # number of asterisks to use as separator in debug/test output +RESERVED_OPERATORS = ['AND', 'OR', 'NOT', 'XOR', 'NAND'] + +########################################################################################## + +from sqlobject import * # SQLObject ORM +from sqlobject.inheritance import InheritableSQLObject # Inheritance for Element, Expression classes +from datetime import datetime +import types +import re + +########################################################################################## + +class BasePyPLEType(InheritableSQLObject): + """ + Base class/interface for Element and Expression persistent types + """ + + # Meta + class sqlmeta: + table = "pyple_base_pyple_type" + + # Methods + def eval(self): + """ + Both Element and Expression should have eval() methods. + """ + pass + +########################################################################################## + +class Expression(BasePyPLEType): + """ + Expressions are composed of a left-hand-side (LHS), a right-hand-side (RHS), and + an Operator (op). LHS and RHS can be either an Element or an Expression. + """ + + # Columns + operator = ForeignKey('Operator') + LHS = ForeignKey('BasePyPLEType') # can also be Expression! + RHS = ForeignKey('BasePyPLEType') # can also be Expression! + + # Meta + class sqlmeta: + table = "pyple_expression" + + # Methods + 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 + + if type(self.LHS) is Expression: + L = self.LHS.eval() + elif type(self.LHS) is Element: + L = self.LHS + else: + raise TypeError("not an Element: %s" % str(L)) + + if type(self.RHS) is Expression: + R = self.RHS.eval() + elif type(self.RHS) is Element: + R = self.RHS + else: + raise TypeError("not an Element: %s" % str(R)) + + #perform operation and return Element + return self.operator.eval(L, R) + +########################################################################################## + +class Element(BasePyPLEType): + + # Columns + + types = ['element', 'expression', 'boolean', 'integer', 'string', 'datetime', 'null', 'float'] + + type = EnumCol(enumValues=types) + value = PickleCol(length=2**24) + + # Meta + class sqlmeta: + table = "pyple_element" + + # Methods + + def eval(self): + """ + eval() on an Element returns a native Python object. + """ + + if self.type == 'expression': + return Expression.Expression(self.value) + elif self.type == 'boolean': + return types.BooleanType(self.value) + elif self.type == 'integer': + return int(self.value) + elif self.type == 'string': + return str(self.value) + elif self.type == 'datetime': + return datetime.datetime(self.value) + elif self.type == 'null': + return None + elif self.type == 'float': + return float(self.value) + else: + raise IndexError("Unknown type: %s" % self.type) + + @staticmethod + def create(o): + temp_t = type(o) + + #TODO: DRY this up: refactor out into to_pyple_type() helper function + if temp_t is Expression: + t = 'expression' + elif temp_t is types.BooleanType: + t = 'boolean' + elif temp_t is types.IntType: + t = 'integer' + elif temp_t is types.StringType: + t = 'string' + elif temp_t is datetime.datetime: + t = 'datetime' + elif temp_t is types.NoneType: + t = 'null' + elif temp_t is types.FloatType: + t = 'float' + else: + raise TypeError("Unknown type: %s" % str(temp_t)) + + return Element(type=t, value=o) + + def __str__(self): + """Return string representation of Element""" + return "PyPLE Element of type " + str(self.type) + "; value = " + str(self.value) + +########################################################################################## + +class Operator(SQLObject): + + engines = ['internal', 'python', 'shell', 'perl'] + + # Columns + name = StringCol(length=200) + engine = EnumCol(enumValues=engines, default='python') + code = ForeignKey('Code') + + # Meta + class sqlmeta: + table = "pyple_operator" + + # Methods + + def _get_function(self): + try: + if self.fx is not None: + return self.fx + else: # no function set + #print "fx is None" + if self.code is not None: + self.fx = self.code.function + return self.fx + #print "* about to eval() Operator code..." + ##print "self.code is a:", str(type(self.code)) + #self.function = eval(self.code.content, {}, {}) + #return self.fx + else: + raise Exception("No function or Code set; don't know how to continue!") + except AttributeError: + #print "No fx" + if self.code is not None: + #print "* about to eval() Operator code... (no fx)" + #print "self.code is a:", str(type(self.code)) + self.fx = self.code.function + return self.fx + except: + raise Exception("Error in Operator._get_function()!!") + + #if self.fx is not None: + # return self.fx + #else: # no function set + # if self.code is not None: + # print "* about to eval() Operator code..." + # self.function = eval(self.code, {}, {}) + # else: + # raise Exception("No function or Code set; don't know how to continue!") + + def _set_function(self, f): + print "Setting function for Operator %s" % self.name + self.fx = f + + def eval(self, LHS=None, RHS=None): + """ + Perform an operation on LHS and RHS + """ + #print "**Operator.eval() called." + if self.function 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) + #return Element.Element(self.eval_function(LHS.eval(), RHS.eval())) + + left = None + right = None + + if type(LHS) in [Element, Expression]: + left = LHS.eval() + else: + left = LHS + + if type(RHS) in [Element, Expression]: + right = RHS.eval() + else: + right = RHS + + return self.function(left, right) + + + # Functions for internal operators + + @staticmethod + def op_and(LHS, RHS): + """Internal AND operator""" + #print "** Internal AND operator called. LHS=",LHS,"; RHS=",RHS + return (LHS and RHS) + + @staticmethod + def op_or(LHS, RHS): + """Internal OR operator""" + return (LHS or RHS) + + @staticmethod + def op_not(LHS, RHS): + """Internal NOT operator""" + return (LHS and not RHS) + + @staticmethod + def op_xor(LHS, RHS): + """Internal XOR operator""" + return ( (LHS and not RHS) or (RHS and not LHS) ) + + @staticmethod + def op_nand(LHS, RHS): + """Internal NAND operator""" + #TODO: is this really what NAND is supposed to do? + if (LHS and RHS): + return False + else: + return True + + +########################################################################################## + +class Code(SQLObject): + + """ + Code for running Operators + """ + # Columns + name = StringCol(length=200) + content = StringCol() + type = EnumCol(enumValues=['interpreted','binary','pickled'], default='interpreted') + engine = EnumCol(enumValues=Operator.engines, default='python') #ForeignKey('Engine') + + # Meta + class sqlmeta: + table = "pyple_code" + + # Methods + #TODO: add methods, etc. + + def _get_function(self): + if self.type=='interpreted' and self.engine=='python': + #return eval(self.content, {}, {}) + return eval("lambda LHS, RHS: " + self.content) + else: + raise Exception("Non-Python function generation not yet implemented.") + +########################################################################################## + +class Engine: + """ + PyPLE engine class. + """ + + def operator(self, name): + return list(Operator.selectBy(name=name))[0] + + def __init__(self, debug=0, dburi=None): + """ + PyPLE Engine constructor + """ + self.debuglevel = debug + self.connect_to_db(dburi) + + # Bind functions to internal operators + internal_operators = list(Operator.selectBy(engine='internal')) + internal_functions = { + 'AND': Operator.op_and, + 'OR': Operator.op_or, + 'NOT': Operator.op_not, + 'XOR': Operator.op_xor, + 'NAND': Operator.op_nand + } + for op in internal_operators: + op.function = internal_functions[op.name] + + #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) + + @staticmethod + def build_db_uri(d): + """ + Builds a SQLObject database connection URI from dictionary of connection parameters. + The dictionary should have the following keys: + dbtype e.g. 'mysql' + username + password + host + port + database + """ + uri = d['dbtype'] + "://" + d['username'] + ":" + d['password'] + "@" + d['host'] + ":" + str(d['port']) + "/" + d['database'] + return uri + + def connect_to_db(self, uri): + if self.debuglevel > 0: + print "Connecting to DB with: %s" % uri + + self.dbconnection = connectionForURI(uri) + sqlhub.processConnection = self.dbconnection + + if self.debuglevel > 0: + print "Connected to DB: %s" % self.dbconnection + +########################################################################################## + +def create_tables(): + """ + Issue CREATE TABLE commands via SQLObject + """ + + # Connect to DB (must have create table privileges on target DB) + import syck + dburi = Engine.build_db_uri(syck.load(open("root.yaml").read())) + sqlhub.processConnection = connectionForURI(dburi) + + # Create tables + BasePyPLEType.createTable() + Expression.createTable() + Element.createTable() + Operator.createTable() + Code.createTable() + print "CREATE TABLEs done." + + # Add internal operators + for opname in RESERVED_OPERATORS: + o = Operator(name=opname, engine='internal', code=None) + print "Added Operator %s" % o.name + +if __name__ == "__main__": + print PYPLE_TAGLINE + print PYPLE_COPYRIGHT + print + + #TODO: handle params; if "--create-tables", do create_tables() + + print "-"*40 + print "Instantiating PyPLE Engine object: ", + import syck + dburi = Engine.build_db_uri(syck.load(open("mysql.yaml").read())) + P = Engine(debug=1, dburi=dburi) + print "Done." + print "-"*40 + + print "Test 0:" + l1 = Element.create(2) + r1 = Element.create(False) + and_op = P.operator('AND') #selectBy(name='AND') + print "and_op:", and_op + print "function0:", and_op.function + restult0 = and_op.eval(l1, r1) + print "Test 0 result:" + print result0 + + + print "*" * ASTERISKS + print "Testing 1: " + code1 = Code(name='always_true', content="True") + o_at = Operator(name='always_true', engine='python', code=code1) + print "function:", o_at.function + result1 = o_at.eval(l1, r1) + print "Test 1:", result1 + + print "*" * ASTERISKS + print "Testing 2: " + code2 = "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." + +########################################################################################## \ No newline at end of file Added: src/setup.py =================================================================== --- src/setup.py (rev 0) +++ src/setup.py 2007-01-25 00:54:13 UTC (rev 14) @@ -0,0 +1,46 @@ +#!/usr/bin/env python +""" +PyPLE (say "pipple") -- the Python Persistent Logic Engine + +setup.py: Distutils script + +Copyright (C) 2006-2007 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.2.0', + description='PyPLE (pronounced "pipple") is the Python Persistent Logic Engine -- a framework for composing, evaluating, and storing logical expressions.', + author='Ansel Halliburton', + author_email='an...@us...', + keywords=['logic','engine','expression','database'], + url='http://pyple.sourceforge.net/', + license='BSD License', + classifiers=['Development Status :: 2 - Pre-Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules'], + py_modules=['pyple'], +) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2007-01-25 00:51:37
|
Revision: 13 http://svn.sourceforge.net/pyple/?rev=13&view=rev Author: anseljh Date: 2007-01-24 16:51:37 -0800 (Wed, 24 Jan 2007) Log Message: ----------- update year, link in license file Modified Paths: -------------- doc/LICENSE Modified: doc/LICENSE =================================================================== --- doc/LICENSE 2007-01-25 00:48:31 UTC (rev 12) +++ doc/LICENSE 2007-01-25 00:51:37 UTC (rev 13) @@ -1,19 +1,22 @@ PyPLE (say "pipple") -- the Python Persistent Logic Engine -Copyright (C) 2006 Ansel Halliburton. +Copyright (C) 2006-2007 Ansel Halliburton. All rights reserved. PyPLE is licensed under the BSD License. -To find out more about the license, go to <TODO>. +To find out more about the license, go to http://opensource.org/licenses/bsd-license.php. The full terms of the BSD License are as follows: Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: +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 was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2007-01-25 00:48:33
|
Revision: 12 http://svn.sourceforge.net/pyple/?rev=12&view=rev Author: anseljh Date: 2007-01-24 16:48:31 -0800 (Wed, 24 Jan 2007) Log Message: ----------- delete old db dump Removed Paths: ------------- db/mysql/pyple_dev.sql Deleted: db/mysql/pyple_dev.sql =================================================================== --- db/mysql/pyple_dev.sql 2007-01-25 00:47:40 UTC (rev 11) +++ db/mysql/pyple_dev.sql 2007-01-25 00:48:31 UTC (rev 12) @@ -1,190 +0,0 @@ --- 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'); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2007-01-25 00:47:41
|
Revision: 11 http://svn.sourceforge.net/pyple/?rev=11&view=rev Author: anseljh Date: 2007-01-24 16:47:40 -0800 (Wed, 24 Jan 2007) Log Message: ----------- delete old code; delete old db dump Removed Paths: ------------- src/Code.py src/Element.py src/Expression.py src/Operator.py src/PyPLE.py src/PyPLEType.py src/__init__.py src/setup.py Deleted: src/Code.py =================================================================== --- src/Code.py 2006-04-18 15:13:34 UTC (rev 10) +++ src/Code.py 2007-01-25 00:47:40 UTC (rev 11) @@ -1,38 +0,0 @@ -#!/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 Deleted: src/Element.py =================================================================== --- src/Element.py 2006-04-18 15:13:34 UTC (rev 10) +++ src/Element.py 2007-01-25 00:47:40 UTC (rev 11) @@ -1,74 +0,0 @@ -#!/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) Deleted: src/Expression.py =================================================================== --- src/Expression.py 2006-04-18 15:13:34 UTC (rev 10) +++ src/Expression.py 2007-01-25 00:47:40 UTC (rev 11) @@ -1,78 +0,0 @@ -#!/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) Deleted: src/Operator.py =================================================================== --- src/Operator.py 2006-04-18 15:13:34 UTC (rev 10) +++ src/Operator.py 2007-01-25 00:47:40 UTC (rev 11) @@ -1,84 +0,0 @@ -#!/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) Deleted: src/PyPLE.py =================================================================== --- src/PyPLE.py 2006-04-18 15:13:34 UTC (rev 10) +++ src/PyPLE.py 2007-01-25 00:47:40 UTC (rev 11) @@ -1,275 +0,0 @@ -#!/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 - -__revision__ = "$Id$" -__author__ = 'Ansel Halliburton (anseljh at users dot sourceforge dot net)' -__date__ = '$RevisionDate$'.split()[1].replace('/', '-') -__version__ = '$Revision$' -__release__ = (0,0,1,'alpha',0) - -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." Deleted: src/PyPLEType.py =================================================================== --- src/PyPLEType.py 2006-04-18 15:13:34 UTC (rev 10) +++ src/PyPLEType.py 2007-01-25 00:47:40 UTC (rev 11) @@ -1,107 +0,0 @@ -#!/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] Deleted: src/__init__.py =================================================================== Deleted: src/setup.py =================================================================== --- src/setup.py 2006-04-18 15:13:34 UTC (rev 10) +++ src/setup.py 2007-01-25 00:47:40 UTC (rev 11) @@ -1,45 +0,0 @@ -#!/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='PyPLE (pronounced "pipple") is the Python Persistent Logic Engine -- a framework for composing, evaluating, and storing logical expressions.', - author='Ansel Halliburton', - author_email='an...@us...', - keywords=['logic','engine',expression'], - url='http://pyple.sourceforge.net/', - license='BSD License', - classifiers=['Development Status :: 2 - Pre-Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules'], - 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. |
From: <an...@us...> - 2006-04-18 15:13:45
|
Revision: 10 Author: anseljh Date: 2006-04-18 08:13:34 -0700 (Tue, 18 Apr 2006) ViewCVS: http://svn.sourceforge.net/pyple/?rev=10&view=rev Log Message: ----------- added doc directory Added Paths: ----------- doc/ doc/LICENSE doc/README Added: doc/LICENSE =================================================================== --- doc/LICENSE (rev 0) +++ doc/LICENSE 2006-04-18 15:13:34 UTC (rev 10) @@ -0,0 +1,30 @@ +PyPLE (say "pipple") -- the Python Persistent Logic Engine +Copyright (C) 2006 Ansel Halliburton. +All rights reserved. + +PyPLE is licensed under the BSD License. +To find out more about the license, go to <TODO>. + +The full terms of the BSD License are as follows: + +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. Added: doc/README =================================================================== This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2006-04-13 01:04:42
|
Revision: 9 Author: anseljh Date: 2006-04-12 18:04:39 -0700 (Wed, 12 Apr 2006) ViewCVS: http://svn.sourceforge.net/pyple/?rev=9&view=rev Log Message: ----------- added SF logo and removed rev date Modified Paths: -------------- www/index.html Modified: www/index.html =================================================================== --- www/index.html 2006-04-13 01:00:37 UTC (rev 8) +++ www/index.html 2006-04-13 01:04:39 UTC (rev 9) @@ -17,8 +17,7 @@ <li><a href="mailto:anseljh at users dot sourceforge dot net">Email Ansel Halliburton, the founder/maintainer/everything</a></li> </ul> - <p><a href="http://sourceforge.net/donate/index.php?group_id=164858"><img src="http://images.sourceforge.net/images/project-support.jpg" width="88" height="32" border="0" alt="Support This Project" /></a></p> + <p><a href="http://sourceforge.net/donate/index.php?group_id=164858"><img src="http://images.sourceforge.net/images/project-support.jpg" width="88" height="32" border="0" alt="Support This Project" /></a><a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=164858&type=1" width="88" height="31" border="0" alt="SourceForge.net Logo" /></a></p> - <p>Revision: $LastChangedDate$</p> </body> </html> \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2006-04-13 01:00:41
|
Revision: 8 Author: anseljh Date: 2006-04-12 18:00:37 -0700 (Wed, 12 Apr 2006) ViewCVS: http://svn.sourceforge.net/pyple/?rev=8&view=rev Log Message: ----------- changed keyword for date Modified Paths: -------------- www/index.html Modified: www/index.html =================================================================== --- www/index.html 2006-04-13 00:59:43 UTC (rev 7) +++ www/index.html 2006-04-13 01:00:37 UTC (rev 8) @@ -19,6 +19,6 @@ <p><a href="http://sourceforge.net/donate/index.php?group_id=164858"><img src="http://images.sourceforge.net/images/project-support.jpg" width="88" height="32" border="0" alt="Support This Project" /></a></p> - <p>Revision: $Revision$</p> + <p>Revision: $LastChangedDate$</p> </body> </html> \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2006-04-13 00:59:47
|
Revision: 7 Author: anseljh Date: 2006-04-12 17:59:43 -0700 (Wed, 12 Apr 2006) ViewCVS: http://svn.sourceforge.net/pyple/?rev=7&view=rev Log Message: ----------- Changed keyword for revision date Modified Paths: -------------- src/PyPLE.py Modified: src/PyPLE.py =================================================================== --- src/PyPLE.py 2006-04-13 00:59:17 UTC (rev 6) +++ src/PyPLE.py 2006-04-13 00:59:43 UTC (rev 7) @@ -49,7 +49,7 @@ __revision__ = "$Id$" __author__ = 'Ansel Halliburton (anseljh at users dot sourceforge dot net)' -__date__ = '$Date$'.split()[1].replace('/', '-') +__date__ = '$RevisionDate$'.split()[1].replace('/', '-') __version__ = '$Revision$' __release__ = (0,0,1,'alpha',0) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2006-04-13 00:59:21
|
Revision: 6 Author: anseljh Date: 2006-04-12 17:59:17 -0700 (Wed, 12 Apr 2006) ViewCVS: http://svn.sourceforge.net/pyple/?rev=6&view=rev Log Message: ----------- added more metadata for Cheese Shop Modified Paths: -------------- src/setup.py Modified: src/setup.py =================================================================== --- src/setup.py 2006-04-13 00:57:49 UTC (rev 5) +++ src/setup.py 2006-04-13 00:59:17 UTC (rev 6) @@ -34,9 +34,12 @@ setup(name='PyPLE', version='0.0.1', - description='Python Persistent Logic Engine', + description='PyPLE (pronounced "pipple") is the Python Persistent Logic Engine -- a framework for composing, evaluating, and storing logical expressions.', author='Ansel Halliburton', author_email='an...@us...', - url='http://www.anseljh/code/pyple/', + keywords=['logic','engine',expression'], + url='http://pyple.sourceforge.net/', + license='BSD License', + classifiers=['Development Status :: 2 - Pre-Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules'], 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. |
From: <an...@us...> - 2006-04-13 00:57:58
|
Revision: 5 Author: anseljh Date: 2006-04-12 17:57:49 -0700 (Wed, 12 Apr 2006) ViewCVS: http://svn.sourceforge.net/pyple/?rev=5&view=rev Log Message: ----------- added author email and set keywords Modified Paths: -------------- www/index.html Property Changed: ---------------- www/index.html Modified: www/index.html =================================================================== --- www/index.html 2006-04-13 00:44:48 UTC (rev 4) +++ www/index.html 2006-04-13 00:57:49 UTC (rev 5) @@ -14,8 +14,11 @@ <li><a href="http://svn.sourceforge.net/viewcvs.cgi/pyple/">Browse Subversion code repository</a></li> <li><a href="http://cia.navi.cx/stats/project/pyple">Stats on CIA</a></li> <li><a href="http://python.org/pypi/PyPLE/">Info in Python Cheese Shop</a></li> + <li><a href="mailto:anseljh at users dot sourceforge dot net">Email Ansel Halliburton, the founder/maintainer/everything</a></li> </ul> - <a href="http://sourceforge.net/donate/index.php?group_id=164858"><img src="http://images.sourceforge.net/images/project-support.jpg" width="88" height="32" border="0" alt="Support This Project" /></a> + <p><a href="http://sourceforge.net/donate/index.php?group_id=164858"><img src="http://images.sourceforge.net/images/project-support.jpg" width="88" height="32" border="0" alt="Support This Project" /></a></p> + + <p>Revision: $Revision$</p> </body> </html> \ No newline at end of file Property changes on: www/index.html ___________________________________________________________________ Name: svn:keywords + Rev,Date,LastChangedDate,Revision This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2006-04-13 00:44:58
|
Revision: 4 Author: anseljh Date: 2006-04-12 17:44:48 -0700 (Wed, 12 Apr 2006) ViewCVS: http://svn.sourceforge.net/pyple/?rev=4&view=rev Log Message: ----------- adding index.html Added Paths: ----------- www/index.html Added: www/index.html =================================================================== --- www/index.html (rev 0) +++ www/index.html 2006-04-13 00:44:48 UTC (rev 4) @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>PyPLE</title> +</head> +<body> + <h1>PyPLE</h1> + <p>PyPLE (pronounced "pipple") is the Python Persistent Logic Engine -- a framework for composing, evaluating, and storing logical expressions.</p> + + <h2>Links</h2> + <ul> + <li><a href="http://sourceforge.net/projects/pyple">SourceForge project page</a></li> + <li><a href="http://svn.sourceforge.net/viewcvs.cgi/pyple/">Browse Subversion code repository</a></li> + <li><a href="http://cia.navi.cx/stats/project/pyple">Stats on CIA</a></li> + <li><a href="http://python.org/pypi/PyPLE/">Info in Python Cheese Shop</a></li> + </ul> + + <a href="http://sourceforge.net/donate/index.php?group_id=164858"><img src="http://images.sourceforge.net/images/project-support.jpg" width="88" height="32" border="0" alt="Support This Project" /></a> +</body> +</html> \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2006-04-11 03:46:12
|
Revision: 3 Author: anseljh Date: 2006-04-10 20:46:03 -0700 (Mon, 10 Apr 2006) ViewCVS: http://svn.sourceforge.net/pyple/?rev=3&view=rev Log Message: ----------- removed some old comments and made svn:keywords plain Modified Paths: -------------- src/PyPLE.py Modified: src/PyPLE.py =================================================================== --- src/PyPLE.py 2006-04-11 03:41:49 UTC (rev 2) +++ src/PyPLE.py 2006-04-11 03:46:03 UTC (rev 3) @@ -47,20 +47,11 @@ # #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('/', '-') +__revision__ = "$Id$" +__author__ = 'Ansel Halliburton (anseljh at users dot sourceforge dot net)' +__date__ = '$Date$'.split()[1].replace('/', '-') __version__ = '$Revision$' -__release__ = (0,1,0,'alpha',0) -#TODO: check into SVN to update these -#TODO: add SVN keywords (svn:keywords) +__release__ = (0,0,1,'alpha',0) PYPLE_TAGLINE = "PyPLE (say \"pipple\") -- the Python Persistent Logic Engine" PYPLE_COPYRIGHT = "Copyright (c) 2006 Ansel Halliburton. All rights reserved." This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <an...@us...> - 2006-04-11 03:41:54
|
Revision: 2 Author: anseljh Date: 2006-04-10 20:41:49 -0700 (Mon, 10 Apr 2006) ViewCVS: http://svn.sourceforge.net/pyple/?rev=2&view=rev Log Message: ----------- added svn:keywords properties Modified Paths: -------------- src/PyPLE.py Property Changed: ---------------- src/PyPLE.py Modified: src/PyPLE.py =================================================================== --- src/PyPLE.py 2006-04-11 01:41:15 UTC (rev 1) +++ src/PyPLE.py 2006-04-11 03:41:49 UTC (rev 2) @@ -57,7 +57,7 @@ __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 $' +__version__ = '$Revision$' __release__ = (0,1,0,'alpha',0) #TODO: check into SVN to update these #TODO: add SVN keywords (svn:keywords) Property changes on: src/PyPLE.py ___________________________________________________________________ Name: svn:keywords + Author, Id, LastChangedDate, Date, LastChangedBy, Revision This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
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. |