[tryton-debian-vcs] simpleeval branch debian created. 5ff250a58a7130302c2d3818365c5c755b9e1eca

Mathias Behrle tryton-debian-vcs at alioth.debian.org
Sat Apr 25 15:16:12 UTC 2015


The following commit has been merged in the debian branch:
https://alioth.debian.org/plugins/scmgit/cgi-bin/gitweb.cgi/?p=tryton/simpleeval.git;a=commitdiff;h=5ff250a58a7130302c2d3818365c5c755b9e1eca
commit 5ff250a58a7130302c2d3818365c5c755b9e1eca
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Sat Apr 25 17:15:38 2015 +0200

    Disabling temporarily tests for failing test_string_length.

diff --git a/debian/rules b/debian/rules
index a0d8f2c..93b66bc 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,6 +1,10 @@
 #!/usr/bin/make -f
 
 export PYBUILD_NAME := simpleeval
+# disable temporarily testing due to failing test test_string_length
+# https://github.com/danthedeckie/simpleeval/issues/5
+export PYBUILD_DISABLE_python2.7=test
+export PYBUILD_DISABLE_python3.4=test
 
 %:
 	dh ${@} --with python2,python3 --buildsystem=pybuild
commit eb0d4e6f8c9fe69f54970798b4ab7d7689184c11
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Sat Apr 25 17:13:19 2015 +0200

    Adding missing test file with 01-add_testfile.patch.

diff --git a/debian/patches/01-add_testfile.patch b/debian/patches/01-add_testfile.patch
new file mode 100644
index 0000000..71349cb
--- /dev/null
+++ b/debian/patches/01-add_testfile.patch
@@ -0,0 +1,333 @@
+Description: Adding the missing test file.
+ The test file test_simpleeval.py is missing from the release tarball.
+ We provide it here until upstream includes it.
+ .
+ simpleeval (0.8.2-1) unstable; urgency=low
+Author: Mathias Behrle <mathiasb at m9s.biz>
+Bug: https://github.com/danthedeckie/simpleeval/issues/4
+Forwarded: not-needed
+
+--- /dev/null
++++ simpleeval-0.8.2/test_simpleeval.py
+@@ -0,0 +1,321 @@
++'''
++    Unit tests for simpleeval.
++    --------------------------
++
++    Most of this stuff is pretty basic.
++
++'''
++# pylint: disable=too-many-public-methods, missing-docstring
++
++import unittest
++import simpleeval
++from simpleeval import SimpleEval, NameNotDefined, InvalidExpression, simple_eval
++
++class DRYTest(unittest.TestCase):
++    ''' Stuff we need to do every test, let's do here instead..
++        Don't Repeat Yourself. '''
++
++    def setUp(self):
++        ''' initialize a SimpleEval '''
++        self.s = SimpleEval()
++
++    def t(self, expr, shouldbe): #pylint: disable=invalid-name
++        ''' test an evaluation of an expression against an expected answer '''
++        return self.assertEqual(self.s.eval(expr), shouldbe)
++
++class TestBasic(DRYTest):
++    ''' Simple expressions. '''
++
++    def test_maths_with_ints(self):
++        ''' simple maths expressions '''
++
++        self.t("21 + 21", 42)
++        self.t("6*7", 42)
++        self.t("20 + 1 + (10*2) + 1", 42)
++        self.t("100/10", 10)
++        self.t("12*12", 144)
++        self.t("2 ** 10", 1024)
++        self.t("100 % 9", 1)
++
++    def test_bools_and_or(self):
++        self.t('True and False', False)
++        self.t('True or False', True)
++        self.t('1 - 1 or 21', True)
++        self.t('1 - 1 and 11', False)
++        self.t('110 == 100 + 10 and True', True)
++
++    def test_maths_with_floats(self):
++        self.t("11.02 - 9.1", 1.92)
++        self.t("29.1+39", 68.1)
++
++    def test_comparisons(self):
++        # GT & LT:
++        self.t("1 > 0", True)
++        self.t("100000 < 28", False)
++        self.t("-2 < 11", True)
++        self.t("+2 < 5", True)
++        self.t("0 == 0", True)
++
++        # GtE, LtE
++        self.t("-2 <= -2", True)
++        self.t("2 >= 2", True)
++        self.t("1 >= 12", False)
++        self.t("1.09 <= 1967392", True)
++
++    def test_mixed_comparisons(self):
++        self.t("1 > 0.999999", True)
++        self.t("1 == True", True)  # Note ==, not 'is'.
++        self.t("0 == False", True)  # Note ==, not 'is'.
++        self.t("False == False", True)
++        self.t("False < True", True)
++
++    def test_if_else(self):
++        ''' x if y else z '''
++
++        # and test if/else expressions:
++        self.t("'a' if 1 == 1 else 'b'", 'a')
++        self.t("'a' if 1 > 2 else 'b'", 'b')
++
++        # and more complex expressions:
++        self.t("'a' if 4 < 1 else 'b' if 1 == 2 else 'c'", 'c')
++
++    def test_default_conversions(self):
++        ''' conversion between types '''
++
++        self.t('int("20") + int(0.22*100)', 42)
++        self.t('float("42")', 42.0)
++        self.t('"Test Stuff!" + str(11)', u"Test Stuff!11")
++
++class TestFunctions(DRYTest):
++    ''' Functions for expressions to play with '''
++
++    def test_load_file(self):
++        ''' add in a function which loads data from an external file. '''
++
++        # write to the file:
++
++        with open("file.txt", 'w') as f:
++            f.write("42")
++
++        # define the function we'll send to the eval'er
++
++        def load_file(filename):
++            ''' load a file and return its contents '''
++            with open(filename) as f:
++                return f.read()
++
++        # simple load:
++
++        self.s.functions = {u"read": load_file}
++        self.t("read('file.txt')", "42")
++
++        # and we should have *replaced* the default functions. Let's check:
++
++        with self.assertRaises(simpleeval.FunctionNotDefined):
++            self.t("int(read('file.txt'))", 42)
++
++        # OK, so we can load in the default functions as well...
++
++        self.s.functions.update(simpleeval.DEFAULT_FUNCTIONS)
++
++        # now it works:
++
++        self.t("int(read('file.txt'))", 42)
++
++    def test_randoms(self):
++        ''' test the rand() and randint() functions '''
++
++        self.s.functions['type'] = type
++
++        self.t('type(randint(1000))', int)
++        self.t('type(rand())', float)
++
++        self.t("randint(20)<20", True)
++        self.t("rand()<1.0", True)
++
++        # I don't know how to further test these functions.  Ideas?
++
++class TestOperators(DRYTest):
++    ''' Test adding in new operators, removing them, make sure it works. '''
++    pass
++
++class TestTryingToBreakOut(DRYTest):
++    ''' Test various weird methods to break the security sandbox... '''
++
++    def test_import(self):
++        ''' usual suspect. import '''
++        # cannot import things:
++        with self.assertRaises(AttributeError):
++            self.t("import sys", None)
++
++    def test_long_running(self):
++        ''' exponent operations can take a long time. '''
++        old_max = simpleeval.MAX_POWER
++
++        self.t("9**9**5", 9**9**5)
++
++        with self.assertRaises(simpleeval.NumberTooHigh):
++            self.t("9**9**8", 0)
++
++        # and does limiting work?
++
++        simpleeval.MAX_POWER = 100
++
++        with self.assertRaises(simpleeval.NumberTooHigh):
++            self.t("101**2", 0)
++
++        # good, so set it back:
++
++        simpleeval.MAX_POWER = old_max
++
++    def test_string_length(self):
++
++        with self.assertRaises(simpleeval.StringTooLong):
++            self.t("50000*'text'", 0)
++
++        with self.assertRaises(simpleeval.StringTooLong):
++            self.t("'text'*50000", 0)
++
++        with self.assertRaises(simpleeval.StringTooLong):
++            self.t("('text'*50000)*1000", 0)
++
++        with self.assertRaises(simpleeval.StringTooLong):
++            self.t("(50000*'text')*1000", 0)
++
++        self.t("'stuff'*20000", 20000*'stuff')
++
++        self.t("20000*'stuff'", 20000*'stuff')
++
++        with self.assertRaises(simpleeval.StringTooLong):
++            self.t("('stuff'*20000) + ('stuff'*20000) ", 0)
++
++        with self.assertRaises(simpleeval.StringTooLong):
++            self.t("'stuff'*100000", 100000*'stuff')
++
++        with self.assertRaises(simpleeval.StringTooLong):
++            self.t("'" + (10000*"stuff") +"'*100", 0)
++
++        with self.assertRaises(simpleeval.StringTooLong):
++            self.t("'" + (50000 * "stuff") + "'", 0)
++
++    def test_python_stuff(self):
++        ''' other various pythony things. '''
++        # it only evaluates the first statement:
++        self.t("a = 11; x = 21; x + x", 11)
++
++        # list comprehensions don't work:
++        # this could be changed in a future release, if people want...
++        with self.assertRaises(simpleeval.FeatureNotAvailable):
++            self.t("[x for x in (1, 2, 3)]", (1, 2, 3))
++
++class TestNames(DRYTest):
++    ''' 'names', what other languages call variables... '''
++
++    def test_none(self):
++        ''' what to do when names isn't defined, or is 'none' '''
++        with self.assertRaises(NameNotDefined):
++            self.t("a == 2", None)
++
++        self.s.names["s"] = 21
++
++        with self.assertRaises(NameNotDefined):
++            self.t("s += a", 21)
++
++        self.s.names = None
++
++        with self.assertRaises(InvalidExpression):
++            self.t('s', 21)
++
++
++    def test_dict(self):
++        ''' using a normal dict for names lookup '''
++
++        self.s.names = {'a': 42}
++        self.t("a + a", 84)
++
++        self.s.names['also'] = 100
++
++        self.t("a + also - a", 100)
++
++        # however, you can't assign to those names:
++
++        self.t("a = 200", 200)
++
++        self.assertEqual(self.s.names['a'], 42)
++
++        # or assign to lists
++
++        self.s.names['b'] = [0]
++
++        self.t("b[0] = 11", 11)
++
++        self.assertEqual(self.s.names['b'], [0])
++
++        # but you can get items from a list:
++
++        self.s.names['b'] = [6, 7]
++
++        self.t("b[0] * b[1]", 42)
++
++        # or from a dict
++
++        self.s.names['c'] = {'i': 11}
++
++        self.t("c['i']", 11)
++
++        # you still can't assign though:
++
++        self.t("c['b'] = 99", 99)
++
++        self.assertFalse('b' in self.s.names['c'])
++
++        # and going all 'inception' on it doesn't work either:
++
++        self.s.names['c']['c'] = {'c': 11}
++
++        self.t("c['c']['c'] = 21", 21)
++
++        self.assertEqual(self.s.names['c']['c']['c'], 11)
++
++    def test_func(self):
++        ''' using a function for 'names lookup' '''
++
++        def resolver(node): # pylint: disable=unused-argument
++            ''' all names now equal 1024! '''
++            return 1024
++
++        self.s.names = resolver
++
++        self.t("a", 1024)
++        self.t("a + b - c - d", 0)
++
++        # the function can do stuff with the value it's sent:
++
++        def my_name(node):
++            ''' all names equal their textual name, twice. '''
++            return node.id + node.id
++
++        self.s.names = my_name
++
++        self.t("a", "aa")
++
++    def test_from_doc(self):
++        ''' the 'name first letter as value' example from the docs '''
++
++        def name_handler(node):
++            ''' return the alphabet number of the first letter of
++                the name's textual name '''
++            return ord(node.id[0].lower())-96
++
++        self.s.names = name_handler
++        self.t('a', 1)
++        self.t('a + b', 3)
++
++class Test_simple_eval(unittest.TestCase):
++    ''' test the 'simple_eval' wrapper function '''
++    def test_basic_run(self):
++        self.assertEqual(simple_eval('6*7'), 42)
++
++    def test_default_functions(self):
++        self.assertEqual(simple_eval('rand() < 1.0 and rand() > -0.01'), True)
++        self.assertEqual(simple_eval('randint(200) < 200 and rand() > 0'), True)
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..a778174
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1 @@
+01-add_testfile.patch
commit 8958e69a7be4053e486fae93250b7d362d55fc87
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Thu Apr 23 19:10:38 2015 +0200

    Adding upstream version 0.8.2.
    
    Signed-off-by: Mathias Behrle <mathiasb at m9s.biz>

diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..9561fb1
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1 @@
+include README.rst
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..a321e93
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,240 @@
+Metadata-Version: 1.1
+Name: simpleeval
+Version: 0.8.2
+Summary: A simple, safe single expression evaluator library.
+Home-page: https://github.com/danthedeckie/simpleeval
+Author: Daniel Fairhead
+Author-email: danthedeckie at gmail.com
+License: UNKNOWN
+Download-URL: https://github.com/danthedeckie/simpleeval/tarball/0.8.2
+Description: simpleeval (Simple Eval)
+        ========================
+        
+        A quick single file library for easily adding evaluatable expressions into python
+        projects.  Say you want to allow a user to set an alarm volume, which could depend
+        on the time of day, alarm level, how many previous alarms had gone off, and if there
+        is music playing at the time.
+        
+        Or if you want to allow simple formulae in a web application, but don't want to
+        give full eval() access, or don't want to run in javascript on the client side.
+        
+        It's deliberately very simple, just a single file you can dump into a project, or import
+        from pypi (pip or easy_install).
+        
+        Internally, it's using the amazing python ``ast`` module to parse the expression, which
+        allows very fine control of what is and isn't allowed.  It should be completely safe in terms
+        of what operations can be performed by the expression.
+        
+        The only issue I know to be aware of is that you can create an expression which
+        takes a long time to evaluate, or which evaluating requires an awful lot of memory,
+        which leaves the potential for DOS attacks.  There is basic protection against this,
+        and you can lock it down further if you desire. (see the `Operators` section below)
+        
+        You should be aware of this when deploying in a public setting.
+        
+        The defaults are pretty locked down and basic, and it's very easy to add whatever
+        extra specific functionality you need (your own functions, variable/name lookup, etc).
+        
+        Basic Usage
+        -----------
+        
+        To get very simple evaluating: ::
+        
+            from simpleeval import simple_eval
+        
+            simple_eval("21 + 21")
+        
+        returns ``42``.
+        
+        Expressions can be as complex and convoluted as you want: ::
+        
+            simple_eval("21 + 19 / 7 + (8 % 3) ** 9")
+        
+        returns ``535.714285714``.
+        
+        You can add your own functions in as well. ::
+        
+            simple_eval("square(11)", functions={"square": lambda x: x*x})
+        
+        returns ``121``.
+        
+        For more details of working with functions, read further down.
+        
+        Note:
+        ~~~~~
+        all further examples use ``>>>`` to designate python code, as if you are using the python interactive
+        prompt.
+        
+        Operators
+        ---------
+        You can add operators yourself, using the ``operators`` argument, but these are the defaults:
+        
+         +----+------------------------------------+
+         | \+ | add two things. ``x + y``          |
+         |    | ``1 + 1`` -> ``2``                 |
+         +----+------------------------------------+
+         | \- | subtract two things ``x - y``      |
+         |    | ``100 - 1`` -> ``99``              |
+         +----+------------------------------------+
+         | \/ | divide one thing by another        |
+         |    | ``x / y``                          |
+         |    | ``100/10`` -> ``10``               |
+         +----+------------------------------------+
+         | \* | multiple one thing by another      |
+         |    | ``x * y``                          |
+         |    | ``10 * 10`` -> ``100``             |
+         +----+------------------------------------+
+         |\*\*| 'to the power of' ``x**y``         |
+         |    | ``2 ** 10`` -> ``1024``            |
+         +----+------------------------------------+
+         | \% | modulus. (remainder)  ``x % y``    |
+         |    | ``15 % 4`` -> ``3``                |
+         +----+------------------------------------+
+         | == | equals  ``x == y``                 |
+         |    | ``15 == 4`` -> ``False``           |
+         +----+------------------------------------+
+         | <  | Less than. ``x < y``               |
+         |    | ``1 < 4`` -> ``True``              |
+         +----+------------------------------------+
+         | >  | Greater than. ``x > y``            |
+         |    | ``1 > 4`` -> ``False``             |
+         +----+------------------------------------+
+         | <= | Less than or Equal to. ``x <= y``  |
+         |    | ``1 < 4`` -> ``True``              |
+         +----+------------------------------------+
+         | >= | Greater or Equal to ``x >= 21``    |
+         |    | ``1 >= 4`` -> ``False``            |
+         +----+------------------------------------+
+        
+        
+        The ``^`` operator is notably missing - not because it's hard, but because it is often mistaken for
+        a exponent operator, not the bitwise operation that it is in python.  It's trivial to add back in again
+        if you wish (using the class based evaluator explained below): ::
+        
+            >>> import ast
+            >>> import operator
+        
+            >>> s = SimpleEval()
+            >>> s.operators[ast.BitXor] = operator.xor
+        
+            >>> s.eval("2 ^ 10")
+            8
+        
+        Limited Power
+        ~~~~~~~~~~~~~
+        
+        Also note, the ``**`` operator has been locked down by default to have a maximum input value
+        of ``4000000``, which makes it somewhat harder to make expressions which go on for ever.  You
+        can change this limit by changing the ``simpleeval.POWER_MAX`` module level value to whatever
+        is an appropriate value for you (and the hardware that you're running on) or if you want to
+        completely remove all limitations, you can set the ``s.operators[ast.Pow] = operator.pow`` or make
+        your own function.
+        
+        On my computer, ``9**9**5`` evaluates almost instantly, but ``9**9**6`` takes over 30 seconds.
+        Since ``9**7`` is ``4782969``, and so over the ``POWER_MAX`` limit, it throws a
+        ``NumberTooHigh`` exception for you. (Otherwise it would go on for hours, or until the computer
+        runs out of memory)
+        
+        String Safety
+        ~~~~~~~~~~~~~
+        
+        There are also limits on string length (100000 characters, ``MAX_STRING_LENGTH``).
+        This can be changed if you wish.
+        
+        If Expressions
+        --------------
+        
+        You can use python style ``if x then y else z`` type expressions: ::
+        
+            >>> simple_eval("'equal' if x == y else 'not equal'",
+                            names={"x": 1, "y": 2})
+            'not equal'
+        
+        which, of course, can be nested: ::
+        
+            >>> simple_eval("'a' if 1 == 2 else 'b' if 2 == 3 else 'c'")
+            'c'
+            
+        
+        Functions
+        ---------
+        
+        You can define functions which you'd like the expresssions to have access to: ::
+        
+            >>> simple_eval("double(21)", functions={"double": lambda x:x*2})
+            42
+        
+        You can define "real" functions to pass in rather than lambdas, of course too, and even re-name them so that expressions can be shorter ::
+        
+            >>> def double(x):
+                    return x * 2
+            >>> simple_eval("d(100) + double(1)", functions={"d": double, "double":double})
+            202
+        
+        Names
+        -----
+         
+        Sometimes it's useful to have variables available, which in python terminology are called 'names'. ::
+        
+            >>> simple_eval("a + b", names={"a": 11, "b": 100})
+            111
+        
+        You can also hand the handling of names over to a function, if you prefer: ::
+        
+            >>> def name_handler(node):
+                    return ord(node.id[0].lower(a))-96
+        
+            >>> simple_eval('a + b', names=name_handler)
+            3
+        
+        That was a bit of a silly example, but you could use this for pulling values from a database or file, say, or doing some kind of caching system.
+        
+        Creating an Evaluator Class
+        ---------------------------
+        
+        Rather than creating a new evaluator each time, if you are doing a lot of evaluations,
+        you can create a SimpleEval object, and pass it expressions each time (which should be a bit quicker, and certainly more convienient for some use cases): ::
+        
+            s = SimpleEval()
+            s.eval("1 + 1")
+            # and so on...
+        
+        You can assign / edit the various options of the ``SimpleEval`` object if you want to.
+        Either assign them during creation (like the ``simple_eval`` function) ::
+        
+            s = SimpleEval(functions={"boo": boo})
+        
+        or edit them after creation: ::
+        
+            s.names['fortytwo'] = 42
+        
+        this actually means you can modify names (or functions) with functions, if you really feel so inclined: ::
+        
+            s = SimpleEval()
+            def set_val(name, value):
+                s.names[name.value] = value.value
+                return value.value
+        
+            s.functions = {'set': set_val}
+        
+            s.eval("set('age', 111)")
+        
+        Say.  This would allow a certain level of 'scriptyness' if you had these evaluations happening as callbacks in a program.  Although you really are reaching the end of what this library is intended for at this stage.
+        
+        Other...
+        --------
+        
+        This is written using python 2.7, but should be trivial to convert to python3 with the 2to3 converter.  It totals around 100 lines of code, so it isn't a complex beast.
+        
+        Please read the ``test_simpleeval.py`` file for other potential gotchas or details.  I'm very happy to accept pull requests, suggestions, or other issues.  Enjoy!
+        
+        .. image:: https://coveralls.io/repos/danthedeckie/simpleeval/badge.png :target: https://coveralls.io/r/danthedeckie/simpleeval 
+        
+Keywords: eval,simple,expression,parse,ast
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..035b0f7
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,222 @@
+simpleeval (Simple Eval)
+========================
+
+A quick single file library for easily adding evaluatable expressions into python
+projects.  Say you want to allow a user to set an alarm volume, which could depend
+on the time of day, alarm level, how many previous alarms had gone off, and if there
+is music playing at the time.
+
+Or if you want to allow simple formulae in a web application, but don't want to
+give full eval() access, or don't want to run in javascript on the client side.
+
+It's deliberately very simple, just a single file you can dump into a project, or import
+from pypi (pip or easy_install).
+
+Internally, it's using the amazing python ``ast`` module to parse the expression, which
+allows very fine control of what is and isn't allowed.  It should be completely safe in terms
+of what operations can be performed by the expression.
+
+The only issue I know to be aware of is that you can create an expression which
+takes a long time to evaluate, or which evaluating requires an awful lot of memory,
+which leaves the potential for DOS attacks.  There is basic protection against this,
+and you can lock it down further if you desire. (see the `Operators` section below)
+
+You should be aware of this when deploying in a public setting.
+
+The defaults are pretty locked down and basic, and it's very easy to add whatever
+extra specific functionality you need (your own functions, variable/name lookup, etc).
+
+Basic Usage
+-----------
+
+To get very simple evaluating: ::
+
+    from simpleeval import simple_eval
+
+    simple_eval("21 + 21")
+
+returns ``42``.
+
+Expressions can be as complex and convoluted as you want: ::
+
+    simple_eval("21 + 19 / 7 + (8 % 3) ** 9")
+
+returns ``535.714285714``.
+
+You can add your own functions in as well. ::
+
+    simple_eval("square(11)", functions={"square": lambda x: x*x})
+
+returns ``121``.
+
+For more details of working with functions, read further down.
+
+Note:
+~~~~~
+all further examples use ``>>>`` to designate python code, as if you are using the python interactive
+prompt.
+
+Operators
+---------
+You can add operators yourself, using the ``operators`` argument, but these are the defaults:
+
+ +----+------------------------------------+
+ | \+ | add two things. ``x + y``          |
+ |    | ``1 + 1`` -> ``2``                 |
+ +----+------------------------------------+
+ | \- | subtract two things ``x - y``      |
+ |    | ``100 - 1`` -> ``99``              |
+ +----+------------------------------------+
+ | \/ | divide one thing by another        |
+ |    | ``x / y``                          |
+ |    | ``100/10`` -> ``10``               |
+ +----+------------------------------------+
+ | \* | multiple one thing by another      |
+ |    | ``x * y``                          |
+ |    | ``10 * 10`` -> ``100``             |
+ +----+------------------------------------+
+ |\*\*| 'to the power of' ``x**y``         |
+ |    | ``2 ** 10`` -> ``1024``            |
+ +----+------------------------------------+
+ | \% | modulus. (remainder)  ``x % y``    |
+ |    | ``15 % 4`` -> ``3``                |
+ +----+------------------------------------+
+ | == | equals  ``x == y``                 |
+ |    | ``15 == 4`` -> ``False``           |
+ +----+------------------------------------+
+ | <  | Less than. ``x < y``               |
+ |    | ``1 < 4`` -> ``True``              |
+ +----+------------------------------------+
+ | >  | Greater than. ``x > y``            |
+ |    | ``1 > 4`` -> ``False``             |
+ +----+------------------------------------+
+ | <= | Less than or Equal to. ``x <= y``  |
+ |    | ``1 < 4`` -> ``True``              |
+ +----+------------------------------------+
+ | >= | Greater or Equal to ``x >= 21``    |
+ |    | ``1 >= 4`` -> ``False``            |
+ +----+------------------------------------+
+
+
+The ``^`` operator is notably missing - not because it's hard, but because it is often mistaken for
+a exponent operator, not the bitwise operation that it is in python.  It's trivial to add back in again
+if you wish (using the class based evaluator explained below): ::
+
+    >>> import ast
+    >>> import operator
+
+    >>> s = SimpleEval()
+    >>> s.operators[ast.BitXor] = operator.xor
+
+    >>> s.eval("2 ^ 10")
+    8
+
+Limited Power
+~~~~~~~~~~~~~
+
+Also note, the ``**`` operator has been locked down by default to have a maximum input value
+of ``4000000``, which makes it somewhat harder to make expressions which go on for ever.  You
+can change this limit by changing the ``simpleeval.POWER_MAX`` module level value to whatever
+is an appropriate value for you (and the hardware that you're running on) or if you want to
+completely remove all limitations, you can set the ``s.operators[ast.Pow] = operator.pow`` or make
+your own function.
+
+On my computer, ``9**9**5`` evaluates almost instantly, but ``9**9**6`` takes over 30 seconds.
+Since ``9**7`` is ``4782969``, and so over the ``POWER_MAX`` limit, it throws a
+``NumberTooHigh`` exception for you. (Otherwise it would go on for hours, or until the computer
+runs out of memory)
+
+String Safety
+~~~~~~~~~~~~~
+
+There are also limits on string length (100000 characters, ``MAX_STRING_LENGTH``).
+This can be changed if you wish.
+
+If Expressions
+--------------
+
+You can use python style ``if x then y else z`` type expressions: ::
+
+    >>> simple_eval("'equal' if x == y else 'not equal'",
+                    names={"x": 1, "y": 2})
+    'not equal'
+
+which, of course, can be nested: ::
+
+    >>> simple_eval("'a' if 1 == 2 else 'b' if 2 == 3 else 'c'")
+    'c'
+    
+
+Functions
+---------
+
+You can define functions which you'd like the expresssions to have access to: ::
+
+    >>> simple_eval("double(21)", functions={"double": lambda x:x*2})
+    42
+
+You can define "real" functions to pass in rather than lambdas, of course too, and even re-name them so that expressions can be shorter ::
+
+    >>> def double(x):
+            return x * 2
+    >>> simple_eval("d(100) + double(1)", functions={"d": double, "double":double})
+    202
+
+Names
+-----
+ 
+Sometimes it's useful to have variables available, which in python terminology are called 'names'. ::
+
+    >>> simple_eval("a + b", names={"a": 11, "b": 100})
+    111
+
+You can also hand the handling of names over to a function, if you prefer: ::
+
+    >>> def name_handler(node):
+            return ord(node.id[0].lower(a))-96
+
+    >>> simple_eval('a + b', names=name_handler)
+    3
+
+That was a bit of a silly example, but you could use this for pulling values from a database or file, say, or doing some kind of caching system.
+
+Creating an Evaluator Class
+---------------------------
+
+Rather than creating a new evaluator each time, if you are doing a lot of evaluations,
+you can create a SimpleEval object, and pass it expressions each time (which should be a bit quicker, and certainly more convienient for some use cases): ::
+
+    s = SimpleEval()
+    s.eval("1 + 1")
+    # and so on...
+
+You can assign / edit the various options of the ``SimpleEval`` object if you want to.
+Either assign them during creation (like the ``simple_eval`` function) ::
+
+    s = SimpleEval(functions={"boo": boo})
+
+or edit them after creation: ::
+
+    s.names['fortytwo'] = 42
+
+this actually means you can modify names (or functions) with functions, if you really feel so inclined: ::
+
+    s = SimpleEval()
+    def set_val(name, value):
+        s.names[name.value] = value.value
+        return value.value
+
+    s.functions = {'set': set_val}
+
+    s.eval("set('age', 111)")
+
+Say.  This would allow a certain level of 'scriptyness' if you had these evaluations happening as callbacks in a program.  Although you really are reaching the end of what this library is intended for at this stage.
+
+Other...
+--------
+
+This is written using python 2.7, but should be trivial to convert to python3 with the 2to3 converter.  It totals around 100 lines of code, so it isn't a complex beast.
+
+Please read the ``test_simpleeval.py`` file for other potential gotchas or details.  I'm very happy to accept pull requests, suggestions, or other issues.  Enjoy!
+
+.. image:: https://coveralls.io/repos/danthedeckie/simpleeval/badge.png :target: https://coveralls.io/r/danthedeckie/simpleeval 
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..e38d9f0
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+simpleeval (0.8.2-1) unstable; urgency=low
+
+  * Initial packaging (Closes: #783188).
+
+ -- Mathias Behrle <mathiasb at m9s.biz>  Thu, 23 Apr 2015 19:25:39 +0200
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..0f20a62
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,45 @@
+Source: simpleeval
+Section: python
+Priority: optional
+Maintainer: Debian Tryton Maintainers <maintainers at debian.tryton.org>
+Uploaders: Mathias Behrle <mathiasb at m9s.biz>
+Build-Depends:
+ debhelper (>= 9),
+ dh-python (>= 1.20130901-1~),
+ python (>= 2.6.6-3~),
+ python-setuptools,
+ python3,
+ python3-setuptools,
+Standards-Version: 3.9.6
+Homepage: https://github.com/danthedeckie/simpleeval
+Vcs-Browser: http://anonscm.debian.org/gitweb/?p=tryton/simpleeval.git
+Vcs-Git: git://anonscm.debian.org/tryton/simpleeval.git
+X-Python-Version: >= 2.6
+
+Package: python-simpleeval
+Architecture: all
+Depends: python-pkg-resources, ${misc:Depends}, ${python:Depends}
+Description: Simple, safe single expression evaluator library (Python 2)
+ Quick single file library for easily adding evaluatable expressions into
+ Python projects.
+ .
+ Short, easy to use, safe and reasonably extensible expression evaluator.
+ Designed for things like in a website where you want to allow the user to
+ generate a string, or a number from some other input, without allowing full
+ eval() or other unsafe or needlessly complex linguistics.
+ .
+ This package is targeting Python version 2.
+
+Package: python3-simpleeval
+Architecture: all
+Depends: python3-pkg-resources, ${misc:Depends}, ${python3:Depends}
+Description: Simple, safe single expression evaluator library (Python 3)
+ Quick single file library for easily adding evaluatable expressions into
+ Python projects.
+ .
+ Short, easy to use, safe and reasonably extensible expression evaluator.
+ Designed for things like in a website where you want to allow the user to
+ generate a string, or a number from some other input, without allowing full
+ eval() or other unsafe or needlessly complex linguistics.
+ .
+ This package is targeting Python version 3.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..7928ea2
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,28 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+
+Files: *
+Copyright: 2013-2014 Daniel Fairhead
+License: MIT
+
+Files: debian/*
+Copyright: 2015 Mathias Behrle <mathiasb at m9s.biz>
+License: MIT
+
+License: MIT
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ .
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
diff --git a/debian/gbp.conf b/debian/gbp.conf
new file mode 100644
index 0000000..b6106b4
--- /dev/null
+++ b/debian/gbp.conf
@@ -0,0 +1,12 @@
+# Settings for Debian Tryton Maintainer repositories
+# for usage with git-buildpackage
+
+[DEFAULT]
+debian-branch = debian
+pristine-tar = True
+
+[git-buildpackage]
+ignore-new = True
+# Use export-dir at your discretion to avoid git-buildpackage messing
+# your git repeository
+#export-dir = ../build-area/
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..a0d8f2c
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,11 @@
+#!/usr/bin/make -f
+
+export PYBUILD_NAME := simpleeval
+
+%:
+	dh ${@} --with python2,python3 --buildsystem=pybuild
+
+override_dh_auto_clean:
+	rm -rf $(PACKAGE_NAME).egg-info
+	rm -rf PKG-INFO
+	dh_auto_clean
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..256c226
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,3 @@
+version=3
+opts=uversionmangle=s/(rc|a|b|c)/~$1/ \
+http://pypi.debian.net/simpleeval/simpleeval-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..861a9f5
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,5 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+tag_svn_revision = 0
+
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..f319b8b
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,24 @@
+from setuptools import setup
+__version__ = '0.8.2'
+
+setup(
+    name = 'simpleeval',
+    py_modules = ['simpleeval'],
+    version = __version__,
+    description = 'A simple, safe single expression evaluator library.',
+    long_description=open('README.rst','r').read(),
+    author = 'Daniel Fairhead',
+    author_email = 'danthedeckie at gmail.com',
+    url = 'https://github.com/danthedeckie/simpleeval',
+    download_url = 'https://github.com/danthedeckie/simpleeval/tarball/' + __version__,
+    keywords = ['eval', 'simple', 'expression', 'parse', 'ast'],
+    test_suite = 'test_simpleeval',
+    use_2to3 = True,
+    classifiers = ['Development Status :: 4 - Beta',
+                   'Intended Audience :: Developers',
+                   'License :: OSI Approved :: MIT License',
+                   'Topic :: Software Development :: Libraries :: Python Modules',
+                   'Programming Language :: Python :: 2',
+                   'Programming Language :: Python :: 3',
+                  ],
+    )
diff --git a/simpleeval.egg-info/PKG-INFO b/simpleeval.egg-info/PKG-INFO
new file mode 100644
index 0000000..a321e93
--- /dev/null
+++ b/simpleeval.egg-info/PKG-INFO
@@ -0,0 +1,240 @@
+Metadata-Version: 1.1
+Name: simpleeval
+Version: 0.8.2
+Summary: A simple, safe single expression evaluator library.
+Home-page: https://github.com/danthedeckie/simpleeval
+Author: Daniel Fairhead
+Author-email: danthedeckie at gmail.com
+License: UNKNOWN
+Download-URL: https://github.com/danthedeckie/simpleeval/tarball/0.8.2
+Description: simpleeval (Simple Eval)
+        ========================
+        
+        A quick single file library for easily adding evaluatable expressions into python
+        projects.  Say you want to allow a user to set an alarm volume, which could depend
+        on the time of day, alarm level, how many previous alarms had gone off, and if there
+        is music playing at the time.
+        
+        Or if you want to allow simple formulae in a web application, but don't want to
+        give full eval() access, or don't want to run in javascript on the client side.
+        
+        It's deliberately very simple, just a single file you can dump into a project, or import
+        from pypi (pip or easy_install).
+        
+        Internally, it's using the amazing python ``ast`` module to parse the expression, which
+        allows very fine control of what is and isn't allowed.  It should be completely safe in terms
+        of what operations can be performed by the expression.
+        
+        The only issue I know to be aware of is that you can create an expression which
+        takes a long time to evaluate, or which evaluating requires an awful lot of memory,
+        which leaves the potential for DOS attacks.  There is basic protection against this,
+        and you can lock it down further if you desire. (see the `Operators` section below)
+        
+        You should be aware of this when deploying in a public setting.
+        
+        The defaults are pretty locked down and basic, and it's very easy to add whatever
+        extra specific functionality you need (your own functions, variable/name lookup, etc).
+        
+        Basic Usage
+        -----------
+        
+        To get very simple evaluating: ::
+        
+            from simpleeval import simple_eval
+        
+            simple_eval("21 + 21")
+        
+        returns ``42``.
+        
+        Expressions can be as complex and convoluted as you want: ::
+        
+            simple_eval("21 + 19 / 7 + (8 % 3) ** 9")
+        
+        returns ``535.714285714``.
+        
+        You can add your own functions in as well. ::
+        
+            simple_eval("square(11)", functions={"square": lambda x: x*x})
+        
+        returns ``121``.
+        
+        For more details of working with functions, read further down.
+        
+        Note:
+        ~~~~~
+        all further examples use ``>>>`` to designate python code, as if you are using the python interactive
+        prompt.
+        
+        Operators
+        ---------
+        You can add operators yourself, using the ``operators`` argument, but these are the defaults:
+        
+         +----+------------------------------------+
+         | \+ | add two things. ``x + y``          |
+         |    | ``1 + 1`` -> ``2``                 |
+         +----+------------------------------------+
+         | \- | subtract two things ``x - y``      |
+         |    | ``100 - 1`` -> ``99``              |
+         +----+------------------------------------+
+         | \/ | divide one thing by another        |
+         |    | ``x / y``                          |
+         |    | ``100/10`` -> ``10``               |
+         +----+------------------------------------+
+         | \* | multiple one thing by another      |
+         |    | ``x * y``                          |
+         |    | ``10 * 10`` -> ``100``             |
+         +----+------------------------------------+
+         |\*\*| 'to the power of' ``x**y``         |
+         |    | ``2 ** 10`` -> ``1024``            |
+         +----+------------------------------------+
+         | \% | modulus. (remainder)  ``x % y``    |
+         |    | ``15 % 4`` -> ``3``                |
+         +----+------------------------------------+
+         | == | equals  ``x == y``                 |
+         |    | ``15 == 4`` -> ``False``           |
+         +----+------------------------------------+
+         | <  | Less than. ``x < y``               |
+         |    | ``1 < 4`` -> ``True``              |
+         +----+------------------------------------+
+         | >  | Greater than. ``x > y``            |
+         |    | ``1 > 4`` -> ``False``             |
+         +----+------------------------------------+
+         | <= | Less than or Equal to. ``x <= y``  |
+         |    | ``1 < 4`` -> ``True``              |
+         +----+------------------------------------+
+         | >= | Greater or Equal to ``x >= 21``    |
+         |    | ``1 >= 4`` -> ``False``            |
+         +----+------------------------------------+
+        
+        
+        The ``^`` operator is notably missing - not because it's hard, but because it is often mistaken for
+        a exponent operator, not the bitwise operation that it is in python.  It's trivial to add back in again
+        if you wish (using the class based evaluator explained below): ::
+        
+            >>> import ast
+            >>> import operator
+        
+            >>> s = SimpleEval()
+            >>> s.operators[ast.BitXor] = operator.xor
+        
+            >>> s.eval("2 ^ 10")
+            8
+        
+        Limited Power
+        ~~~~~~~~~~~~~
+        
+        Also note, the ``**`` operator has been locked down by default to have a maximum input value
+        of ``4000000``, which makes it somewhat harder to make expressions which go on for ever.  You
+        can change this limit by changing the ``simpleeval.POWER_MAX`` module level value to whatever
+        is an appropriate value for you (and the hardware that you're running on) or if you want to
+        completely remove all limitations, you can set the ``s.operators[ast.Pow] = operator.pow`` or make
+        your own function.
+        
+        On my computer, ``9**9**5`` evaluates almost instantly, but ``9**9**6`` takes over 30 seconds.
+        Since ``9**7`` is ``4782969``, and so over the ``POWER_MAX`` limit, it throws a
+        ``NumberTooHigh`` exception for you. (Otherwise it would go on for hours, or until the computer
+        runs out of memory)
+        
+        String Safety
+        ~~~~~~~~~~~~~
+        
+        There are also limits on string length (100000 characters, ``MAX_STRING_LENGTH``).
+        This can be changed if you wish.
+        
+        If Expressions
+        --------------
+        
+        You can use python style ``if x then y else z`` type expressions: ::
+        
+            >>> simple_eval("'equal' if x == y else 'not equal'",
+                            names={"x": 1, "y": 2})
+            'not equal'
+        
+        which, of course, can be nested: ::
+        
+            >>> simple_eval("'a' if 1 == 2 else 'b' if 2 == 3 else 'c'")
+            'c'
+            
+        
+        Functions
+        ---------
+        
+        You can define functions which you'd like the expresssions to have access to: ::
+        
+            >>> simple_eval("double(21)", functions={"double": lambda x:x*2})
+            42
+        
+        You can define "real" functions to pass in rather than lambdas, of course too, and even re-name them so that expressions can be shorter ::
+        
+            >>> def double(x):
+                    return x * 2
+            >>> simple_eval("d(100) + double(1)", functions={"d": double, "double":double})
+            202
+        
+        Names
+        -----
+         
+        Sometimes it's useful to have variables available, which in python terminology are called 'names'. ::
+        
+            >>> simple_eval("a + b", names={"a": 11, "b": 100})
+            111
+        
+        You can also hand the handling of names over to a function, if you prefer: ::
+        
+            >>> def name_handler(node):
+                    return ord(node.id[0].lower(a))-96
+        
+            >>> simple_eval('a + b', names=name_handler)
+            3
+        
+        That was a bit of a silly example, but you could use this for pulling values from a database or file, say, or doing some kind of caching system.
+        
+        Creating an Evaluator Class
+        ---------------------------
+        
+        Rather than creating a new evaluator each time, if you are doing a lot of evaluations,
+        you can create a SimpleEval object, and pass it expressions each time (which should be a bit quicker, and certainly more convienient for some use cases): ::
+        
+            s = SimpleEval()
+            s.eval("1 + 1")
+            # and so on...
+        
+        You can assign / edit the various options of the ``SimpleEval`` object if you want to.
+        Either assign them during creation (like the ``simple_eval`` function) ::
+        
+            s = SimpleEval(functions={"boo": boo})
+        
+        or edit them after creation: ::
+        
+            s.names['fortytwo'] = 42
+        
+        this actually means you can modify names (or functions) with functions, if you really feel so inclined: ::
+        
+            s = SimpleEval()
+            def set_val(name, value):
+                s.names[name.value] = value.value
+                return value.value
+        
+            s.functions = {'set': set_val}
+        
+            s.eval("set('age', 111)")
+        
+        Say.  This would allow a certain level of 'scriptyness' if you had these evaluations happening as callbacks in a program.  Although you really are reaching the end of what this library is intended for at this stage.
+        
+        Other...
+        --------
+        
+        This is written using python 2.7, but should be trivial to convert to python3 with the 2to3 converter.  It totals around 100 lines of code, so it isn't a complex beast.
+        
+        Please read the ``test_simpleeval.py`` file for other potential gotchas or details.  I'm very happy to accept pull requests, suggestions, or other issues.  Enjoy!
+        
+        .. image:: https://coveralls.io/repos/danthedeckie/simpleeval/badge.png :target: https://coveralls.io/r/danthedeckie/simpleeval 
+        
+Keywords: eval,simple,expression,parse,ast
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Topic :: Software Development :: Libraries :: Python Modules
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 3
diff --git a/simpleeval.egg-info/SOURCES.txt b/simpleeval.egg-info/SOURCES.txt
new file mode 100644
index 0000000..0547ed6
--- /dev/null
+++ b/simpleeval.egg-info/SOURCES.txt
@@ -0,0 +1,8 @@
+MANIFEST.in
+README.rst
+setup.py
+simpleeval.py
+simpleeval.egg-info/PKG-INFO
+simpleeval.egg-info/SOURCES.txt
+simpleeval.egg-info/dependency_links.txt
+simpleeval.egg-info/top_level.txt
\ No newline at end of file
diff --git a/simpleeval.egg-info/dependency_links.txt b/simpleeval.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/simpleeval.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/simpleeval.egg-info/top_level.txt b/simpleeval.egg-info/top_level.txt
new file mode 100644
index 0000000..49a7c04
--- /dev/null
+++ b/simpleeval.egg-info/top_level.txt
@@ -0,0 +1 @@
+simpleeval
diff --git a/simpleeval.py b/simpleeval.py
new file mode 100644
index 0000000..67af226
--- /dev/null
+++ b/simpleeval.py
@@ -0,0 +1,282 @@
+'''
+SimpleEval - (C) 2013/2014 Daniel Fairhead
+-------------------------------------
+
+An short, easy to use, safe and reasonably extensible expression evaluator.
+Designed for things like in a website where you want to allow the user to
+generate a string, or a number from some other input, without allowing full
+eval() or other unsafe or needlessly complex linguistics.
+
+-------------------------------------
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+-------------------------------------
+
+Initial idea copied from J.F. Sebastian on Stack Overflow
+( http://stackoverflow.com/a/9558001/1973500 ) with
+modifications and many improvments.
+
+-------------------------------------
+Usage:
+
+>>> s = SimpleEval()
+>>> s.eval("20 + 30")
+50
+
+You can add your own functions easily too:
+
+if file.txt contents is "11"
+
+>>> def get_file():
+        with open("file.txt",'r') as f:
+            return f.read()
+
+    s.functions["get_file"] = get_file
+    s.eval("int(get_file()) + 31")
+42
+
+For more information, see the full package documentation on pypi, or the github
+repo.
+
+-----------
+
+If you don't need to re-use the evaluator (with it's names, functions, etc),
+then you can use the simple_eval() function:
+
+>>> simple_eval("21 + 19")
+40
+
+You can pass names, operators and functions to the simple_eval function as
+well:
+
+>>> simple_eval("40 + two", names={"two": 2})
+42
+
+'''
+
+import ast
+import operator as op
+from random import random
+
+########################################
+# Module wide 'globals'
+
+MAX_STRING_LENGTH = 100000
+MAX_POWER = 4000000 # highest exponent
+
+########################################
+# Exceptions:
+
+class InvalidExpression(Exception):
+    ''' Generic Exception '''
+    pass
+
+class FunctionNotDefined(InvalidExpression):
+    ''' sorry! That function isn't defined! '''
+    def __init__(self, func_name, expression):
+        self.message = "Function '{0}' not defined," \
+                       " for expression '{1}'.".format( func_name, expression)
+        self.func_name = func_name
+        self.expression = expression
+
+        # pylint: disable=bad-super-call
+        super(InvalidExpression, self).__init__(self.message)
+
+class NameNotDefined(InvalidExpression):
+    ''' a name isn't defined. '''
+    def __init__(self, name, expression):
+        self.message = "'{0}' is not defined for expression '{1}'".format(
+                            name, expression)
+        self.name = name
+        self.expression = expression
+
+        # pylint: disable=bad-super-call
+        super(InvalidExpression, self).__init__(self.message)
+
+class FeatureNotAvailable(InvalidExpression):
+    ''' What you're trying to do is not allowed. '''
+    pass
+
+class NumberTooHigh(InvalidExpression):
+    ''' Sorry! That number is too high. I don't want to spend the
+        next 10 years evaluating this expression! '''
+    pass
+
+class StringTooLong(InvalidExpression):
+    ''' That string is **way** too long, baby. '''
+    pass
+
+########################################
+# Default simple functions to include:
+
+def random_int(top):
+    ''' return a random int below <top> '''
+    return int(random() * top)
+
+def safe_power(a, b): # pylint: disable=invalid-name
+    ''' a limited exponent/to-the-power-of function, for safety reasons '''
+    if abs(a) > MAX_POWER or abs(b) > MAX_POWER:
+        raise NumberTooHigh("Sorry! I don't want to evaluate {0} ** {1}"
+                            .format(a, b))
+    return a ** b
+
+def safe_mult(a, b): # pylint: disable=invalid-name
+    ''' limit the number of times a string can be repeated... '''
+    if isinstance(a, str) or isinstance(b, str):
+        if isinstance(a, int) and a*len(b) > MAX_STRING_LENGTH:
+            raise StringTooLong("Sorry, a string that long is not allowed")
+        elif isinstance(b, int) and b*len(a) > MAX_STRING_LENGTH:
+            raise StringTooLong("Sorry, a string that long is not allowed")
+
+    return a * b
+
+def safe_add(a, b): # pylint: disable=invalid-name
+    ''' string length limit again '''
+    if isinstance(a, str) and isinstance(b, str):
+        if len(a) + len(b) > MAX_STRING_LENGTH:
+            raise StringTooLong("Sorry, adding those two strings would"
+                                " make a too long string.")
+    return a + b
+
+
+########################################
+# Defaults for the evaluator:
+
+DEFAULT_OPERATORS = {ast.Add: safe_add, ast.Sub: op.sub, ast.Mult: safe_mult,
+                     ast.Div: op.truediv, ast.Pow: safe_power, ast.Mod: op.mod,
+                     ast.Eq: op.eq, ast.Gt: op.gt, ast.Lt: op.lt,
+                     ast.GtE: op.ge, ast.LtE: op.le, ast.USub: op.neg,
+                     ast.UAdd: op.pos}
+
+DEFAULT_FUNCTIONS = {"rand": random, "randint": random_int,
+                     "int": int, "float": float, "str": unicode}
+
+DEFAULT_NAMES = {"True": True, "False": False}
+
+########################################
+# And the actual evaluator:
+
+class SimpleEval(object): # pylint: disable=too-few-public-methods
+    ''' A very simple expression parser.
+        >>> s = SimpleEval()
+        >>> s.eval("20 + 30 - ( 10 * 5)")
+        0
+        '''
+    expr = ""
+
+    def __init__(self, operators=None, functions=None, names=None):
+        '''
+            Create the evaluator instance.  Set up valid operators (+,-, etc)
+            functions (add, random, get_val, whatever) and names. '''
+
+        if not operators:
+            operators = DEFAULT_OPERATORS
+        if not functions:
+            functions = DEFAULT_FUNCTIONS
+        if not names:
+            names = DEFAULT_NAMES
+
+        self.operators = operators
+        self.functions = functions
+        self.names = names
+
+    def eval(self, expr):
+        ''' evaluate an expresssion, using the operators, functions and
+            names previously set up. '''
+
+        # set a copy of the expression aside, so we can give nice errors...
+
+        self.expr = expr
+
+        # and evaluate:
+        return self._eval(ast.parse(expr).body[0].value)
+
+    # pylint: disable=too-many-return-statements, too-many-branches
+    def _eval(self, node):
+        ''' The internal eval function used on each node in the parsed tree. '''
+
+        # literals:
+
+        if isinstance(node, ast.Num): # <number>
+            return node.n
+        elif isinstance(node, ast.Str): # <string>
+            if len(node.s) > MAX_STRING_LENGTH:
+                raise StringTooLong("{0} is too long!"
+                                    " ({1}, when {2} is max)".format(
+                                    node.id, len(node.s), MAX_STRING_LENGTH))
+            return node.s
+
+        # python 3 compatibility:
+
+        elif (hasattr(ast, 'NameConstant') and
+                isinstance(node, ast.NameConstant)): # <bool>
+            return node.value
+
+        # operators, functions, etc:
+
+        elif isinstance(node, ast.UnaryOp): # - and + etc.
+            return self.operators[type(node.op)](self._eval(node.operand))
+        elif isinstance(node, ast.BinOp): # <left> <operator> <right>
+            return self.operators[type(node.op)](self._eval(node.left),
+                                       self._eval(node.right))
+        elif isinstance(node, ast.BoolOp): # and & or...
+            if isinstance(node.op, ast.And):
+                return all((self._eval(v) for v in node.values))
+            elif isinstance(node.op, ast.Or):
+                return any((self._eval(v) for v in node.values))
+        elif isinstance(node, ast.Compare): # 1 < 2, a == b...
+            return self.operators[type(node.ops[0])](self._eval(node.left),
+                                                     self._eval(node.comparators[0]))
+        elif isinstance(node, ast.IfExp): # x if y else z
+            return self._eval(node.body) if self._eval(node.test) \
+                                         else self._eval(node.orelse)
+        elif isinstance(node, ast.Call): # function...
+            try:
+                return self.functions[node.func.id](*(self._eval(a)
+                                                      for a in node.args))
+            except KeyError:
+                raise FunctionNotDefined(node.func.id, self.expr)
+
+        # variables/names:
+
+        elif isinstance(node, ast.Name): # a, b, c...
+            try:
+                if isinstance(self.names, dict):
+                    return self.names[node.id]
+                elif callable(self.names):
+                    return self.names(node)
+                else:
+                    raise KeyError('undefined name')
+            except KeyError:
+                raise NameNotDefined(node.id, self.expr)
+
+        elif isinstance(node, ast.Subscript): # b[1]
+            return self._eval(node.value)[self._eval(node.slice.value)]
+
+        else:
+            raise FeatureNotAvailable("Sorry, {0} is not available in this "
+                                      "evaluator".format(type(node).__name__ ))
+
+def simple_eval(expr, operators=None, functions=None, names=None):
+    ''' Simply evaluate an expresssion '''
+    s = SimpleEval(operators=operators,
+                   functions=functions,
+                   names=names)
+    return s.eval(expr)
-- 
simpleeval



More information about the tryton-debian-vcs mailing list