Hello community, here is the log from the commit of package python-asteval for openSUSE:Factory checked in at 2019-03-06 15:52:29 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-asteval (Old) and /work/SRC/openSUSE:Factory/.python-asteval.new.28833 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-asteval" Wed Mar 6 15:52:29 2019 rev:3 rq:682133 version:0.9.13 Changes: -------- --- /work/SRC/openSUSE:Factory/python-asteval/python-asteval.changes 2018-08-31 10:45:19.567266102 +0200 +++ /work/SRC/openSUSE:Factory/.python-asteval.new.28833/python-asteval.changes 2019-03-06 15:52:38.628420863 +0100 @@ -1,0 +2,7 @@ +Wed Mar 6 12:17:43 UTC 2019 - Tomáš Chvátal <[email protected]> + +- Update 0.9.13: + * Various spelling fixes + * Error reporting tweaks + +------------------------------------------------------------------- Old: ---- asteval-0.9.12.tar.gz New: ---- asteval-0.9.13.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-asteval.spec ++++++ --- /var/tmp/diff_new_pack.0PJ7VE/_old 2019-03-06 15:52:40.100420568 +0100 +++ /var/tmp/diff_new_pack.0PJ7VE/_new 2019-03-06 15:52:40.100420568 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-asteval # -# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -12,31 +12,30 @@ # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. -# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# Please submit bugfixes or comments via https://bugs.opensuse.org/ # %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-asteval -Version: 0.9.12 +Version: 0.9.13 Release: 0 Summary: Safe, minimalistic evaluator of python expression using ast module License: MIT Group: Development/Languages/Python -Url: http://github.com/newville/asteval +URL: http://github.com/newville/asteval Source: https://files.pythonhosted.org/packages/source/a/asteval/asteval-%{version}.tar.gz BuildRequires: %{python_module setuptools} -# SECTION test requirements -BuildRequires: %{python_module numpy >= 1.6} -BuildRequires: %{python_module pytest} -BuildRequires: %{python_module six} -# /SECTION BuildRequires: fdupes BuildRequires: python-rpm-macros Requires: python-numpy >= 1.6 Requires: python-six BuildArch: noarch - +# SECTION test requirements +BuildRequires: %{python_module numpy >= 1.6} +BuildRequires: %{python_module pytest} +BuildRequires: %{python_module six} +# /SECTION %python_subpackages %description @@ -62,9 +61,7 @@ %python_expand %fdupes %{buildroot}%{$python_sitelib} %check -pushd tests -%python_expand PYTHONPATH=%{buildroot}%{$python_sitelib} py.test-%{$python_bin_suffix} -popd +%python_expand PYTHONPATH=%{buildroot}%{$python_sitelib} py.test-%{$python_bin_suffix} -v %files %{python_files} %doc README.rst ++++++ asteval-0.9.12.tar.gz -> asteval-0.9.13.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asteval-0.9.12/PKG-INFO new/asteval-0.9.13/PKG-INFO --- old/asteval-0.9.12/PKG-INFO 2018-03-08 23:09:06.000000000 +0100 +++ new/asteval-0.9.13/PKG-INFO 2018-09-29 15:15:38.000000000 +0200 @@ -1,12 +1,11 @@ Metadata-Version: 1.1 Name: asteval -Version: 0.9.12 +Version: 0.9.13 Summary: Safe, minimalistic evaluator of python expression using ast module Home-page: http://github.com/newville/asteval Author: Matthew Newville Author-email: [email protected] License: MIT -Description-Content-Type: UNKNOWN Description: ASTEVAL provides a numpy-aware, safe(ish) 'eval' function Emphasis is on mathematical expressions, and so numpy ufuncs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asteval-0.9.12/asteval/__init__.py new/asteval-0.9.13/asteval/__init__.py --- old/asteval-0.9.12/asteval/__init__.py 2018-03-08 23:07:09.000000000 +0100 +++ new/asteval-0.9.13/asteval/__init__.py 2018-09-29 15:08:22.000000000 +0200 @@ -9,8 +9,8 @@ Expressions can be compiled into ast node for later evaluation, using the values in the symbol table current at evaluation time. - version: 0.9.12 - last update: 2018-March-8 + version: 0.9.13 + last update: 2018-Sept-29 License: MIT Author: Matthew Newville <[email protected]> Center for Advanced Radiation Sources, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asteval-0.9.12/asteval/_version.py new/asteval-0.9.13/asteval/_version.py --- old/asteval-0.9.12/asteval/_version.py 2018-03-08 23:09:06.000000000 +0100 +++ new/asteval-0.9.13/asteval/_version.py 2018-09-29 15:15:38.000000000 +0200 @@ -8,11 +8,11 @@ version_json = ''' { - "date": "2018-03-08T14:46:40-0600", + "date": "2018-09-29T08:08:37-0500", "dirty": false, "error": null, - "full-revisionid": "c865690ee5a3f4e7f409fa758eecd23bdbc3ead9", - "version": "0.9.12" + "full-revisionid": "e388a003415cdebc910c3ac10bc5a395d10d9424", + "version": "0.9.13" } ''' # END VERSION_JSON diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asteval-0.9.12/asteval/asteval.py new/asteval-0.9.13/asteval/asteval.py --- old/asteval-0.9.12/asteval/asteval.py 2018-03-08 23:07:09.000000000 +0100 +++ new/asteval-0.9.13/asteval/asteval.py 2018-09-29 15:06:59.000000000 +0200 @@ -107,13 +107,17 @@ no_print : bool whether to support `print`. max_time : float - deprecated. max run time in seconds (see Note 2) [30.0] + deprecated, unreliable. max_time will be dropped soon. (default 86400) + readonly_symbols : iterable or `None` + symbols that the user can not assign to + builtins_readonly : bool + whether to blacklist all symbols that are in the initial symtable Notes ----- 1. setting `minimal=True` is equivalent to setting all `no_***` options to `True`. - 2. max_time is not reliable and support may be dropped soon. + 2. max_time is not reliable and no longer supported -- the keyword will be dropped soon. """ def __init__(self, symtable=None, usersyms=None, writer=None, @@ -121,7 +125,8 @@ no_if=False, no_for=False, no_while=False, no_try=False, no_functiondef=False, no_ifexp=False, no_listcomp=False, no_augassign=False, no_assert=False, no_delete=False, - no_raise=False, no_print=False, max_time=30): + no_raise=False, no_print=False, max_time=86400, + readonly_symbols=None, builtins_readonly=False): self.writer = writer or stdout self.err_writer = err_writer or stderr @@ -180,6 +185,14 @@ self.node_handlers['tryexcept'] = self.node_handlers['try'] self.node_handlers['tryfinally'] = self.node_handlers['try'] + if readonly_symbols is None: + self.readonly_symbols = set() + else: + self.readonly_symbols = set(readonly_symbols) + + if builtins_readonly: + self.readonly_symbols |= set(self.symtable) + self.no_deepcopy = [key for key, val in symtable.items() if (callable(val) or 'numpy.lib.index_tricks' in repr(val) @@ -237,9 +250,9 @@ self._interrupt = ast.Break() self.error.append(err) if self.error_msg is None: - self.error_msg = "%s in expr='%s'" % (msg, self.expr) + self.error_msg = "at expr='%s'" % (self.expr) elif len(msg) > 0: - self.error_msg = "%s\n %s" % (self.error_msg, msg) + self.error_msg = msg if exc is None: try: exc = self.error[0].exc @@ -450,7 +463,7 @@ """ if node.__class__ == ast.Name: - if not valid_symbol_name(node.id): + if not valid_symbol_name(node.id) or node.id in self.readonly_symbols: errmsg = "invalid symbol name (reserved word?) %s" % node.id self.raise_exception(node, exc=NameError, msg=errmsg) self.symtable[node.id] = val @@ -553,7 +566,7 @@ children.append(tnode.attr) tnode = tnode.value - if tnode.__class__ == ast.Name: + if tnode.__class__ == ast.Name and tnode.id not in self.readonly_symbols: children.append(tnode.id) children.reverse() self.symtable.pop('.'.join(children)) @@ -704,6 +717,7 @@ for tline in hnd.body: self.run(tline) break + break if no_errors and hasattr(node, 'orelse'): for tnode in node.orelse: self.run(tnode) @@ -756,8 +770,10 @@ try: return func(*args, **keywords) - except: - self.raise_exception(node, msg="Error running %s" % (func)) + except Exception as ex: + self.raise_exception( + node, msg="Error running function call '%s' with args %s and " + "kwargs %s: %s" % (func.__name__, args, keywords, ex)) def on_arg(self, node): # ('test', 'msg') """Arg for function definitions.""" @@ -770,6 +786,10 @@ raise Warning("decorated procedures not supported!") kwargs = [] + if not valid_symbol_name(node.name) or node.name in self.readonly_symbols: + errmsg = "invalid function name (reserved word?) %s" % node.name + self.raise_exception(node, exc=NameError, msg=errmsg) + offset = len(node.args.args) - len(node.args.defaults) for idef, defnode in enumerate(node.args.defaults): defval = self.run(defnode) @@ -817,6 +837,7 @@ """TODO: docstring in public method.""" self.__ininit__ = True self.name = name + self.__name__ = self.name self.__asteval__ = interp self.raise_exc = self.__asteval__.raise_exception self.__doc__ = doc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asteval-0.9.12/asteval.egg-info/PKG-INFO new/asteval-0.9.13/asteval.egg-info/PKG-INFO --- old/asteval-0.9.12/asteval.egg-info/PKG-INFO 2018-03-08 23:09:06.000000000 +0100 +++ new/asteval-0.9.13/asteval.egg-info/PKG-INFO 2018-09-29 15:15:38.000000000 +0200 @@ -1,12 +1,11 @@ Metadata-Version: 1.1 Name: asteval -Version: 0.9.12 +Version: 0.9.13 Summary: Safe, minimalistic evaluator of python expression using ast module Home-page: http://github.com/newville/asteval Author: Matthew Newville Author-email: [email protected] License: MIT -Description-Content-Type: UNKNOWN Description: ASTEVAL provides a numpy-aware, safe(ish) 'eval' function Emphasis is on mathematical expressions, and so numpy ufuncs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asteval-0.9.12/asteval.egg-info/SOURCES.txt new/asteval-0.9.13/asteval.egg-info/SOURCES.txt --- old/asteval-0.9.12/asteval.egg-info/SOURCES.txt 2018-03-08 23:09:06.000000000 +0100 +++ new/asteval-0.9.13/asteval.egg-info/SOURCES.txt 2018-09-29 15:15:38.000000000 +0200 @@ -23,4 +23,6 @@ doc/motivation.rst doc/_static/empty doc/_templates/indexsidebar.html +tests/A.py +tests/m.py tests/test_asteval.py \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asteval-0.9.12/doc/motivation.rst new/asteval-0.9.13/doc/motivation.rst --- old/asteval-0.9.12/doc/motivation.rst 2018-03-08 23:07:09.000000000 +0100 +++ new/asteval-0.9.13/doc/motivation.rst 2018-09-29 15:06:59.000000000 +0200 @@ -106,6 +106,16 @@ without knowing the values of `x`, `y`, and `z`. In short, runtime cannot be determined lexically. +Unfortunately, there is not a good way to check for a long-running +calculation within a single Python process. For example, the double +exponential example above will be stuck deep inside C-code evaluated by the +Python interpreter itself, and will not return or allow other threads to +run until that calculation is done. That is, from within a single process, +there is not a foolproof way to tell `asteval` when a calculation has taken +too long. The most reliable way to limit run time is to have a second +process watching the execution time of the asteval process and interrupt +or kill it. + For a limited range of problems, you can try to avoid asteval taking too long. For example, you may try to limit the *recursion limit* when executing expressions, with a code like this:: @@ -124,17 +134,15 @@ with limited_recursion(100): Interpreter().eval(...) -You can also pass in a `max_time` (in seconds) when you create an asteval -Interpreter, wich will try to limit the amount of time an expression will -take. This is actually of limited utility, since the calculation must -return to the asteval interpreter for the runtime to be checked at all. Many -long-running calculations will be stuck deep inside C-code evaluated by the -Python interpreter itself, and not return or allow other threads to run -until that calculation is done. That is, from within a single process, -there really is not a foolproof way to tell asteval to have a maximum -runtime. The most reliable way to put a firm limit on runtime is to have a -second process watching the execution time of the asteval process and -interrupt or kill it. +As an addition security concern, the default list of supported functions +does include Python's `open()` which will allow disk access to the +untrusted user. If `numpy` is supported, its `load()` and `loadtxt()` +functions will also be supported. This doesn't really elevate permissions, +but it does allow the user of the `asteval` interpreter to read files with +the privileges of the calling program. In some cases, this may not be +desireable, and you may want to remove some of these functions from the +symbol table, re-implement them, or ensure that your program cannot access +information on disk that should be kept private. In summary, while asteval attempts to be safe and is definitely safer than using :py:func:`eval`, there are many ways that asteval could be considered diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asteval-0.9.12/tests/A.py new/asteval-0.9.13/tests/A.py --- old/asteval-0.9.12/tests/A.py 1970-01-01 01:00:00.000000000 +0100 +++ new/asteval-0.9.13/tests/A.py 2018-09-21 02:52:44.000000000 +0200 @@ -0,0 +1,18 @@ +import sys +from asteval import Interpreter +aeval = Interpreter() + +script = """ +def tmp(x): + return tmp(x+1) +## +""" + +aeval(script) + +for rec_limit in (50, 100, 200, 500, 1000, 2000, 5000, 10000): + sys.setrecursionlimit(rec_limit) + aeval('tmp(33)') + msg = aeval.error_msg + if msg is not None: + print("rec limit=%d, length of error messge=%d" % (rec_limit, len(msg))) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asteval-0.9.12/tests/m.py new/asteval-0.9.13/tests/m.py --- old/asteval-0.9.12/tests/m.py 1970-01-01 01:00:00.000000000 +0100 +++ new/asteval-0.9.13/tests/m.py 2018-09-21 02:33:45.000000000 +0200 @@ -0,0 +1,8 @@ +from asteval import Interpreter + +aeval = Interpreter() + +text = """ +def foo(): + return foo() +""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asteval-0.9.12/tests/test_asteval.py new/asteval-0.9.13/tests/test_asteval.py --- old/asteval-0.9.12/tests/test_asteval.py 2018-03-08 23:07:09.000000000 +0100 +++ new/asteval-0.9.13/tests/test_asteval.py 2018-09-29 15:06:59.000000000 +0200 @@ -16,6 +16,8 @@ PY3 = version_info[0] == 3 PY33Plus = PY3 and version_info[1] >= 3 PY35Plus = PY3 and version_info[1] >= 5 +PY35 = PY3 and version_info[1] == 5 +PY36Plus = PY3 and version_info[1] >= 6 if PY3: # noinspection PyUnresolvedReferences @@ -616,6 +618,16 @@ """)) self.isvalue('x', -1) + self.interp(textwrap.dedent(""" + x = 15 + try: + raise Exception() + x = 20 + except: + pass + """)) + self.isvalue('x', 15) + def test_tryelsefinally(self): self.interp(textwrap.dedent(""" @@ -816,14 +828,20 @@ self.interp('open("foo3", "rb", 2<<18)') self.check_error('RuntimeError') - def test_dos(self): + def test_recursionlimit(self): + self.interp("""def foo(): return foo()\nfoo()""") + if PY35Plus: + self.check_error('RecursionError') + else: + self.check_error('RuntimeError') + + def test_runtime(self): self.interp.max_time = 3 self.interp("""for x in range(2<<21): pass""") self.check_error('RuntimeError', 'time limit') self.interp("""while True: pass""") self.check_error('RuntimeError', 'time limit') - self.interp("""def foo(): return foo()\nfoo()""") - self.check_error('RecursionError' if PY35Plus else 'RuntimeError') + def test_kaboom(self): """ test Ned Batchelder's 'Eval really is dangerous' - Kaboom test (and related tests)""" @@ -905,6 +923,60 @@ assert_allclose(x2, 0.866025, rtol=0.001) assert_allclose(x3, 1.00, rtol=0.001) + def test_readonly_symbols(self): + + def foo(): + return 31 + + + usersyms = { + "a": 10, + "b": 11, + "c": 12, + "d": 13, + "foo": foo, + "bar": foo, + "x": 5, + "y": 7 + } + + aeval = Interpreter(usersyms=usersyms, readonly_symbols={"a", "b", "c", "d", "foo", "bar"}) + + aeval("a = 20") + aeval("def b(): return 100") + aeval("c += 1") + aeval("del d") + aeval("def foo(): return 55") + aeval("bar = None") + aeval("x = 21") + aeval("y += a") + + assert(aeval("a") == 10) + assert(aeval("b") == 11) + assert(aeval("c") == 12) + assert(aeval("d") == 13) + assert(aeval("foo()") == 31) + assert(aeval("bar()") == 31) + assert(aeval("x") == 21) + assert(aeval("y") == 17) + + + assert(aeval("abs(8)") == 8) + assert(aeval("abs(-8)") == 8) + aeval("def abs(x): return x*2") + assert(aeval("abs(8)") == 16) + assert(aeval("abs(-8)") == -16) + + aeval2 = Interpreter(builtins_readonly=True) + + assert(aeval2("abs(8)") == 8) + assert(aeval2("abs(-8)") == 8) + aeval2("def abs(x): return x*2") + assert(aeval2("abs(8)") == 8) + assert(aeval2("abs(-8)") == 8) + + + class TestCase2(unittest.TestCase):
