[tryton-debian-vcs] simpleeval branch upstream created. 5e7592badb01ccfd119b463a9f91e95c2938529b

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 upstream branch:
https://alioth.debian.org/plugins/scmgit/cgi-bin/gitweb.cgi/?p=tryton/simpleeval.git;a=commitdiff;h=5e7592badb01ccfd119b463a9f91e95c2938529b
commit 5e7592badb01ccfd119b463a9f91e95c2938529b
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/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