[tryton-debian-vcs] simpleeval branch debian updated. debian/0.9.3-1-6-g3bf8981
Mathias Behrle
tryton-debian-vcs at alioth.debian.org
Wed Sep 6 09:58:13 UTC 2017
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=debian/0.9.3-1-6-g3bf8981
commit 3bf8981c71862e4e3b7f39ab1246cac26079e9c2
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Wed Sep 6 11:27:58 2017 +0200
Releasing debian version 0.9.5-1.
Signed-off-by: Mathias Behrle <mathiasb at m9s.biz>
diff --git a/debian/changelog b/debian/changelog
index ccd99f1..5ebe96a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,14 @@
+simpleeval (0.9.5-1) unstable; urgency=medium
+
+ * Change the maintainer address to tryton-debian at lists.alioth.debian.org
+ (Closes: #865109).
+ * Use the preferred https URL format in the copyright file.
+ * Bump the Standards-Version to 4.0.1.
+ * Bump the Standards-Version to 4.1.0, no changes needed.
+ * Merging upstream version 0.9.5.
+
+ -- Mathias Behrle <mathiasb at m9s.biz> Mon, 04 Sep 2017 16:23:10 +0200
+
simpleeval (0.9.3-1) unstable; urgency=medium
* Merging upstream version 0.9.3.
commit 28afdac4af8a7690a855b28a3e78678fc7f40186
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Mon Sep 4 16:23:09 2017 +0200
Merging upstream version 0.9.5.
diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000..3aad258
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+branch = True
+omit = /home/travis/virtualenv/*
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ef70fef
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+*.pyc
+build
+dist
+MANIFEST
+.idea
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2ce315b
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,20 @@
+language: python
+python:
+ - "2.7"
+ - "3.2"
+ - "3.3"
+ - "3.4"
+ - "3.5"
+ - "3.6"
+install:
+ - pip install nose
+ - pip install coveralls
+ # coverage no longer supports python 3.2...
+ # - pip install coverage
+ - if [ "$TRAVIS_PYTHON_VERSION" == "3.2" ]; then travis_retry pip install coverage==3.7.1; fi
+ - if [ "$TRAVIS_PYTHON_VERSION" != "3.2" ]; then travis_retry pip install coverage; fi
+script:
+ - nosetests
+ - coverage run -m nose
+after_success:
+ - coveralls
diff --git a/LICENCE b/LICENCE
new file mode 100644
index 0000000..a71b854
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,21 @@
+simpleeval - Copyright (c) 2013-2017 Daniel Fairhead
+
+(MIT Licence)
+
+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/PKG-INFO b/PKG-INFO
deleted file mode 100644
index 9933cb5..0000000
--- a/PKG-INFO
+++ /dev/null
@@ -1,323 +0,0 @@
-Metadata-Version: 1.1
-Name: simpleeval
-Version: 0.9.3
-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.9.3
-Description: simpleeval (Simple Eval)
- ========================
-
- .. image:: https://travis-ci.org/danthedeckie/simpleeval.svg?branch=master
- :target: https://travis-ci.org/danthedeckie/simpleeval
- :alt: Build Status
-
- .. image:: https://coveralls.io/repos/github/danthedeckie/simpleeval/badge.svg?branch=master
- :target: https://coveralls.io/r/danthedeckie/simpleeval?branch=master
- :alt: Coverage Status
-
- .. image:: https://badge.fury.io/py/simpleeval.svg
- :target: https://badge.fury.io/py/simpleeval
- :alt: PyPI Version
-
- 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, pull it in from PyPI (pip or easy_install), or
- even just a single file you can dump into a project.
-
- 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:
-
- .. code-block:: python
-
- from simpleeval import simple_eval
-
- simple_eval("21 + 21")
-
- returns ``42``.
-
- Expressions can be as complex and convoluted as you want:
-
- .. code-block:: python
-
- simple_eval("21 + 19 / 7 + (8 % 3) ** 9")
-
- returns ``535.714285714``.
-
- You can add your own functions in as well.
-
- .. code-block:: python
-
- 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:
-
- 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`` |
- +--------+------------------------------------+
- | ``in`` | is something contained within |
- | | something else. |
- | | ``"spam" in "my breakfast"`` |
- | | -> ``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):
-
- .. code-block:: python
-
- >>> 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:
-
- .. code-block:: python
-
- >>> simple_eval("'equal' if x == y else 'not equal'",
- names={"x": 1, "y": 2})
- 'not equal'
-
- which, of course, can be nested:
-
- .. code-block:: python
-
- >>> 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:
-
- .. code-block:: python
-
- >>> 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
-
- .. code-block:: python
-
- >>> 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'.
-
- .. code-block:: python
-
- >>> 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:
-
-
- .. code-block:: python
-
- >>> 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 convenient for some use
- cases):
-
- .. code-block:: python
-
- >>> s = SimpleEval()
-
- >>> s.eval("1 + 1")
- 2
-
- >>> s.eval('100 * 10')
- 1000
-
- # 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)
-
- .. code-block:: python
-
- def boo():
- return 'Boo!'
-
- s = SimpleEval(functions={"boo": boo})
-
- or edit them after creation:
-
- .. code-block:: python
-
- s.names['fortytwo'] = 42
-
- this actually means you can modify names (or functions) with functions, if you
- really feel so inclined:
-
- .. code-block:: python
-
- 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.
-
- Compound Types
- --------------
-
- Compound types (``dict``, ``tuple``, ``list``, ``set``) in general just work if
- you pass them in as named objects. If you want to allow creation of these, the
- ``EvalWithCompoundTypes`` class works. Just replace any use of ``SimpleEval`` with
- that.
-
- Other...
- --------
-
- The library supports both python 2 and 3.
-
- Object attributes that start with ``_`` or ``func_`` are disallowed by default.
- If you really need that (BE CAREFUL!), then modify the module global
- ``simpleeval.DISALLOW_PREFIXES``.
-
- 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!
-
-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
diff --git a/README.rst b/README.rst
index d5f3179..f118bc0 100644
--- a/README.rst
+++ b/README.rst
@@ -159,12 +159,15 @@ 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
+Strings (and other Iterables) Safety
~~~~~~~~~~~~~
There are also limits on string length (100000 characters,
``MAX_STRING_LENGTH``). This can be changed if you wish.
+Related to this, if you try to create a silly long string/bytes/list, by doing
+``'i want to break free'.split() * 9999999999`` for instance, it will block you.
+
If Expressions
--------------
@@ -204,6 +207,33 @@ and even re-name them so that expressions can be shorter
>>> simple_eval("d(100) + double(1)", functions={"d": double, "double":double})
202
+If you don't provide your own ``functions`` dict, then the the following defaults
+are provided in the ``DEFAULT_FUNCTIONS`` dict:
+
++----------------+--------------------------------------------------+
+| ``randint(x)`` | Return a random ``int`` below ``x`` |
++----------------+--------------------------------------------------+
+| ``rand()`` | Return a random ``float`` between 0 and 1 |
++----------------+--------------------------------------------------+
+| ``int(x)`` | Convert ``x`` to an ``int``. |
++----------------+--------------------------------------------------+
+| ``float(x)`` | Convert ``x`` to a ``float``. |
++----------------+--------------------------------------------------+
+| ``str(x)`` | Convert ``x`` to a ``str`` (``unicode`` in py2) |
++----------------+--------------------------------------------------+
+
+If you want to provide a list of functions, but want to keep these as well,
+then you can do a normal python ``.copy()`` & ``.update``:
+
+.. code-block:: python
+
+ >>> my_functions = simpleeval.DEFAULT_FUNCTIONS.copy()
+ >>> my_functions.update(
+ square=(lambda x:x*x),
+ double=(lambda x:x+x),
+ )
+ >>> simple_eval('square(randint(100))', functions=my_functions)
+
Names
-----
@@ -229,6 +259,8 @@ You can also hand the handling of names over to a function, if you prefer:
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.
+The two default names that are provided are ``True`` and ``False``. So if you want to provide your own names, but want ``True`` and ``False`` to keep working, either provide them yourself, or ``.copy()`` and ``.update`` the ``DEFAULT_NAMES``. (See functions example above).
+
Creating an Evaluator Class
---------------------------
@@ -292,6 +324,25 @@ you pass them in as named objects. If you want to allow creation of these, the
``EvalWithCompoundTypes`` class works. Just replace any use of ``SimpleEval`` with
that.
+Extending
+---------
+
+The ``SimpleEval`` class is pretty easy to extend. For instance, to create a
+version that disallows method invocation on objects:
+
+.. code-block:: python
+
+ import ast
+ import simpleeval
+
+ class EvalNoMethods(simpleeval.SimpleEval):
+ def _eval_call(self, node):
+ if isinstance(node.func, ast.Attribute):
+ raise simpleeval.FeatureNotAvailable("No methods please, we're British")
+ return super(EvalNoMethods, self)._eval_call(node)
+
+and then use ``EvalNoMethods`` instead of the ``SimpleEval`` class.
+
Other...
--------
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 861a9f5..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-[egg_info]
-tag_build =
-tag_date = 0
-tag_svn_revision = 0
-
diff --git a/setup.py b/setup.py
index 76afb03..860c0fc 100644
--- a/setup.py
+++ b/setup.py
@@ -1,5 +1,5 @@
from setuptools import setup
-__version__ = '0.9.3'
+__version__ = '0.9.5'
setup(
name='simpleeval',
diff --git a/simpleeval.egg-info/PKG-INFO b/simpleeval.egg-info/PKG-INFO
deleted file mode 100644
index 9933cb5..0000000
--- a/simpleeval.egg-info/PKG-INFO
+++ /dev/null
@@ -1,323 +0,0 @@
-Metadata-Version: 1.1
-Name: simpleeval
-Version: 0.9.3
-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.9.3
-Description: simpleeval (Simple Eval)
- ========================
-
- .. image:: https://travis-ci.org/danthedeckie/simpleeval.svg?branch=master
- :target: https://travis-ci.org/danthedeckie/simpleeval
- :alt: Build Status
-
- .. image:: https://coveralls.io/repos/github/danthedeckie/simpleeval/badge.svg?branch=master
- :target: https://coveralls.io/r/danthedeckie/simpleeval?branch=master
- :alt: Coverage Status
-
- .. image:: https://badge.fury.io/py/simpleeval.svg
- :target: https://badge.fury.io/py/simpleeval
- :alt: PyPI Version
-
- 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, pull it in from PyPI (pip or easy_install), or
- even just a single file you can dump into a project.
-
- 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:
-
- .. code-block:: python
-
- from simpleeval import simple_eval
-
- simple_eval("21 + 21")
-
- returns ``42``.
-
- Expressions can be as complex and convoluted as you want:
-
- .. code-block:: python
-
- simple_eval("21 + 19 / 7 + (8 % 3) ** 9")
-
- returns ``535.714285714``.
-
- You can add your own functions in as well.
-
- .. code-block:: python
-
- 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:
-
- 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`` |
- +--------+------------------------------------+
- | ``in`` | is something contained within |
- | | something else. |
- | | ``"spam" in "my breakfast"`` |
- | | -> ``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):
-
- .. code-block:: python
-
- >>> 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:
-
- .. code-block:: python
-
- >>> simple_eval("'equal' if x == y else 'not equal'",
- names={"x": 1, "y": 2})
- 'not equal'
-
- which, of course, can be nested:
-
- .. code-block:: python
-
- >>> 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:
-
- .. code-block:: python
-
- >>> 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
-
- .. code-block:: python
-
- >>> 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'.
-
- .. code-block:: python
-
- >>> 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:
-
-
- .. code-block:: python
-
- >>> 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 convenient for some use
- cases):
-
- .. code-block:: python
-
- >>> s = SimpleEval()
-
- >>> s.eval("1 + 1")
- 2
-
- >>> s.eval('100 * 10')
- 1000
-
- # 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)
-
- .. code-block:: python
-
- def boo():
- return 'Boo!'
-
- s = SimpleEval(functions={"boo": boo})
-
- or edit them after creation:
-
- .. code-block:: python
-
- s.names['fortytwo'] = 42
-
- this actually means you can modify names (or functions) with functions, if you
- really feel so inclined:
-
- .. code-block:: python
-
- 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.
-
- Compound Types
- --------------
-
- Compound types (``dict``, ``tuple``, ``list``, ``set``) in general just work if
- you pass them in as named objects. If you want to allow creation of these, the
- ``EvalWithCompoundTypes`` class works. Just replace any use of ``SimpleEval`` with
- that.
-
- Other...
- --------
-
- The library supports both python 2 and 3.
-
- Object attributes that start with ``_`` or ``func_`` are disallowed by default.
- If you really need that (BE CAREFUL!), then modify the module global
- ``simpleeval.DISALLOW_PREFIXES``.
-
- 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!
-
-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
diff --git a/simpleeval.egg-info/SOURCES.txt b/simpleeval.egg-info/SOURCES.txt
deleted file mode 100644
index e0716d8..0000000
--- a/simpleeval.egg-info/SOURCES.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-MANIFEST.in
-README.rst
-setup.py
-simpleeval.py
-test_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
deleted file mode 100644
index 8b13789..0000000
--- a/simpleeval.egg-info/dependency_links.txt
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/simpleeval.egg-info/top_level.txt b/simpleeval.egg-info/top_level.txt
deleted file mode 100644
index 49a7c04..0000000
--- a/simpleeval.egg-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-simpleeval
diff --git a/simpleeval.py b/simpleeval.py
index fc9dc91..79885de 100644
--- a/simpleeval.py
+++ b/simpleeval.py
@@ -1,4 +1,4 @@
-'''
+"""
SimpleEval - (C) 2013-2017 Daniel Fairhead
-------------------------------------
@@ -42,6 +42,7 @@ Contributors:
- perkinslr (Logan Perkins) (.__globals__ or .func_ breakouts)
- impala2 (Kirill Stepanov) (massive _eval refactor)
- gk (ugik) (Other iterables than str can DOS too, and can be made)
+- daveisfera (Dave Johansen) 'not' Boolean op, Pycharm and pep8 fixes.
-------------------------------------
Usage:
@@ -79,7 +80,7 @@ well:
>>> simple_eval("40 + two", names={"two": 2})
42
-'''
+"""
import ast
import sys
@@ -100,12 +101,12 @@ PYTHON3 = sys.version_info[0] == 3
class InvalidExpression(Exception):
- ''' Generic Exception '''
+ """ Generic Exception """
pass
class FunctionNotDefined(InvalidExpression):
- ''' sorry! That function isn't defined! '''
+ """ 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)
@@ -117,7 +118,7 @@ class FunctionNotDefined(InvalidExpression):
class NameNotDefined(InvalidExpression):
- ''' a name isn't defined. '''
+ """ a name isn't defined. """
def __init__(self, name, expression):
self.name = name
self.message = "'{0}' is not defined for expression '{1}'".format(
@@ -129,7 +130,7 @@ class NameNotDefined(InvalidExpression):
class AttributeDoesNotExist(InvalidExpression):
- '''attribute does not exist'''
+ """attribute does not exist"""
def __init__(self, attr, expression):
self.message = \
"Attribute '{0}' does not exist in expression '{1}'".format(
@@ -139,18 +140,18 @@ class AttributeDoesNotExist(InvalidExpression):
class FeatureNotAvailable(InvalidExpression):
- ''' What you're trying to do is not allowed. '''
+ """ 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! '''
+ """ Sorry! That number is too high. I don't want to spend the
+ next 10 years evaluating this expression! """
pass
class IterableTooLong(InvalidExpression):
- ''' That iterable is **way** too long, baby. '''
+ """ That iterable is **way** too long, baby. """
pass
@@ -159,12 +160,12 @@ class IterableTooLong(InvalidExpression):
def random_int(top):
- ''' return a random int below <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 '''
+ """ 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))
@@ -172,7 +173,7 @@ def safe_power(a, b): # pylint: disable=invalid-name
def safe_mult(a, b): # pylint: disable=invalid-name
- ''' limit the number of times an iterable can be repeated... '''
+ """ limit the number of times an iterable can be repeated... """
if hasattr(a, '__len__') and b*len(a) > MAX_STRING_LENGTH:
raise IterableTooLong('Sorry, I will not evalute something that long.')
@@ -183,7 +184,7 @@ def safe_mult(a, b): # pylint: disable=invalid-name
def safe_add(a, b): # pylint: disable=invalid-name
- ''' iterable length limit again '''
+ """ iterable length limit again """
if hasattr(a, '__len__') and hasattr(b, '__len__'):
if len(a) + len(b) > MAX_STRING_LENGTH:
raise IterableTooLong("Sorry, adding those two together would"
@@ -200,6 +201,7 @@ DEFAULT_OPERATORS = {ast.Add: safe_add, ast.Sub: op.sub, ast.Mult: safe_mult,
ast.Eq: op.eq, ast.NotEq: op.ne,
ast.Gt: op.gt, ast.Lt: op.lt,
ast.GtE: op.ge, ast.LtE: op.le,
+ ast.Not: op.not_,
ast.USub: op.neg, ast.UAdd: op.pos,
ast.In: lambda x, y: op.contains(y, x),
ast.NotIn: lambda x, y: not op.contains(y, x),
@@ -216,17 +218,17 @@ DEFAULT_NAMES = {"True": True, "False": False}
class SimpleEval(object): # pylint: disable=too-few-public-methods
- ''' A very simple expression parser.
+ """ 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. '''
+ functions (add, random, get_val, whatever) and names. """
if not operators:
operators = DEFAULT_OPERATORS
@@ -250,7 +252,6 @@ class SimpleEval(object): # pylint: disable=too-few-public-methods
ast.IfExp: self._eval_ifexp,
ast.Call: self._eval_call,
ast.keyword: self._eval_keyword,
- ast.Name: self._eval_name,
ast.Subscript: self._eval_subscript,
ast.Attribute: self._eval_attribute,
ast.Index: self._eval_index,
@@ -262,8 +263,8 @@ class SimpleEval(object): # pylint: disable=too-few-public-methods
self.nodes[ast.NameConstant] = self._eval_nameconstant
def eval(self, expr):
- ''' evaluate an expresssion, using the operators, functions and
- names previously set up. '''
+ """ 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...
@@ -273,7 +274,7 @@ class SimpleEval(object): # pylint: disable=too-few-public-methods
return self._eval(ast.parse(expr.strip()).body[0].value)
def _eval(self, node):
- ''' The internal evaluator used on each node in the parsed tree. '''
+ """ The internal evaluator used on each node in the parsed tree. """
try:
handler = self.nodes[type(node)]
@@ -283,17 +284,20 @@ class SimpleEval(object): # pylint: disable=too-few-public-methods
return handler(node)
- def _eval_num(self, node):
+ @staticmethod
+ def _eval_num(node):
return node.n
- def _eval_str(self, node):
+ @staticmethod
+ def _eval_str(node):
if len(node.s) > MAX_STRING_LENGTH:
raise IterableTooLong("String Literal in statement is too long!"
" ({0}, when {1} is max)".format(
- len(node.s), MAX_STRING_LENGTH))
+ len(node.s), MAX_STRING_LENGTH))
return node.s
- def _eval_nameconstant(self, node):
+ @staticmethod
+ def _eval_nameconstant(node):
return node.value
def _eval_unaryop(self, node):
@@ -305,6 +309,7 @@ class SimpleEval(object): # pylint: disable=too-few-public-methods
def _eval_boolop(self, node):
if isinstance(node.op, ast.And):
+ vout = False
for value in node.values:
vout = self._eval(value)
if not vout:
@@ -367,6 +372,9 @@ class SimpleEval(object): # pylint: disable=too-few-public-methods
' evaluator'.format(node.id))
except KeyError:
+ if node.id in self.functions:
+ return self.functions[node.id]
+
raise NameNotDefined(node.id, self.expr)
def _eval_subscript(self, node):
@@ -378,8 +386,6 @@ class SimpleEval(object): # pylint: disable=too-few-public-methods
except KeyError:
raise
- return self._eval(node.value)[self._eval(node.slice)]
-
def _eval_attribute(self, node):
for prefix in DISALLOW_PREFIXES:
if node.attr.startswith(prefix):
@@ -417,13 +423,13 @@ class SimpleEval(object): # pylint: disable=too-few-public-methods
class EvalWithCompoundTypes(SimpleEval):
- '''
+ """
SimpleEval with additional Compound Types, and their respective
function editions. (list, tuple, dict, set).
- '''
+ """
- def __init__(self, *args, **kwargs):
- super(EvalWithCompoundTypes, self).__init__(*args, **kwargs)
+ def __init__(self, operators=None, functions=None, names=None):
+ super(EvalWithCompoundTypes, self).__init__(operators, functions, names)
self.functions.update(
list=list,
@@ -453,7 +459,7 @@ class EvalWithCompoundTypes(SimpleEval):
def simple_eval(expr, operators=None, functions=None, names=None):
- ''' Simply evaluate an expresssion '''
+ """ Simply evaluate an expresssion """
s = SimpleEval(operators=operators,
functions=functions,
names=names)
diff --git a/test_simpleeval.py b/test_simpleeval.py
index ca07b6b..66eff7e 100644
--- a/test_simpleeval.py
+++ b/test_simpleeval.py
@@ -1,10 +1,10 @@
-'''
+"""
Unit tests for simpleeval.
--------------------------
Most of this stuff is pretty basic.
-'''
+"""
# pylint: disable=too-many-public-methods, missing-docstring
import unittest
@@ -12,29 +12,29 @@ import operator
import ast
import simpleeval
from simpleeval import (
- SimpleEval, EvalWithCompoundTypes, NameNotDefined,
+ SimpleEval, EvalWithCompoundTypes, FeatureNotAvailable, FunctionNotDefined, NameNotDefined,
InvalidExpression, AttributeDoesNotExist, simple_eval
)
class DRYTest(unittest.TestCase):
- ''' Stuff we need to do every test, let's do here instead..
- Don't Repeat Yourself. '''
+ """ Stuff we need to do every test, let's do here instead..
+ Don't Repeat Yourself. """
def setUp(self):
- ''' initialize a SimpleEval '''
+ """ 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 '''
+ 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. '''
+ """ Simple expressions. """
def test_maths_with_ints(self):
- ''' simple maths expressions '''
+ """ simple maths expressions """
self.t("21 + 21", 42)
self.t("6*7", 42)
@@ -58,6 +58,12 @@ class TestBasic(DRYTest):
' or (out and position > 6 and -5)'
' or (not out and 15)', -10)
+ def test_not(self):
+ self.t('not False', True)
+ self.t('not True', False)
+ self.t('not 0', True)
+ self.t('not 1', False)
+
def test_maths_with_floats(self):
self.t("11.02 - 9.1", 1.92)
self.t("29.1+39", 68.1)
@@ -91,7 +97,7 @@ class TestBasic(DRYTest):
self.t("False < True", True)
def test_if_else(self):
- ''' x if y else z '''
+ """ x if y else z """
# and test if/else expressions:
self.t("'a' if 1 == 1 else 'b'", 'a')
@@ -101,15 +107,15 @@ class TestBasic(DRYTest):
self.t("'a' if 4 < 1 else 'b' if 1 == 2 else 'c'", 'c')
def test_default_conversions(self):
- ''' conversion between types '''
+ """ conversion between types """
self.t('int("20") + int(0.22*100)', 42)
self.t('float("42")', 42.0)
self.t('"Test Stuff!" + str(11)', "Test Stuff!11")
def test_slicing(self):
- self.s.operators[ast.Slice] = (operator.getslice \
- if hasattr(operator, "getslice") else operator.getitem)
+ self.s.operators[ast.Slice] = (operator.getslice
+ if hasattr(operator, "getslice") else operator.getitem)
self.t("'hello'[1]", "e")
self.t("'hello'[:]", "hello")
self.t("'hello'[:3]", "hel")
@@ -135,10 +141,10 @@ class TestBasic(DRYTest):
class TestFunctions(DRYTest):
- ''' Functions for expressions to play with '''
+ """ Functions for expressions to play with """
def test_load_file(self):
- ''' add in a function which loads data from an external file. '''
+ """ add in a function which loads data from an external file. """
# write to the file:
@@ -148,9 +154,9 @@ class TestFunctions(DRYTest):
# 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()
+ """ load a file and return its contents """
+ with open(filename) as f2:
+ return f2.read()
# simple load:
@@ -171,7 +177,7 @@ class TestFunctions(DRYTest):
self.t("int(read('file.txt'))", 42)
def test_randoms(self):
- ''' test the rand() and randint() functions '''
+ """ test the rand() and randint() functions """
self.s.functions['type'] = type
@@ -234,24 +240,24 @@ class TestFunctions(DRYTest):
class TestOperators(DRYTest):
- ''' Test adding in new operators, removing them, make sure it works. '''
+ """ Test adding in new operators, removing them, make sure it works. """
pass
class TestTryingToBreakOut(DRYTest):
- ''' Test various weird methods to break the security sandbox... '''
+ """ Test various weird methods to break the security sandbox... """
def test_import(self):
- ''' usual suspect. import '''
+ """ 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. '''
+ """ exponent operations can take a long time. """
old_max = simpleeval.MAX_POWER
- self.t("9**9**5", 9**9**5)
+ self.t("9**9**5", 9 ** 9 ** 5)
with self.assertRaises(simpleeval.NumberTooHigh):
self.t("9**9**8", 0)
@@ -274,7 +280,6 @@ class TestTryingToBreakOut(DRYTest):
self.t('(1).from_bytes(("123123123123123123123123").encode()*999999, "big")', 0)
def test_string_length(self):
-
with self.assertRaises(simpleeval.IterableTooLong):
self.t("50000*'text'", 0)
@@ -298,14 +303,14 @@ class TestTryingToBreakOut(DRYTest):
self.t("'stuff'*100000", 100000 * 'stuff')
with self.assertRaises(simpleeval.IterableTooLong):
- self.t("'" + (10000 * "stuff") +"'*100", 0)
+ self.t("'" + (10000 * "stuff") + "'*100", 0)
with self.assertRaises(simpleeval.IterableTooLong):
self.t("'" + (50000 * "stuff") + "'", 0)
def test_bytes_array_test(self):
self.t("'20000000000000000000'.encode() * 5000",
- '20000000000000000000'.encode() * 5000)
+ '20000000000000000000'.encode() * 5000)
with self.assertRaises(simpleeval.IterableTooLong):
self.t("'123121323123131231223'.encode() * 5000", 20)
@@ -317,7 +322,7 @@ class TestTryingToBreakOut(DRYTest):
self.t("('spam spam spam' * 5000).split() * 5000", None)
def test_python_stuff(self):
- ''' other various pythony things. '''
+ """ other various pythony things. """
# it only evaluates the first statement:
self.t("a = 11; x = 21; x + x", 11)
@@ -327,7 +332,7 @@ class TestTryingToBreakOut(DRYTest):
self.t("[x for x in (1, 2, 3)]", (1, 2, 3))
def test_function_globals_breakout(self):
- ''' by accessing function.__globals__ or func_... '''
+ """ by accessing function.__globals__ or func_... """
# thanks perkinslr.
self.s.functions['x'] = lambda y: y + y
@@ -337,10 +342,12 @@ class TestTryingToBreakOut(DRYTest):
self.t('x.__globals__', None)
class EscapeArtist(object):
- def trapdoor(self):
+ @staticmethod
+ def trapdoor():
return 42
- def _quasi_private(self):
+ @staticmethod
+ def _quasi_private():
return 84
self.s.names['houdini'] = EscapeArtist()
@@ -372,7 +379,7 @@ class TestTryingToBreakOut(DRYTest):
class TestCompoundTypes(DRYTest):
- ''' Test the compound-types edition of the library '''
+ """ Test the compound-types edition of the library """
def setUp(self):
self.s = EvalWithCompoundTypes()
@@ -431,12 +438,33 @@ class TestCompoundTypes(DRYTest):
self.t('2 in {1,2,3,4}', True)
self.t('22 not in {1,2,3,4}', True)
+ def test_not(self):
+ self.t('not []', True)
+ self.t('not [0]', False)
+ self.t('not {}', True)
+ self.t('not {0: 1}', False)
+ self.t('not {0}', False)
+
+ def test_use_func(self):
+ self.s = EvalWithCompoundTypes(functions={"map": map, "str": str})
+ self.t('list(map(str, [-1, 0, 1]))', ['-1', '0', '1'])
+ with self.assertRaises(NameNotDefined):
+ self.s.eval('list(map(bad, [-1, 0, 1]))')
+
+ with self.assertRaises(FunctionNotDefined):
+ self.s.eval('dir(str)')
+ with self.assertRaises(FeatureNotAvailable):
+ self.s.eval('str.__dict__')
+
+ self.s = EvalWithCompoundTypes(functions={"dir": dir, "str": str})
+ self.t('dir(str)', dir(str))
+
class TestNames(DRYTest):
- ''' 'names', what other languages call variables... '''
+ """ 'names', what other languages call variables... """
def test_none(self):
- ''' what to do when names isn't defined, or is 'none' '''
+ """ what to do when names isn't defined, or is 'none' """
with self.assertRaises(NameNotDefined):
self.t("a == 2", None)
@@ -456,7 +484,7 @@ class TestNames(DRYTest):
self.t('a.b.d**2', 42)
def test_dict(self):
- ''' using a normal dict for names lookup '''
+ """ using a normal dict for names lookup """
self.s.names = {'a': 42}
self.t("a + a", 84)
@@ -521,9 +549,11 @@ class TestNames(DRYTest):
self.assertEqual(self.s.names['a']['d'], 11)
def test_object(self):
- ''' using an object for name lookup '''
+ """ using an object for name lookup """
+
class TestObject(object):
- def method_thing(self):
+ @staticmethod
+ def method_thing():
return 42
o = TestObject()
@@ -544,10 +574,10 @@ class TestNames(DRYTest):
self.t('o.d', None)
def test_func(self):
- ''' using a function for 'names lookup' '''
+ """ using a function for 'names lookup' """
- def resolver(node): # pylint: disable=unused-argument
- ''' all names now equal 1024! '''
+ def resolver(_):
+ """ all names now equal 1024! """
return 1024
self.s.names = resolver
@@ -558,7 +588,7 @@ class TestNames(DRYTest):
# the function can do stuff with the value it's sent:
def my_name(node):
- ''' all names equal their textual name, twice. '''
+ """ all names equal their textual name, twice. """
return node.id + node.id
self.s.names = my_name
@@ -566,20 +596,21 @@ class TestNames(DRYTest):
self.t("a", "aa")
def test_from_doc(self):
- ''' the 'name first letter as value' example from the docs '''
+ """ 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
+ """ 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_whitespace(DRYTest):
- ''' test that incorrect whitespace (preceding/trailing) doesn't matter. '''
+class TestWhitespace(DRYTest):
+ """ test that incorrect whitespace (preceding/trailing) doesn't matter. """
+
def test_no_whitespace(self):
self.t('200 + 200', 400)
@@ -599,8 +630,9 @@ class Test_whitespace(DRYTest):
self.t(" \t 200 + 200 ", 400)
-class Test_simple_eval(unittest.TestCase):
- ''' test the 'simple_eval' wrapper function '''
+class TestSimpleEval(unittest.TestCase):
+ """ test the 'simple_eval' wrapper function """
+
def test_basic_run(self):
self.assertEqual(simple_eval('6*7'), 42)
@@ -609,5 +641,28 @@ class Test_simple_eval(unittest.TestCase):
self.assertEqual(simple_eval('randint(200) < 200 and rand() > 0'), True)
+class TestExtendingClass(unittest.TestCase):
+ """
+ It should be pretty easy to extend / inherit from the SimpleEval class,
+ to further lock things down, or unlock stuff, or whatever.
+ """
+
+ def test_methods_forbidden(self):
+ # Example from README
+ class EvalNoMethods(simpleeval.SimpleEval):
+ def _eval_call(self, node):
+ if isinstance(node.func, ast.Attribute):
+ raise simpleeval.FeatureNotAvailable("No methods please, we're British")
+ return super(EvalNoMethods, self)._eval_call(node)
+
+ e = EvalNoMethods()
+
+ self.assertEqual(e.eval('"stuff happens"'), "stuff happens")
+ self.assertEqual(e.eval('22 + 20'), 42)
+
+ with self.assertRaises(simpleeval.FeatureNotAvailable):
+ e.eval('" blah ".strip()')
+
+
if __name__ == '__main__':
unittest.main()
commit cb0c53570c0f84ef748b630bad1459ace291f6a9
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Mon Sep 4 16:20:07 2017 +0200
Bump the Standards-Version to 4.1.0, no changes needed.
diff --git a/debian/control b/debian/control
index 2c9993d..7d897cf 100644
--- a/debian/control
+++ b/debian/control
@@ -10,7 +10,7 @@ Build-Depends:
python-setuptools,
python3,
python3-setuptools,
-Standards-Version: 4.0.1
+Standards-Version: 4.1.0
Homepage: https://github.com/danthedeckie/simpleeval
Vcs-Browser: https://anonscm.debian.org/cgit/tryton/simpleeval.git
Vcs-Git: https://anonscm.debian.org/cgit/tryton/simpleeval.git
--
simpleeval
More information about the tryton-debian-vcs
mailing list