Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-asteval for openSUSE:Factory 
checked in at 2025-11-14 16:13:53
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-asteval (Old)
 and      /work/SRC/openSUSE:Factory/.python-asteval.new.2061 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-asteval"

Fri Nov 14 16:13:53 2025 rev:22 rq:1317640 version:1.0.7

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-asteval/python-asteval.changes    
2025-01-27 20:58:56.755763625 +0100
+++ /work/SRC/openSUSE:Factory/.python-asteval.new.2061/python-asteval.changes  
2025-11-14 16:14:08.815382415 +0100
@@ -1,0 +2,17 @@
+Thu Nov 13 14:25:13 UTC 2025 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to 1.0.7
+  * return in while, for, and with blocks in functions properly signal
+    an immediate exit of the function. (fixes #141)
+  * fix augassign to retain line numbers for exceptions properly. (#140)
+  * make sure that "unsafe_modules" should not be accessed even if imported
+    and exposed by other modules
+  * cleanup unused nodes
+  * tweaks and fixes to docs
+  * drop testing with Python 3.9
+  * add testing for Python 3.14
+  * update pyproject.toml from the endless churn from PyPA, to move the
+    location and formatting for the LICENSE, to continue compliance with
+    the endless churn from PyPA.
+
+-------------------------------------------------------------------

Old:
----
  asteval-1.0.6.tar.gz

New:
----
  asteval-1.0.7.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-asteval.spec ++++++
--- /var/tmp/diff_new_pack.iWuQ4X/_old  2025-11-14 16:14:13.715588088 +0100
+++ /var/tmp/diff_new_pack.iWuQ4X/_new  2025-11-14 16:14:13.715588088 +0100
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-asteval
-Version:        1.0.6
+Version:        1.0.7
 Release:        0
 Summary:        Safe, minimalistic evaluator of python expression using ast 
module
 License:        MIT

++++++ asteval-1.0.6.tar.gz -> asteval-1.0.7.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-1.0.6/.github/workflows/macos_numpy.yml 
new/asteval-1.0.7/.github/workflows/macos_numpy.yml
--- old/asteval-1.0.6/.github/workflows/macos_numpy.yml 2025-01-19 
22:38:23.000000000 +0100
+++ new/asteval-1.0.7/.github/workflows/macos_numpy.yml 2025-11-06 
22:41:41.000000000 +0100
@@ -8,7 +8,7 @@
     strategy:
       fail-fast: false
       matrix:
-        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
+        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
 
     steps:
     - uses: actions/checkout@v4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-1.0.6/.github/workflows/ubuntu_nonumpy.yml 
new/asteval-1.0.7/.github/workflows/ubuntu_nonumpy.yml
--- old/asteval-1.0.6/.github/workflows/ubuntu_nonumpy.yml      2025-01-19 
22:38:23.000000000 +0100
+++ new/asteval-1.0.7/.github/workflows/ubuntu_nonumpy.yml      2025-11-06 
22:41:41.000000000 +0100
@@ -13,7 +13,7 @@
     strategy:
       fail-fast: false
       matrix:
-        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
+        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
 
     steps:
     - uses: actions/checkout@v4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-1.0.6/.github/workflows/ubuntu_numpy.yml 
new/asteval-1.0.7/.github/workflows/ubuntu_numpy.yml
--- old/asteval-1.0.6/.github/workflows/ubuntu_numpy.yml        2025-01-19 
22:38:23.000000000 +0100
+++ new/asteval-1.0.7/.github/workflows/ubuntu_numpy.yml        2025-11-06 
22:41:41.000000000 +0100
@@ -13,7 +13,7 @@
     strategy:
       fail-fast: false
       matrix:
-        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
+        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
         with_financial: [0, 1]
 
     steps:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-1.0.6/.github/workflows/windows_numpy.yml 
new/asteval-1.0.7/.github/workflows/windows_numpy.yml
--- old/asteval-1.0.6/.github/workflows/windows_numpy.yml       2025-01-19 
22:38:23.000000000 +0100
+++ new/asteval-1.0.7/.github/workflows/windows_numpy.yml       2025-11-06 
22:41:41.000000000 +0100
@@ -8,7 +8,7 @@
     strategy:
       fail-fast: false
       matrix:
-        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
+        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
 
     steps:
     - uses: actions/checkout@v4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-1.0.6/PKG-INFO new/asteval-1.0.7/PKG-INFO
--- old/asteval-1.0.6/PKG-INFO  2025-01-19 22:43:44.722988600 +0100
+++ new/asteval-1.0.7/PKG-INFO  2025-11-06 22:41:52.521916200 +0100
@@ -1,45 +1,23 @@
-Metadata-Version: 2.2
+Metadata-Version: 2.4
 Name: asteval
-Version: 1.0.6
+Version: 1.0.7
 Summary: Safe, minimalistic evaluator of python expression using ast module
 Author-email: Matthew Newville <[email protected]>
-License: The MIT License
-        
-        Copyright (c) 2025 Matthew Newville, The University of Chicago
-        
-        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.
-        
+License-Expression: MIT
 Project-URL: Homepage,  https://github.com/lmfit/asteval
 Project-URL: Documentation, https://lmfit.github.io/asteval/
 Project-URL: Tracker, https://github.com/lmfit/asteval/issues
 Keywords: AST,expression evaluation,eval
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
 Classifier: Programming Language :: Python :: Implementation :: PyPy
-Requires-Python: >=3.9
+Requires-Python: >=3.10
 Description-Content-Type: text/x-rst
 License-File: LICENSE
 Provides-Extra: dev
@@ -53,6 +31,7 @@
 Requires-Dist: coverage; extra == "test"
 Provides-Extra: all
 Requires-Dist: asteval[dev,doc,test]; extra == "all"
+Dynamic: license-file
 
 ASTEVAL
 =======
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-1.0.6/asteval/asteval.py 
new/asteval-1.0.7/asteval/asteval.py
--- old/asteval-1.0.6/asteval/asteval.py        2025-01-19 22:38:23.000000000 
+0100
+++ new/asteval-1.0.7/asteval/asteval.py        2025-11-06 22:41:41.000000000 
+0100
@@ -48,15 +48,16 @@
                        ExceptionHolder, ReturnedNone, Empty, make_symbol_table,
                        numpy, op2func, safe_getattr, safe_format, 
valid_symbol_name, Procedure)
 
-ALL_NODES = ['arg', 'assert', 'assign', 'attribute', 'augassign', 'binop',
-             'boolop', 'break', 'bytes', 'call', 'compare', 'constant',
-             'continue', 'delete', 'dict', 'dictcomp', 'ellipsis',
-             'excepthandler', 'expr', 'extslice', 'for', 'functiondef', 'if',
-             'ifexp', 'import', 'importfrom', 'index', 'interrupt', 'list',
-             'listcomp', 'module', 'name', 'nameconstant', 'num', 'pass',
-             'raise', 'repr', 'return', 'set', 'setcomp', 'slice', 'str',
-             'subscript', 'try', 'tuple', 'unaryop', 'while', 'with',
-             'formattedvalue', 'joinedstr']
+ALL_NODES = ['arg', 'assert', 'assign', 'attribute', 'augassign',
+             'binop', 'boolop', 'break', 'call', 'compare',
+             'constant', 'continue', 'delete', 'dict', 'dictcomp',
+             'excepthandler', 'expr', 'extslice', 'for',
+             'functiondef', 'if', 'ifexp', 'import', 'importfrom',
+             'index', 'interrupt', 'list', 'listcomp', 'module',
+             'name', 'pass', 'raise', 'repr', 'return', 'set',
+             'setcomp', 'slice', 'subscript', 'try', 'tuple',
+             'unaryop', 'while', 'with', 'formattedvalue',
+             'joinedstr']
 
 
 MINIMAL_CONFIG = {'import': False, 'importfrom': False}
@@ -95,7 +96,7 @@
     minimal : bool
         create a minimal interpreter: disable many nodes (see Note 1).
     config : dict
-        dictionay listing which nodes to support (see note 2))
+        dictionary listing which nodes to support (see note 2))
 
     Notes
     -----
@@ -152,7 +153,6 @@
         self.lineno = 0
         self.code_text = []
         self.start_time = time.time()
-
         self.node_handlers = {}
         for node in ALL_NODES:
             handler = self.unimplemented
@@ -160,6 +160,8 @@
                 handler = getattr(self, f"on_{node}", self.unimplemented)
             self.node_handlers[node] = handler
 
+        self.allow_unsafe_modules = self.config.get('import', False)
+
         # to rationalize try/except try/finally
         if 'try' in self.node_handlers:
             self.node_handlers['tryexcept'] = self.node_handlers['try']
@@ -186,6 +188,8 @@
         out = None
         if node in self.node_handlers:
             out = self.node_handlers.pop(node)
+        if node == 'import':
+            self.allow_unsafe_modules = False
         return out
 
     def set_nodehandler(self, node, handler=None):
@@ -193,6 +197,8 @@
         if handler is None:
             handler = getattr(self, f"on_{node}", self.unimplemented)
         self.node_handlers[node] = handler
+        if node == 'import':
+            self.allow_unsafe_modules = True
         return handler
 
     def user_defined_symbols(self):
@@ -446,6 +452,7 @@
         self.retval = self.run(node.value)
         if self.retval is None:
             self.retval = ReturnedNone
+        self._interrupt = node
 
     def on_repr(self, node):
         """Repr."""
@@ -582,8 +589,8 @@
         sym = self.run(node.value)
         if ctx == ast.Del:
             return delattr(sym, node.attr)
-
-        return safe_getattr(sym, node.attr, self.raise_exception, node)
+        return safe_getattr(sym, node.attr, self.raise_exception, node,
+                            allow_unsafe_modules=self.allow_unsafe_modules)
 
 
     def on_assign(self, node):    # ('targets', 'value')
@@ -594,10 +601,18 @@
 
     def on_augassign(self, node):    # ('target', 'op', 'value')
         """Augmented assign."""
+        line_info = {
+            'lineno': node.lineno,
+            'col_offset': node.col_offset,
+            'end_lineno': node.end_lineno,
+            'end_col_offset': node.end_col_offset
+        }
         return self.on_assign(ast.Assign(targets=[node.target],
                                          value=ast.BinOp(left=node.target,
                                                          op=node.op,
-                                                         right=node.value)))
+                                                         right=node.value,
+                                                         **line_info),
+                                                         **line_info))
 
     def on_slice(self, node):    # ():('lower', 'upper', 'step')
         """Simple slice."""
@@ -721,7 +736,7 @@
                 self.run(tnode)
                 if self._interrupt is not None:
                     break
-            if isinstance(self._interrupt, ast.Break):
+            if isinstance(self._interrupt, (ast.Break, ast.Return)):
                 break
         else:
             for tnode in node.orelse:
@@ -737,7 +752,7 @@
                 self.run(tnode)
                 if self._interrupt is not None:
                     break
-            if isinstance(self._interrupt, ast.Break):
+            if isinstance(self._interrupt, (ast.Break, ast.Return)):
                 break
         else:
             for tnode in node.orelse:
@@ -761,11 +776,11 @@
             self.run(bnode)
             if self._interrupt is not None:
                 break
-
         for ctx in contexts:
             if hasattr(ctx, '__exit__'):
                 ctx.__exit__()
 
+
     def _comp_save_syms(self, node):
         """find and save symbols that will be used in a comprehension"""
         saved_syms = {}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-1.0.6/asteval/astutils.py 
new/asteval-1.0.7/asteval/astutils.py
--- old/asteval-1.0.6/asteval/astutils.py       2025-01-19 22:38:23.000000000 
+0100
+++ new/asteval-1.0.7/asteval/astutils.py       2025-11-06 22:41:41.000000000 
+0100
@@ -6,10 +6,13 @@
 """
 import ast
 import io
+import os
+import sys
+import ctypes
 import math
 import numbers
 import re
-from sys import exc_info
+
 from tokenize import ENCODING as tk_ENCODING
 from tokenize import NAME as tk_NAME
 from tokenize import tokenize as generate_tokens
@@ -73,6 +76,9 @@
 # unsafe attributes for particular objects, by type
 UNSAFE_ATTRS_DTYPES = {str: ('format', 'format_map')}
 
+# unsafe modules that may be exposed in other modules
+# but should be prevented from being accessed
+UNSAFE_MODULES = (io, os, sys, ctypes)
 
 # inherit these from python's __builtins__
 FROM_PY = ('ArithmeticError', 'AssertionError', 'AttributeError',
@@ -277,7 +283,7 @@
 
 # Safe version of getattr
 
-def safe_getattr(obj, attr, raise_exc, node):
+def safe_getattr(obj, attr, raise_exc, node, allow_unsafe_modules=False):
     """safe version of getattr"""
     unsafe = (attr in UNSAFE_ATTRS or
             (attr.startswith('__') and attr.endswith('__')))
@@ -286,6 +292,11 @@
             unsafe = (isinstance(obj, dtype) or obj is dtype) and attr in 
attrlist
             if unsafe:
                 break
+    if not unsafe and not allow_unsafe_modules:
+        for mod in UNSAFE_MODULES:
+            unsafe = obj is mod or getattr(obj, attr) is mod
+            if unsafe:
+                break
     if unsafe:
         msg = f"no safe attribute '{attr}' for {repr(obj)}"
         raise_exc(node, exc=AttributeError, msg=msg)
@@ -382,7 +393,7 @@
                 self.col_offset = node.col_offset
             except:
                 pass
-        self.exc_info = exc_info()
+        self.exc_info = sys.exc_info()
         if self.exc is None and self.exc_info[0] is not None:
             self.exc = self.exc_info[0]
         if self.msg == '' and self.exc_info[1] is not None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-1.0.6/asteval/version.py 
new/asteval-1.0.7/asteval/version.py
--- old/asteval-1.0.6/asteval/version.py        2025-01-19 22:43:44.000000000 
+0100
+++ new/asteval-1.0.7/asteval/version.py        2025-11-06 22:41:52.000000000 
+0100
@@ -1,16 +1,34 @@
-# file generated by setuptools_scm
+# file generated by setuptools-scm
 # don't change, don't track in version control
+
+__all__ = [
+    "__version__",
+    "__version_tuple__",
+    "version",
+    "version_tuple",
+    "__commit_id__",
+    "commit_id",
+]
+
 TYPE_CHECKING = False
 if TYPE_CHECKING:
-    from typing import Tuple, Union
+    from typing import Tuple
+    from typing import Union
+
     VERSION_TUPLE = Tuple[Union[int, str], ...]
+    COMMIT_ID = Union[str, None]
 else:
     VERSION_TUPLE = object
+    COMMIT_ID = object
 
 version: str
 __version__: str
 __version_tuple__: VERSION_TUPLE
 version_tuple: VERSION_TUPLE
+commit_id: COMMIT_ID
+__commit_id__: COMMIT_ID
+
+__version__ = version = '1.0.7'
+__version_tuple__ = version_tuple = (1, 0, 7)
 
-__version__ = version = '1.0.6'
-__version_tuple__ = version_tuple = (1, 0, 6)
+__commit_id__ = commit_id = 'gc9991033e'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-1.0.6/asteval.egg-info/PKG-INFO 
new/asteval-1.0.7/asteval.egg-info/PKG-INFO
--- old/asteval-1.0.6/asteval.egg-info/PKG-INFO 2025-01-19 22:43:44.000000000 
+0100
+++ new/asteval-1.0.7/asteval.egg-info/PKG-INFO 2025-11-06 22:41:52.000000000 
+0100
@@ -1,45 +1,23 @@
-Metadata-Version: 2.2
+Metadata-Version: 2.4
 Name: asteval
-Version: 1.0.6
+Version: 1.0.7
 Summary: Safe, minimalistic evaluator of python expression using ast module
 Author-email: Matthew Newville <[email protected]>
-License: The MIT License
-        
-        Copyright (c) 2025 Matthew Newville, The University of Chicago
-        
-        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.
-        
+License-Expression: MIT
 Project-URL: Homepage,  https://github.com/lmfit/asteval
 Project-URL: Documentation, https://lmfit.github.io/asteval/
 Project-URL: Tracker, https://github.com/lmfit/asteval/issues
 Keywords: AST,expression evaluation,eval
 Classifier: Development Status :: 5 - Production/Stable
 Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
 Classifier: Programming Language :: Python :: 3.11
 Classifier: Programming Language :: Python :: 3.12
 Classifier: Programming Language :: Python :: 3.13
+Classifier: Programming Language :: Python :: 3.14
 Classifier: Programming Language :: Python :: Implementation :: PyPy
-Requires-Python: >=3.9
+Requires-Python: >=3.10
 Description-Content-Type: text/x-rst
 License-File: LICENSE
 Provides-Extra: dev
@@ -53,6 +31,7 @@
 Requires-Dist: coverage; extra == "test"
 Provides-Extra: all
 Requires-Dist: asteval[dev,doc,test]; extra == "all"
+Dynamic: license-file
 
 ASTEVAL
 =======
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-1.0.6/doc/motivation.rst 
new/asteval-1.0.7/doc/motivation.rst
--- old/asteval-1.0.6/doc/motivation.rst        2025-01-19 22:38:23.000000000 
+0100
+++ new/asteval-1.0.7/doc/motivation.rst        2025-11-06 22:41:41.000000000 
+0100
@@ -40,7 +40,7 @@
 expression will be parsed correctly and converted into an Abstract Syntax Tree.
 Furthermore, the resulting AST is easy to walk through, greatly simplifying the
 evaluation process.  What started as a desire for a simple expression evaluator
-grew into a quite useable procedural domain-specific language for mathematical
+grew into a quite usable procedural domain-specific language for mathematical
 applications.
 
 Asteval makes no claims about speed. Evaluating the AST involves many
@@ -70,6 +70,8 @@
 evaluate user-supplied expressions, including `numexpr` and `sympy`
 use the builtin :py:func:`eval` as part of their processing.
 
+Prohibited Python statements and attributes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Some of the things not allowed in the asteval interpreter for safety reasons 
include:
 
@@ -107,21 +109,26 @@
 consider disabling the use of numpy, or take extra care to specify
 what numpy functions can be used.
 
-In 2024, an independent security audit of asteval done by Andrew Effenhauser,
-Ayman Hammad, and Daniel Crowley in the X-Force Security Research division of
-IBM showed insecurities with ``string.format``, so that access to this and
-``string.format_map`` method were removed.  In addition, this audit showed
-that the ``numpy`` submodules ``linalg``, ``fft``, and ``polynomial`` expose
-many exploitable objects, so these submodules were removed by default.  If
-needed, these modules can be added to any Interpreter either using the
-``user_symbols`` argument when creating it, or adding the needed symbols to the
-symbol table after the Interpreter is created.
+In 2024, an independent security audit of asteval done by Andrew
+Effenhauser, Ayman Hammad, and Daniel Crowley in the X-Force Security
+Research division of IBM showed insecurities with ``string.format``,
+so that access to this and ``string.format_map`` method were removed.
+In addition, this audit showed that the ``numpy`` submodules
+``linalg``, ``fft``, and ``polynomial`` expose many exploitable
+objects, so these submodules were removed by default.  If needed,
+these modules can be added to any Interpreter either using the
+``user_symbols`` argument when creating it, or adding the needed
+symbols to the symbol table after the Interpreter is created.
 
 In 2025, William Khem Marquez demonstrated two vulnerabilities: one
 from leaving some AST objects exposed within the interpreter for
 user-defined functions ("Procedures"), and one with f-string
 formatting.  Both of these were fixed for version 1.0.6.
 
+
+Avoiding resource hogging
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
 There are other categories of safety that asteval may attempt to
 address, but cannot guarantee success.  The most important of these is
 resource hogging, which might be used for a denial-of-service attack.
@@ -140,23 +147,24 @@
 that value of ``nmax`` almost certainly will, and can even crash the
 Python shell.
 
-As another example, and an illustration of the fundamental problem,
-consider the Python expression ``a = x**y**z``.  For values
-``x=y=z=5``, the run time will be well under 0.001 seconds.  For
-``x=y=z=8``, run time will still be under 1 sec.  Changing to ``x=8,
-y=9, z=9``, Python will ake several seconds (the value is :math:`\sim
-10^{350,000,000}`) With ``x=y=z=9``, executing that statement may take
-more than 1 hour on some machines.  It is not hard to come up with
+As another illustration of the fundamental challenge, consider the
+Python expression ``a = x**y**z``. With values ``x=y=z=5``, the run
+time will be well under 0.001 seconds.  Even with ``x=y=z=8``, run
+time will be under 1 sec.  Changing to ``x=8, y=9, z=9``, Python will
+take several seconds (the value is :math:`\sim 10^{350,000,000}`) With
+``x=y=z=9``, executing that statement may take more than 1 hour on
+some machines.  The result is that it is not hard to come up with
 short program that would run for hundreds of years, which probably
 exceeds everyones threshold for an acceptable run-time.  The point
-here is tha there simply is not a good way to predict how long any
-code will take to run from the text of the code itself: run time
-cannot be determined lexically.
+here is that there simply is not a good way to predict runtime for any
+code from the text of the code alone: run time cannot be determined
+lexically.
 
 To be clear, for the ``x**y**z`` exponentiation example, asteval will
 raise a runtime error, telling you that an exponent > 10,000 is not
 allowed.  Several other attempts are also made to prevent long-running
-operations or memory exhaustion.  These checks will prevent:
+operations or memory exhaustion.  These checks will prevent the
+following ways to hog resources:
 
   * statements longer than 50,000 bytes.
   * values of exponents (``p`` in ``x**p``) > 10,000.
@@ -165,11 +173,16 @@
   * more than 262144 open buffers
   * opening a file with a mode other than ``'r'``, ``'rb'``, or ``'ru'``.
 
-These checks happen at runtime, not by analyzing the text of the code.
-As with the example above using ``numpy.arange``, very large arrays
-and lists can be created that might approach memory limits.  There are
-countless other "clever ways" to have very long run times that cannot
-be readily predicted from the text of the code.
+These checks happen at runtime, not by analyzing the text of the code,
+but the values for these operations.  Still, as with the example above
+using ``numpy.arange``, very large arrays and lists can be created
+that can approach memory limits.  There are countless "clever ways" to
+have very long run times that cannot be readily predicted from the
+text of the code.
+
+
+File access
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 By default, the list of supported functions does include Python's
 ``open()`` -- in read-only mode -- which will allow disk access to the
@@ -183,18 +196,24 @@
 re-implement them, or ensure that your program cannot access
 information on disk that should be kept private.
 
-The exponential example also highlights the issue that there is not a good way
-to check for a long-running calculation within a single Python process.  That
-calculation is not stuck within the Python interpreter, but in C code (no doubt
-the ``pow()`` function) called by the Python interpreter itself.  That call
-will not return from the C library to the Python interpreter or allow other
-threads to run until that call is done.  That means that from within a single
-process, there is not a reliable way to tell asteval (or really, even Python)
-when a calculation has taken too long: Denial of Service is hard to detect
-before it happens, and even challenging to detect while it is happening.  The
-only reliable way to limit run time is at the level of the operating system,
-with a second process watching the execution time of the asteval process and
-either try to interrupt it or kill it.
+
+Monitoring Runtime and interrupting processes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+The exponential example also highlights the issue that there is not a
+good way to check for a long-running calculation within a single
+Python process.  That calculation is not stuck within the Python
+interpreter, but in C code (no doubt the ``pow()`` function) called by
+the Python interpreter itself.  That call will not return from the C
+library to the Python interpreter or allow other threads to run until
+that call is done.  That means that from within a single process,
+there is not a reliable way to tell asteval (or really, even Python)
+when a calculation has taken too long: Denial of Service is hard to
+detect before it happens, and even challenging to detect while it is
+happening.  The only reliable way to limit run time is at the level of
+the operating system, with a second process watching the execution
+time of the asteval process and either try to interrupt it 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-1.0.6/pyproject.toml 
new/asteval-1.0.7/pyproject.toml
--- old/asteval-1.0.6/pyproject.toml    2025-01-19 22:38:23.000000000 +0100
+++ new/asteval-1.0.7/pyproject.toml    2025-11-06 22:41:41.000000000 +0100
@@ -18,24 +18,24 @@
 [project]
 name = "asteval"
 dynamic = ["version"]
-requires-python = ">= 3.9"
+requires-python = ">= 3.10"
 description = "Safe, minimalistic evaluator of python expression using ast 
module"
 readme = "README.rst"
 authors = [
      {name = "Matthew Newville", email = "[email protected]"}
 ]
-license = {file = "LICENSE"}
+license = "MIT"
+license-files = ["LICENSE"]
 keywords = ["AST", "expression evaluation", "eval"]
 classifiers = [
     "Development Status :: 5 - Production/Stable",
     "Intended Audience :: Developers",
-    "License :: OSI Approved :: MIT License",
     "Operating System :: OS Independent",
-    "Programming Language :: Python :: 3.9",
     "Programming Language :: Python :: 3.10",
     "Programming Language :: Python :: 3.11",
     "Programming Language :: Python :: 3.12",
     "Programming Language :: Python :: 3.13",
+    "Programming Language :: Python :: 3.14",
     "Programming Language :: Python :: Implementation :: PyPy",
     ]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-1.0.6/tests/test_asteval.py 
new/asteval-1.0.7/tests/test_asteval.py
--- old/asteval-1.0.6/tests/test_asteval.py     2025-01-19 22:38:23.000000000 
+0100
+++ new/asteval-1.0.7/tests/test_asteval.py     2025-11-06 22:41:41.000000000 
+0100
@@ -89,7 +89,6 @@
         if chk_type:
             assert False
 
-
 def test_py3():
     assert version_info.major > 2
 
@@ -323,6 +322,39 @@
     isvalue(interp, 'n', 7)
 
 @pytest.mark.parametrize("nested", [False, True])
+def test_while_return(nested):
+    interp = make_interpreter(nested_symtable=nested)
+    interp(textwrap.dedent("""
+            def func_while(nmax=10):
+                n = 0
+                while n < nmax:
+                    n += 1
+                    if n > 6:
+                        return 99
+                return n
+            o1 = func_while(3)
+            o2 = func_while(12)
+            """))
+    isvalue(interp, 'o1', 3)
+    isvalue(interp, 'o2', 99)
+
[email protected]("nested", [False, True])
+def test_for_return(nested):
+    interp = make_interpreter(nested_symtable=nested)
+    interp(textwrap.dedent("""
+            def func_for(nmax=10):
+                for n in range(nmax):
+                    if n > 10:
+                        return -2
+                return n
+            o1 = func_for(7)
+            o2 = func_for(99)
+            """))
+    isvalue(interp, 'o1', 6)
+    isvalue(interp, 'o2', -2)
+
+
[email protected]("nested", [False, True])
 def test_with(nested):
     "test with"
     interp = make_interpreter(nested_symtable=nested)
@@ -1586,7 +1618,7 @@
     etype, fullmsg = error.get_error()
     assert 'no safe attribute' in error.msg
     assert etype == 'AttributeError'
-    
+
 @pytest.mark.parametrize("nested", [False, True])
 def test_unsafe_format_string_access(nested):
     """
@@ -1602,7 +1634,7 @@
     etype, fullmsg = error.get_error()
     assert 'no safe attribute' in error.msg
     assert etype == 'AttributeError'
-    
+
 @pytest.mark.parametrize("nested", [False, True])
 def test_unsafe_attr_dtypes(nested):
     """
@@ -1617,12 +1649,12 @@
     etype, fullmsg = error.get_error()
     assert 'no safe attribute' in error.msg
     assert etype == 'AttributeError'
-    
+
     interp = make_interpreter(nested_symtable=nested)
     interp(textwrap.dedent("""
             str.format('{0}', dict)
      """),  raise_errors=False)
-    
+
     error = interp.error[0]
     etype, fullmsg = error.get_error()
     assert 'no safe attribute' in error.msg
@@ -1645,5 +1677,17 @@
     assert 'unsupported operand' in out
     assert len(interp.error) == 0
 
[email protected]("nested", [False, True])
+def test_augassign_lineno(nested):
+    """test lineno on augassign operation"""
+    interp = make_interpreter(nested_symtable=nested)
+
+    interp(textwrap.dedent("""
+    x = 1
+    x /= 0
+    """))
+    check_error(interp, 'ZeroDivisionError', 'x /= 0')
+    assert interp.error[0].lineno == 3
+
 if __name__ == '__main__':
     pytest.main(['-v', '-x', '-s'])

Reply via email to