[tryton-debian-vcs] simpleeval branch upstream updated. upstream/0.8.2-2-ga31f5d0
Mathias Behrle
tryton-debian-vcs at alioth.debian.org
Mon Nov 9 10:39:58 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=upstream/0.8.2-2-ga31f5d0
commit a31f5d0ff733625552267dc45a61ce1a10e6018c
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Mon Nov 9 11:08:01 2015 +0100
Adding upstream version 0.8.7.
Signed-off-by: Mathias Behrle <mathiasb at m9s.biz>
diff --git a/PKG-INFO b/PKG-INFO
index b3a0e24..d505fd3 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,12 +1,12 @@
Metadata-Version: 1.1
Name: simpleeval
-Version: 0.8.5
+Version: 0.8.7
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.5
+Download-URL: https://github.com/danthedeckie/simpleeval/tarball/0.8.7
Description: simpleeval (Simple Eval)
========================
@@ -193,7 +193,7 @@ Description: simpleeval (Simple Eval)
---------------------------
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): ::
+ 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): ::
s = SimpleEval()
s.eval("1 + 1")
diff --git a/README.rst b/README.rst
index 0bfb650..266f0b6 100644
--- a/README.rst
+++ b/README.rst
@@ -184,7 +184,7 @@ 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): ::
+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): ::
s = SimpleEval()
s.eval("1 + 1")
diff --git a/setup.py b/setup.py
index 2d49312..0e71ef7 100644
--- a/setup.py
+++ b/setup.py
@@ -1,5 +1,5 @@
from setuptools import setup
-__version__ = '0.8.5'
+__version__ = '0.8.7'
setup(
name = 'simpleeval',
diff --git a/simpleeval.egg-info/PKG-INFO b/simpleeval.egg-info/PKG-INFO
index b3a0e24..d505fd3 100644
--- a/simpleeval.egg-info/PKG-INFO
+++ b/simpleeval.egg-info/PKG-INFO
@@ -1,12 +1,12 @@
Metadata-Version: 1.1
Name: simpleeval
-Version: 0.8.5
+Version: 0.8.7
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.5
+Download-URL: https://github.com/danthedeckie/simpleeval/tarball/0.8.7
Description: simpleeval (Simple Eval)
========================
@@ -193,7 +193,7 @@ Description: simpleeval (Simple Eval)
---------------------------
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): ::
+ 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): ::
s = SimpleEval()
s.eval("1 + 1")
diff --git a/simpleeval.py b/simpleeval.py
index 7f29d2e..81e4193 100644
--- a/simpleeval.py
+++ b/simpleeval.py
@@ -1,5 +1,5 @@
'''
-SimpleEval - (C) 2013/2014 Daniel Fairhead
+SimpleEval - (C) 2013/2015 Daniel Fairhead
-------------------------------------
An short, easy to use, safe and reasonably extensible expression evaluator.
@@ -35,7 +35,10 @@ modifications and many improvments.
-------------------------------------
Contributors:
-corro (Robin Baumgartner) (py3k)
+- corro (Robin Baumgartner) (py3k)
+- dratchkov (David R) (nested dicts)
+- marky1991 (Mark Young) (slicing)
+- T045T (Nils Berg) (!=, py3kstr, obj.attributes)
-------------------------------------
Usage:
@@ -76,6 +79,7 @@ well:
'''
import ast
+import sys
import operator as op
from random import random
@@ -84,6 +88,7 @@ from random import random
MAX_STRING_LENGTH = 100000
MAX_POWER = 4000000 # highest exponent
+PYTHON3 = sys.version_info[0] == 3
########################################
# Exceptions:
@@ -114,6 +119,14 @@ class NameNotDefined(InvalidExpression):
# pylint: disable=bad-super-call
super(InvalidExpression, self).__init__(self.message)
+class AttributeDoesNotExist(InvalidExpression):
+ '''attribute does not exist'''
+ def __init__(self, attr, expression):
+ self.message = "Attribute '{0}' does not exist in expression '{1}'".format(
+ attr, expression)
+ self.attr = attr
+ self.expression = expression
+
class FeatureNotAvailable(InvalidExpression):
''' What you're trying to do is not allowed. '''
pass
@@ -165,12 +178,12 @@ def safe_add(a, b): # pylint: disable=invalid-name
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.Eq: op.eq, ast.NotEq: op.ne, 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}
+ "int": int, "float": float, "str": str if PYTHON3 else unicode}
DEFAULT_NAMES = {"True": True, "False": False}
@@ -262,7 +275,13 @@ class SimpleEval(object): # pylint: disable=too-few-public-methods
elif isinstance(node, ast.Name): # a, b, c...
try:
- if isinstance(self.names, dict):
+ #This happens at least for slicing
+ #This is a safe thing to do because it is impossible
+ #that there is a true exression assigning to none
+ #(the compiler rejects it, so you can't even pass that to ast.parse)
+ if node.id == "None":
+ return None
+ elif isinstance(self.names, dict):
return self.names[node.id]
elif callable(self.names):
return self.names(node)
@@ -275,8 +294,34 @@ class SimpleEval(object): # pylint: disable=too-few-public-methods
raise NameNotDefined(node.id, self.expr)
elif isinstance(node, ast.Subscript): # b[1]
- return self._eval(node.value)[self._eval(node.slice.value)]
+ return self._eval(node.value)[self._eval(node.slice)]
+
+ elif isinstance(node, ast.Attribute): # a.b.c
+ try:
+ return self._eval(node.value)[node.attr]
+ except (KeyError, TypeError):
+ pass
+ # Maybe the base object is an actual object, not just a dict
+ try:
+ return getattr(self._eval(node.value), node.attr)
+ except (AttributeError, TypeError):
+ pass
+
+ # If it is neither, raise an exception
+ raise AttributeDoesNotExist(node.attr, self.expr)
+
+ elif isinstance(node, ast.Index):
+ return self._eval(node.value)
+ elif isinstance(node, ast.Slice):
+ lower = upper = step = None
+ if node.lower is not None:
+ lower = self._eval(node.lower)
+ if node.upper is not None:
+ upper = self._eval(node.upper)
+ if node.step is not None:
+ step = self._eval(node.step)
+ return slice(lower, upper, step)
else:
raise FeatureNotAvailable("Sorry, {0} is not available in this "
"evaluator".format(type(node).__name__ ))
diff --git a/test_simpleeval.py b/test_simpleeval.py
index 6fdf849..ec1689a 100644
--- a/test_simpleeval.py
+++ b/test_simpleeval.py
@@ -7,9 +7,9 @@
'''
# pylint: disable=too-many-public-methods, missing-docstring
-import unittest
+import unittest, operator, ast
import simpleeval
-from simpleeval import SimpleEval, NameNotDefined, InvalidExpression, simple_eval
+from simpleeval import SimpleEval, NameNotDefined, InvalidExpression, AttributeDoesNotExist, simple_eval
class DRYTest(unittest.TestCase):
''' Stuff we need to do every test, let's do here instead..
@@ -43,6 +43,7 @@ class TestBasic(DRYTest):
self.t('1 - 1 or 21', True)
self.t('1 - 1 and 11', False)
self.t('110 == 100 + 10 and True', True)
+ self.t('110 != 100 + 10 and True', False)
def test_maths_with_floats(self):
self.t("11.02 - 9.1", 1.92)
@@ -84,7 +85,24 @@ class TestBasic(DRYTest):
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")
+ 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.t("'hello'[1]", "e")
+ self.t("'hello'[:]", "hello")
+ self.t("'hello'[:3]", "hel")
+ self.t("'hello'[3:]", "lo")
+ self.t("'hello'[::2]", "hlo")
+ self.t("'hello'[::-1]", "olleh")
+ self.t("'hello'[3::]", "lo")
+ self.t("'hello'[:3:]", "hel")
+ self.t("'hello'[1:3]", "el")
+ self.t("'hello'[1:3:]", "el")
+ self.t("'hello'[1::2]", "el")
+ self.t("'hello'[:1:2]", "h")
+ self.t("'hello'[1:3:1]", "el")
+ self.t("'hello'[1:3:2]", "e")
class TestFunctions(DRYTest):
''' Functions for expressions to play with '''
@@ -106,7 +124,7 @@ class TestFunctions(DRYTest):
# simple load:
- self.s.functions = {u"read": load_file}
+ self.s.functions = {"read": load_file}
self.t("read('file.txt')", "42")
# and we should have *replaced* the default functions. Let's check:
@@ -226,6 +244,11 @@ class TestNames(DRYTest):
with self.assertRaises(InvalidExpression):
self.t('s', 21)
+ self.s.names = {'a' : {'b': {'c': 42}}}
+
+ with self.assertRaises(AttributeDoesNotExist):
+ self.t('a.b.d**2', 42)
+
def test_dict(self):
''' using a normal dict for names lookup '''
@@ -277,6 +300,39 @@ class TestNames(DRYTest):
self.assertEqual(self.s.names['c']['c']['c'], 11)
+ # nested dict
+
+ self.s.names = {'a' : {'b': {'c': 42}}}
+
+ self.t("a.b.c*2", 84)
+
+ self.t("a.b.c = 11", 11)
+
+ self.assertEqual(self.s.names['a']['b']['c'], 42)
+
+ self.t("a.d = 11", 11)
+
+ with self.assertRaises(KeyError):
+ self.assertEqual(self.s.names['a']['d'], 11)
+
+ def test_object(self):
+ ''' using an object for name lookp '''
+ class TestObject(object):
+ pass
+ o = TestObject()
+ o.a = 23
+ o.b = 42
+ o.c = TestObject()
+ o.c.d = 9001
+
+ self.s.names = {'o' : o}
+
+ self.t('o', o)
+ self.t('o.a', 23)
+ self.t('o.b + o.c.d', 9043)
+ with self.assertRaises(AttributeDoesNotExist):
+ self.t('o.d', None)
+
def test_func(self):
''' using a function for 'names lookup' '''
@@ -319,3 +375,6 @@ class Test_simple_eval(unittest.TestCase):
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)
+
+if __name__ == '__main__':
+ unittest.main()
--
simpleeval
More information about the tryton-debian-vcs
mailing list