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 2021-02-18 20:40:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-asteval (Old)
 and      /work/SRC/openSUSE:Factory/.python-asteval.new.28504 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-asteval"

Thu Feb 18 20:40:32 2021 rev:9 rq:873194 version:0.9.22

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-asteval/python-asteval.changes    
2020-01-18 12:18:30.887151253 +0100
+++ /work/SRC/openSUSE:Factory/.python-asteval.new.28504/python-asteval.changes 
2021-02-18 20:52:39.943453745 +0100
@@ -1,0 +2,8 @@
+Wed Feb 17 11:57:46 UTC 2021 - Ben Greiner <[email protected]>
+
+- Update to 0.9.22
+  * another important but small fix for Python 3.9
+  * Merge branch 'nested_interrupts_returns'
+- Drop hard numpy requirement, don't test on python36
+
+-------------------------------------------------------------------

Old:
----
  asteval-0.9.18.tar.gz

New:
----
  asteval-0.9.22.tar.gz

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

Other differences:
------------------
++++++ python-asteval.spec ++++++
--- /var/tmp/diff_new_pack.85wBqX/_old  2021-02-18 20:52:40.583454346 +0100
+++ /var/tmp/diff_new_pack.85wBqX/_new  2021-02-18 20:52:40.587454350 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-asteval
 #
-# Copyright (c) 2020 SUSE LLC
+# Copyright (c) 2021 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,10 +16,10 @@
 #
 
 
+%{?!python_module:%define python_module() python3-%{**}}
 %define skip_python2 1
-%{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-asteval
-Version:        0.9.18
+Version:        0.9.22
 Release:        0
 Summary:        Safe, minimalistic evaluator of python expression using ast 
module
 License:        MIT
@@ -29,13 +29,10 @@
 BuildRequires:  %{python_module setuptools}
 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}
+BuildRequires:  %{python_module numpy if (%python-base without python36-base)}
 # /SECTION
 %python_subpackages
 

++++++ asteval-0.9.18.tar.gz -> asteval-0.9.22.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/.gitattributes 
new/asteval-0.9.22/.gitattributes
--- old/asteval-0.9.18/.gitattributes   1970-01-01 01:00:00.000000000 +0100
+++ new/asteval-0.9.22/.gitattributes   2021-02-11 22:05:29.000000000 +0100
@@ -0,0 +1 @@
+asteval/_version.py export-subst
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/.gitignore 
new/asteval-0.9.22/.gitignore
--- old/asteval-0.9.18/.gitignore       1970-01-01 01:00:00.000000000 +0100
+++ new/asteval-0.9.22/.gitignore       2021-02-11 22:05:29.000000000 +0100
@@ -0,0 +1,12 @@
+*.pyc
+*~
+*#
+.coverage
+NonGit/
+doc/_build
+doc/*.pdf
+build
+dist
+*.egg-info
+
+MANIFEST
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/INSTALL new/asteval-0.9.22/INSTALL
--- old/asteval-0.9.18/INSTALL  2019-12-17 18:36:32.000000000 +0100
+++ new/asteval-0.9.22/INSTALL  2021-02-11 22:05:29.000000000 +0100
@@ -4,13 +4,12 @@
 To install the asteval module, use::
    python setup.py install
 
-or 
+or
    pip install asteval
 
 Asteval require Python 3.5 or higher.
-If installed, many functions and constants from numpy 
+If installed, many functions and constants from numpy
 will be used by default.
 
 Matt Newville <[email protected]>
 Last Update:  14-Nov-2019
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/LICENSE new/asteval-0.9.22/LICENSE
--- old/asteval-0.9.18/LICENSE  2019-12-17 18:36:32.000000000 +0100
+++ new/asteval-0.9.22/LICENSE  2021-02-11 22:05:29.000000000 +0100
@@ -1,6 +1,6 @@
 The MIT License
 
-Copyright (c) 2019 Matthew Newville, The University of Chicago
+Copyright (c) 2021 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
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/MANIFEST.in 
new/asteval-0.9.22/MANIFEST.in
--- old/asteval-0.9.18/MANIFEST.in      2019-12-17 18:36:32.000000000 +0100
+++ new/asteval-0.9.22/MANIFEST.in      2021-02-11 22:05:29.000000000 +0100
@@ -1,8 +1,8 @@
-include README.txt INSTALL LICENSE MANIFEST.in PKG-INFO 
+include README.txt INSTALL LICENSE MANIFEST.in PKG-INFO
 include setup.py publish_docs.sh
 exclude *.pyc core.* *~ *.pdf
 recursive-include lib *.py
-recursive-include tests *.py 
+recursive-include tests *.py
 recursive-include doc *
 recursive-exclude doc/_build *
 recursive-exclude doc *.pdf
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/PKG-INFO new/asteval-0.9.22/PKG-INFO
--- old/asteval-0.9.18/PKG-INFO 2019-12-17 18:36:53.000000000 +0100
+++ new/asteval-0.9.22/PKG-INFO 2021-02-11 22:05:48.076786500 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: asteval
-Version: 0.9.18
+Version: 0.9.22
 Summary: Safe, minimalistic evaluator of python expression using ast module
 Home-page: http://github.com/newville/asteval
 Author: Matthew Newville
@@ -22,4 +22,4 @@
 Classifier: Intended Audience :: Science/Research
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
-Requires-Python: >=3.5
+Requires-Python: >=3.6
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/README.rst 
new/asteval-0.9.22/README.rst
--- old/asteval-0.9.18/README.rst       2019-12-17 18:36:32.000000000 +0100
+++ new/asteval-0.9.22/README.rst       2021-02-11 22:05:29.000000000 +0100
@@ -7,6 +7,12 @@
 .. image:: https://codecov.io/gh/newville/asteval/branch/master/graph/badge.svg
    :target: https://codecov.io/gh/newville/asteval
 
+.. image:: https://img.shields.io/pypi/v/asteval.svg
+   :target: https://pypi.org/project/asteval
+
+.. image:: https://img.shields.io/pypi/dm/asteval.svg
+   :target: https://pypi.org/project/asteval
+
 .. image:: https://zenodo.org/badge/4185/newville/asteval.svg
    :target: https://zenodo.org/badge/latestdoi/4185/newville/asteval
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/asteval/__init__.py 
new/asteval-0.9.22/asteval/__init__.py
--- old/asteval-0.9.18/asteval/__init__.py      2019-12-17 18:36:32.000000000 
+0100
+++ new/asteval-0.9.22/asteval/__init__.py      2021-02-11 22:05:29.000000000 
+0100
@@ -17,10 +17,10 @@
             The University of Chicago
 """
 
-from .asteval import Interpreter
-from .astutils import (NameFinder, valid_symbol_name, make_symbol_table,
-                       get_ast_names)
 from ._version import get_versions
+from .asteval import Interpreter
+from .astutils import (NameFinder, get_ast_names, make_symbol_table,
+                       valid_symbol_name)
 
 __all__ = ['Interpreter', 'NameFinder', 'valid_symbol_name',
            'make_symbol_table', 'get_ast_names']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/asteval/_version.py 
new/asteval-0.9.22/asteval/_version.py
--- old/asteval-0.9.18/asteval/_version.py      2019-12-17 18:36:53.000000000 
+0100
+++ new/asteval-0.9.22/asteval/_version.py      2021-02-11 22:05:48.076786500 
+0100
@@ -8,11 +8,11 @@
 
 version_json = '''
 {
- "date": "2019-12-17T11:34:21-0600",
+ "date": "2021-02-11T14:59:23-0600",
  "dirty": false,
  "error": null,
- "full-revisionid": "2f796e3560c0e51df52ce8ca8062f2c379452107",
- "version": "0.9.18"
+ "full-revisionid": "3312602c567038e6430b9680075431ab3814b199",
+ "version": "0.9.22"
 }
 '''  # END VERSION_JSON
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/asteval/asteval.py 
new/asteval-0.9.22/asteval/asteval.py
--- old/asteval-0.9.18/asteval/asteval.py       2019-12-17 18:36:32.000000000 
+0100
+++ new/asteval-0.9.22/asteval/asteval.py       2021-02-11 22:05:29.000000000 
+0100
@@ -17,7 +17,7 @@
 in the symbol table.
 
 The result is a restricted, simplified version of Python meant for
-numerical caclulations that is somewhat safer than 'eval' because many
+numerical calculations that is somewhat safer than 'eval' because many
 unsafe operations (such as 'import' and 'eval') are simply not allowed.
 
 Many parts of Python syntax are supported, including:
@@ -37,20 +37,12 @@
 'getattr' for example)
 """
 import ast
-import time
 import inspect
-from sys import exc_info, stdout, stderr, version_info
+import time
+from sys import exc_info, stderr, stdout
 
-from .astutils import (UNSAFE_ATTRS, HAS_NUMPY, make_symbol_table, numpy,
-                       op2func, ExceptionHolder, ReturnedNone,
-                       valid_symbol_name)
-
-if version_info[0] < 3 or version_info[1] < 5:
-    raise SystemError("Python 3.5 or higher required")
-
-builtins = __builtins__
-if not isinstance(builtins, dict):
-    builtins = builtins.__dict__
+from .astutils import (HAS_NUMPY, UNSAFE_ATTRS, ExceptionHolder, ReturnedNone,
+                       make_symbol_table, numpy, op2func, valid_symbol_name)
 
 ALL_NODES = ['arg', 'assert', 'assign', 'attribute', 'augassign', 'binop',
              'boolop', 'break', 'call', 'compare', 'continue', 'delete',
@@ -60,7 +52,8 @@
              'pass', 'raise', 'repr', 'return', 'slice', 'str',
              'subscript', 'try', 'tuple', 'unaryop', 'while', 'constant']
 
-class Interpreter(object):
+
+class Interpreter:
     """create an asteval Interpreter: a restricted, simplified interpreter
     of mathematical expressions using Python syntax.
 
@@ -93,7 +86,7 @@
     no_listcomp : bool
         whether to support list comprehension.
     no_augassign : bool
-        whether to support augemented assigments (`a += 1`, etc).
+        whether to support augemented assignments (`a += 1`, etc).
     no_assert : bool
         whether to support `assert`.
     no_delete : bool
@@ -203,7 +196,6 @@
         """set node handler"""
         self.node_handlers[node] = handler
 
-
     def user_defined_symbols(self):
         """Return a set of symbols that have been added to symtable after
         construction.
@@ -238,7 +230,7 @@
         if len(self.error) > 0 and not isinstance(node, ast.Module):
             msg = '%s' % msg
         err = ExceptionHolder(node, exc=exc, msg=msg, expr=expr, lineno=lineno)
-        self._interrupt = ast.Break()
+        self._interrupt = ast.Raise()
         self.error.append(err)
         if self.error_msg is None:
             self.error_msg = "at expr='%s'" % (self.expr)
@@ -274,6 +266,10 @@
         out = None
         if len(self.error) > 0:
             return out
+        if self.retval is not None:
+            return self.retval
+        if isinstance(self._interrupt, (ast.Break, ast.Continue)):
+            return self._interrupt
         if node is None:
             return out
         if isinstance(node, str):
@@ -300,7 +296,7 @@
         except:
             if with_raise:
                 if len(self.error) == 0:
-                    # Unhandled exception that didn't go through 
raise_exception
+                    # Unhandled exception that didn't use raise_exception
                     self.raise_exception(node, expr=expr)
                 raise
 
@@ -357,7 +353,7 @@
         return self.run(node.value)  # ('value',)
 
     def on_return(self, node):  # ('value',)
-        """Return statement: look for None, return special sentinal."""
+        """Return statement: look for None, return special sentinel."""
         self.retval = self.run(node.value)
         if self.retval is None:
             self.retval = ReturnedNone
@@ -376,7 +372,7 @@
 
     def on_expression(self, node):
         "basic expression"
-        return self.on_module(node) # ():('body',)
+        return self.on_module(node)  # ():('body',)
 
     def on_pass(self, node):
         """Pass statement."""
@@ -403,7 +399,8 @@
     def on_assert(self, node):    # ('test', 'msg')
         """Assert statement."""
         if not self.run(node.test):
-            self.raise_exception(node, exc=AssertionError, msg=node.msg)
+            msg = node.msg.s if node.msg else ""
+            self.raise_exception(node, exc=AssertionError, msg=msg)
         return True
 
     def on_list(self, node):    # ('elt', 'ctx')
@@ -416,8 +413,8 @@
 
     def on_dict(self, node):    # ('keys', 'values')
         """Dictionary."""
-        return dict([(self.run(k), self.run(v)) for k, v in
-                     zip(node.keys, node.values)])
+        return {self.run(k): self.run(v) for k, v in
+                zip(node.keys, node.values)}
 
     def on_constant(self, node):   # ('value', 'kind')
         """Return constant value."""
@@ -431,10 +428,6 @@
         """Return string."""
         return node.s
 
-    def on_nameconstant(self, node):   # ('value',)
-        """named constant"""
-        return node.value
-
     def on_name(self, node):    # ('id', 'ctx')
         """Name node."""
         ctx = node.ctx.__class__
@@ -448,7 +441,7 @@
                 self.raise_exception(node, exc=NameError, msg=msg)
 
     def on_nameconstant(self, node):
-        """ True, False, None in python >= 3.4 """
+        """True, False, or None"""
         return node.value
 
     def node_assign(self, node, val):
@@ -459,7 +452,8 @@
 
         """
         if node.__class__ == ast.Name:
-            if not valid_symbol_name(node.id) or node.id in 
self.readonly_symbols:
+            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
@@ -474,14 +468,8 @@
             setattr(self.run(node.value), node.attr, val)
 
         elif node.__class__ == ast.Subscript:
-            sym = self.run(node.value)
-            xslice = self.run(node.slice)
-            if isinstance(node.slice, ast.Index):
-                sym[xslice] = val
-            elif isinstance(node.slice, ast.Slice):
-                sym[slice(xslice.start, xslice.stop)] = val
-            elif isinstance(node.slice, ast.ExtSlice):
-                sym[xslice] = val
+            self.run(node.value)[self.run(node.slice)] = val
+
         elif node.__class__ in (ast.Tuple, ast.List):
             if len(val) == len(node.elts):
                 for telem, tval in zip(node.elts, val):
@@ -501,7 +489,7 @@
             return delattr(sym, node.attr)
 
         # ctx is ast.Load
-        fmt = "cannnot access attribute '%s' for %s"
+        fmt = "cannot access attribute '%s' for %s"
         if node.attr not in UNSAFE_ATTRS:
             fmt = "no attribute '%s' for %s"
             try:
@@ -544,10 +532,7 @@
         nslice = self.run(node.slice)
         ctx = node.ctx.__class__
         if ctx in (ast.Load, ast.Store):
-            if isinstance(node.slice, (ast.Index, ast.Slice, ast.Ellipsis)):
-                return val.__getitem__(nslice)
-            elif isinstance(node.slice, ast.ExtSlice):
-                return val[nslice]
+            return val[nslice]
         else:
             msg = "subscript with unknown context"
             self.raise_exception(node, msg=msg)
@@ -561,8 +546,8 @@
             while tnode.__class__ == ast.Attribute:
                 children.append(tnode.attr)
                 tnode = tnode.value
-
-            if tnode.__class__ == ast.Name and tnode.id not in 
self.readonly_symbols:
+            if (tnode.__class__ == ast.Name and
+                    tnode.id not in self.readonly_symbols):
                 children.append(tnode.id)
                 children.reverse()
                 self.symtable.pop('.'.join(children))
@@ -598,7 +583,8 @@
             rval = self.run(rnode)
             ret = op2func(op)(lval, rval)
             results.append(ret)
-            if (self.use_numpy and not isinstance(ret, numpy.ndarray)) and not 
ret:
+            if ((self.use_numpy and not isinstance(ret, numpy.ndarray)) and
+                    not ret):
                 break
             lval = rval
         if len(results) == 1:
@@ -697,7 +683,7 @@
                 for hnd in node.handlers:
                     htype = None
                     if hnd.type is not None:
-                        htype = builtins.get(hnd.type.id, None)
+                        htype = __builtins__.get(hnd.type.id, None)
                     if htype is None or isinstance(e_type(), htype):
                         self.error = []
                         if hnd.name is not None:
@@ -741,14 +727,21 @@
         keywords = {}
         if func == print:
             keywords['file'] = self.writer
-
         for key in node.keywords:
             if not isinstance(key, ast.keyword):
                 msg = "keyword error in function call '%s'" % (func)
                 self.raise_exception(node, msg=msg)
-            keywords[key.arg] = self.run(key.value)
+            if key.arg is None:
+                keywords.update(self.run(key.value))
+            elif key.arg in keywords:
+                self.raise_exception(node,
+                                     msg="keyword argument repeated: %s" % 
key.arg,
+                                     exc=SyntaxError)
+            else:
+                keywords[key.arg] = self.run(key.value)
 
         kwargs = getattr(node, 'kwargs', None)
+
         if kwargs is not None:
             keywords.update(self.run(kwargs))
 
@@ -771,7 +764,8 @@
             raise Warning("decorated procedures not supported!")
         kwargs = []
 
-        if not valid_symbol_name(node.name) or node.name in 
self.readonly_symbols:
+        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)
 
@@ -803,7 +797,7 @@
             self.no_deepcopy.remove(node.name)
 
 
-class Procedure(object):
+class Procedure:
     """Procedure: user-defined function for asteval.
 
     This stores the parsed ast nodes as from the 'functiondef' ast node
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/asteval/astutils.py 
new/asteval-0.9.22/asteval/astutils.py
--- old/asteval-0.9.18/asteval/astutils.py      2019-12-17 18:36:32.000000000 
+0100
+++ new/asteval-0.9.22/asteval/astutils.py      2021-02-11 22:05:29.000000000 
+0100
@@ -4,15 +4,15 @@
    Matthew Newville <[email protected]>,
    The University of Chicago
 """
-import io
-import re
 import ast
+import io
 import math
 import numbers
+import re
 from sys import exc_info
-from tokenize import (tokenize as generate_tokens,
-                      ENCODING as tk_ENCODING,
-                      NAME as tk_NAME)
+from tokenize import ENCODING as tk_ENCODING
+from tokenize import NAME as tk_NAME
+from tokenize import tokenize as generate_tokens
 
 HAS_NUMPY = False
 numpy = None
@@ -20,6 +20,7 @@
     import numpy
     ndarr = numpy.ndarray
     HAS_NUMPY = True
+    numpy_version = numpy.version.version.split('.', 2)
 except ImportError:
     pass
 
@@ -159,14 +160,15 @@
                  'arctanh', 'acosh': 'arccosh', 'asinh': 'arcsinh'}
 
 
-def _open(filename, mode='r', buffering=0):
+def _open(filename, mode='r', buffering=-1):
     """read only version of open()"""
     if mode not in ('r', 'rb', 'rU'):
         raise RuntimeError("Invalid open file mode, must be 'r', 'rb', or 
'rU'")
     if buffering > MAX_OPEN_BUFFER:
-        raise RuntimeError("Invalid buffering value, max buffer size is 
{}".format(MAX_OPEN_BUFFER))
+        raise RuntimeError(f"Invalid buffering value, max buffer size is 
{MAX_OPEN_BUFFER}")
     return open(filename, mode, buffering)
 
+
 def _type(obj, *varargs, **varkws):
     """type that prevents varargs and varkws"""
     return type(obj).__name__
@@ -181,25 +183,25 @@
     """safe version of pow"""
     if isinstance(exp, numbers.Number):
         if exp > MAX_EXPONENT:
-            raise RuntimeError("Invalid exponent, max exponent is 
{}".format(MAX_EXPONENT))
+            raise RuntimeError(f"Invalid exponent, max exponent is 
{MAX_EXPONENT}")
     elif HAS_NUMPY:
         if isinstance(exp, numpy.ndarray):
             if numpy.nanmax(exp) > MAX_EXPONENT:
-                raise RuntimeError("Invalid exponent, max exponent is 
{}".format(MAX_EXPONENT))
+                raise RuntimeError(f"Invalid exponent, max exponent is 
{MAX_EXPONENT}")
     return base ** exp
 
 
 def safe_mult(a, b):
     """safe version of multiply"""
     if isinstance(a, str) and isinstance(b, int) and len(a) * b > MAX_STR_LEN:
-        raise RuntimeError("String length exceeded, max string length is 
{}".format(MAX_STR_LEN))
+        raise RuntimeError(f"String length exceeded, max string length is 
{MAX_STR_LEN}")
     return a * b
 
 
 def safe_add(a, b):
     """safe version of add"""
     if isinstance(a, str) and isinstance(b, str) and len(a) + len(b) > 
MAX_STR_LEN:
-        raise RuntimeError("String length exceeded, max string length is 
{}".format(MAX_STR_LEN))
+        raise RuntimeError(f"String length exceeded, max string length is 
{MAX_STR_LEN}")
     return a + b
 
 
@@ -207,11 +209,11 @@
     """safe version of lshift"""
     if isinstance(b, numbers.Number):
         if b > MAX_SHIFT:
-            raise RuntimeError("Invalid left shift, max left shift is 
{}".format(MAX_SHIFT))
+            raise RuntimeError(f"Invalid left shift, max left shift is 
{MAX_SHIFT}")
     elif HAS_NUMPY:
         if isinstance(b, numpy.ndarray):
             if numpy.nanmax(b) > MAX_SHIFT:
-                raise RuntimeError("Invalid left shift, max left shift is 
{}".format(MAX_SHIFT))
+                raise RuntimeError(f"Invalid left shift, max left shift is 
{MAX_SHIFT}")
     return a << b
 
 
@@ -291,7 +293,7 @@
 ReturnedNone = Empty()
 
 
-class ExceptionHolder(object):
+class ExceptionHolder:
     """Basic exception handler."""
 
     def __init__(self, node, exc=None, msg='', expr=None, lineno=None):
@@ -344,10 +346,12 @@
                 self.names.append(node.id)
         ast.NodeVisitor.generic_visit(self, node)
 
+
 builtins = __builtins__
 if not isinstance(builtins, dict):
     builtins = builtins.__dict__
 
+
 def get_ast_names(astnode):
     """Return symbol Names from an AST node."""
     finder = NameFinder()
@@ -382,14 +386,20 @@
             symtable[sym] = getattr(math, sym)
 
     if HAS_NUMPY and use_numpy:
+        # aliases deprecated in NumPy v1.20.0
+        deprecated = ['str', 'bool', 'int', 'float', 'complex', 'pv', 'rate',
+                      'pmt', 'ppmt', 'npv', 'nper', 'long', 'mirr', 'fv',
+                      'irr', 'ipmt']
         for sym in FROM_NUMPY:
+            if (int(numpy_version[0]) == 1 and int(numpy_version[1]) >= 20 and
+                    sym in deprecated):
+                continue
             if hasattr(numpy, sym):
                 symtable[sym] = getattr(numpy, sym)
         for name, sym in NUMPY_RENAMES.items():
             if hasattr(numpy, sym):
                 symtable[name] = getattr(numpy, sym)
 
-
     symtable.update(LOCALFUNCS)
     symtable.update(kws)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/asteval.egg-info/PKG-INFO 
new/asteval-0.9.22/asteval.egg-info/PKG-INFO
--- old/asteval-0.9.18/asteval.egg-info/PKG-INFO        2019-12-17 
18:36:52.000000000 +0100
+++ new/asteval-0.9.22/asteval.egg-info/PKG-INFO        2021-02-11 
22:05:48.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 1.2
 Name: asteval
-Version: 0.9.18
+Version: 0.9.22
 Summary: Safe, minimalistic evaluator of python expression using ast module
 Home-page: http://github.com/newville/asteval
 Author: Matthew Newville
@@ -22,4 +22,4 @@
 Classifier: Intended Audience :: Science/Research
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
-Requires-Python: >=3.5
+Requires-Python: >=3.6
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/asteval.egg-info/SOURCES.txt 
new/asteval-0.9.22/asteval.egg-info/SOURCES.txt
--- old/asteval-0.9.18/asteval.egg-info/SOURCES.txt     2019-12-17 
18:36:52.000000000 +0100
+++ new/asteval-0.9.22/asteval.egg-info/SOURCES.txt     2021-02-11 
22:05:48.000000000 +0100
@@ -1,7 +1,11 @@
+.gitattributes
+.gitignore
 INSTALL
 LICENSE
 MANIFEST.in
 README.rst
+azure-pipelines.yml
+requirements.txt
 setup.cfg
 setup.py
 versioneer.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/azure-pipelines.yml 
new/asteval-0.9.22/azure-pipelines.yml
--- old/asteval-0.9.18/azure-pipelines.yml      1970-01-01 01:00:00.000000000 
+0100
+++ new/asteval-0.9.22/azure-pipelines.yml      2021-02-11 22:05:29.000000000 
+0100
@@ -0,0 +1,39 @@
+# Python package
+# Create and test a Python package on multiple Python versions.
+# Add steps that analyze code, save the dist with the build record, publish to 
a PyPI-compatible index, and more:
+# https://docs.microsoft.com/azure/devops/pipelines/languages/python
+
+trigger:
+- master
+
+pool:
+  vmImage: 'ubuntu-latest'
+strategy:
+  matrix:
+    Python36:
+      python.version: '3.6'
+    Python37:
+      python.version: '3.7'
+    Python38:
+      python.version: '3.8'
+    Python39:
+      python.version: '3.9'
+
+steps:
+- task: UsePythonVersion@0
+  inputs:
+    versionSpec: '$(python.version)'
+  displayName: 'Use Python $(python.version)'
+
+- script: |
+    python -m pip install --upgrade pip
+    pip install numpy codecov coverage pytest pytest-azurepipelines
+  displayName: 'Install dependencies'
+
+- script: |
+    python setup.py install
+    cd tests
+    coverage run --source=asteval -m pytest
+    coverage report -m
+    bash <(curl -s https://codecov.io/bash)
+  displayName: 'Install asteval, run test suite and measure coverage'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/doc/_templates/indexsidebar.html 
new/asteval-0.9.22/doc/_templates/indexsidebar.html
--- old/asteval-0.9.18/doc/_templates/indexsidebar.html 2019-12-17 
18:36:32.000000000 +0100
+++ new/asteval-0.9.22/doc/_templates/indexsidebar.html 2021-02-11 
22:05:29.000000000 +0100
@@ -9,6 +9,3 @@
 Development version: <br> &nbsp; &nbsp; <a 
href="https://github.com/newville/asteval/";>github.com</a>
 
 <hr>
-
-
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/doc/api.rst 
new/asteval-0.9.22/doc/api.rst
--- old/asteval-0.9.18/doc/api.rst      2019-12-17 18:36:32.000000000 +0100
+++ new/asteval-0.9.22/doc/api.rst      2021-02-11 22:05:29.000000000 +0100
@@ -8,7 +8,6 @@
 
 .. module:: asteval
 
-
 The asteval module has a pretty simple interface, providing an
 :class:`Interpreter` class which creates an Interpreter of expressions and
 code.  There are a few options available to control what language features
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/doc/conf.py 
new/asteval-0.9.22/doc/conf.py
--- old/asteval-0.9.18/doc/conf.py      2019-12-17 18:36:32.000000000 +0100
+++ new/asteval-0.9.22/doc/conf.py      2021-02-11 22:05:29.000000000 +0100
@@ -11,6 +11,7 @@
 # serve to show the default.
 
 import sys, os
+from datetime import date
 
 # If extensions (or modules to document with autodoc) are in another directory,
 # add these directories to sys.path here. If the directory is relative to the
@@ -27,7 +28,7 @@
               'sphinx.ext.coverage',
               'sphinx.ext.mathjax', 'sphinx.ext.intersphinx']
 
-intersphinx_mapping = {'py': ('http://docs.python.org/', None)}
+intersphinx_mapping = {'py': ('https://docs.python.org/3/', None)}
 
 # Add any paths that contain templates here, relative to this directory.
 templates_path = ['_templates']
@@ -43,7 +44,7 @@
 
 # General information about the project.
 project = u'asteval'
-copyright = u'2014, Matthew Newville, The University of Chicago'
+copyright = u'{}, Matthew Newville, The University of 
Chicago'.format(date.today().year)
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
@@ -51,7 +52,7 @@
 #
 # The short X.Y version.
 import asteval
-release = asteval.__version__
+release = asteval.__version__.split('+', 1)[0]
 
 
 # The language for content autogenerated by Sphinx. Refer to documentation
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/doc/index.rst 
new/asteval-0.9.22/doc/index.rst
--- old/asteval-0.9.18/doc/index.rst    2019-12-17 18:36:32.000000000 +0100
+++ new/asteval-0.9.22/doc/index.rst    2021-02-11 22:05:29.000000000 +0100
@@ -5,52 +5,54 @@
 
 .. _numpy: http://docs.scipy.org/doc/numpy
 
-The asteval package evaluates mathematical expressions and statements,
-providing a safer alternative to Python's builtin :py:func:`eval` and a
-richer, easier to use alternative to :py:func:`ast.literal_eval`.  It does
-this by building an embedded interpreter for a subset of the Python
-language using Python's :py:mod:`ast` module.  The emphasis here and main
-area of application is the evaluation of mathematical expressions. Because
-of this, mathematical functions from Python's :py:mod:`math` module are
-available, and a large number of functions from `numpy`_ will be available
-if `numpy`_ is installed on your system.
-
-While the emphasis is on basic mathematical expressions, many features of the
-Python language are supported by default.  These features include array
-slicing and subscripting, if-then-else conditionals, while loops, for loops,
-try-except blocks, list comprehension, and user-defined functions.  All
-objects in the asteval interpreter are truly python objects, and all basic
-built-in data structures (strings, dictionaries, tuple, lists, numpy arrays)
-are supported.
+The asteval package evaluates Python expressions and statements, providing
+a safer alternative to Python's builtin :py:func:`eval` and a richer,
+easier to use alternative to :py:func:`ast.literal_eval`.  It does this by
+building an embedded interpreter for a subset of the Python language using
+Python's :py:mod:`ast` module.  The emphasis and main area of application
+is the evaluation of mathematical expressions. Because of this emphasis,
+mathematical functions from Python's :py:mod:`math` module are built-in to
+asteval, and a large number of functions from `numpy`_ will be available if
+`numpy`_ is installed on your system.
+
+While the primary goal is evaluation of mathematical expressions, many
+features and constructs of the Python language are supported by default.
+These features include array slicing and subscripting, if-then-else
+conditionals, while loops, for loops, try-except blocks, list
+comprehension, and user-defined functions.  All objects in the asteval
+interpreter are truly Python objects, and all of the basic built-in data
+structures (strings, dictionaries, tuple, lists, sets, numpy arrays) are
+supported, including the built-in methods for these objects.
 
-However, Asteval is by no means an attempt to reproduce Python with its own
+However, asteval is by no means an attempt to reproduce Python with its own
 :py:mod:`ast` module.  There are important differences and missing features
-compared to Python.  Many of these absences are intentionally trying to make a
-safer version of :py:func:`eval`, while some are simply due to the reduced
-requirements for a small embedded min-language. Some of the main differences
-and absences include:
+compared to Python.  Many of these absences are intentional, and part of
+the effort to try to make a safer version of :py:func:`eval`, while some
+are simply due to the reduced requirements for an embedded mini-language.
+These differences and absences include:
 
  1. Variable and function symbol names are held in a simple symbol
     table - a single dictionary - giving a flat namespace.
  2. creating classes is not allowed.
  3. importing modules is not allowed.
- 4. function decorators, generators, yield, and lambda are not supported.
- 5. Many builtins (:py:func:`eval`, :py:func:`execfile`,
+ 4. f-strings, function decorators, generators, yield, type hint, and
+    `lambda` are not supported.
+ 5. Many builtin functions (:py:func:`eval`, :py:func:`execfile`,
     :py:func:`getattr`, :py:func:`hasattr`, :py:func:`setattr`, and
     :py:func:`delattr`) are not allowed.
  6. Accessing several private object attributes that can provide access to
     the python interpreter are not allowed.
 
-The effect to make the asteval mini-language look and act very much like
-miniature version of Python itself focused on mathematical calculations, and
-with noticeable limitations.
-
-
-Because asteval is suitable for evaluating user-supplied input strings, safety
-against malicious or incompetent user input is an important concern.  Asteval
-tries as hard as possible to prevent user-supplied input from crashing the
-Python interpreter or from returning exploitable parts of the Python
-interpreter.  In this sense asteval is certainly safer than using
+The resulting "asteval language" acts very much like miniature version of
+Python, focused on mathematical calculations, and with noticeable
+limitations.  It is the kind of toy programming language you might use to
+introduce simple scientific programming concepts.
+
+Because asteval is designed for evaluating user-supplied input, safety
+against malicious or incompetent user input is an important concern.
+Asteval tries as hard as possible to prevent user-supplied input from
+crashing the Python interpreter or from returning exploitable parts of the
+Python interpreter.  In this sense asteval is certainly safer than using
 :py:func:`eval`.  However, asteval is an open source project written by
 volunteers, and we cannot guarantee that it is completely safe against
 malicious attacks.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/doc/installation.rst 
new/asteval-0.9.22/doc/installation.rst
--- old/asteval-0.9.18/doc/installation.rst     2019-12-17 18:36:32.000000000 
+0100
+++ new/asteval-0.9.22/doc/installation.rst     2021-02-11 22:05:29.000000000 
+0100
@@ -10,9 +10,18 @@
 ~~~~~~~~~~~~~~~
 
 Asteval is a pure python module with no required dependencies outside of the
-standard library.  Asteval will make use of the `numpy`_ module if available.
+standard library.  Asteval will make use of the `numpy`_ module if
+available.  The test suite requires the `pytest` module.
 
-Version 0.9.18 supports and is tested with Python 3.5 through 3.8.
+The latest stable version of asteval is |release|.
+
+
+Versions 0.9.21 and 0.9.22 support and are tested with Python 3.6 through
+3.9.  Python 3.6 will be supported until at least its official end of life
+(December 2021).  No released version supports Python 3.10 yet.
+
+Versions 0.9.18, 0.9.19, and 0.9.20 supported and were tested with Python
+3.5 through 3.8.
 
 Version 0.9.17 was the last version to support Python 2.7.
 
@@ -20,14 +29,16 @@
 Download and Installation
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-The latest stable version of asteval is |release| and is available at `PyPI`_ 
or as
-a conda package.  You should be able to install asteval with::
+The latest stable version of asteval is |release| and is available at
+`PyPI`_ or as a conda package.  You should be able to install asteval
+with::
 
    pip install asteval
 
-or::
-
-   conda install -c GSECARS asteval
+It may also be available on some conda channels, including `conda-forge`,
+but as it is a pure Python package with no dependencies or OS-specific
+extensions, using `pip` should be the preferred method on all platforms and
+environments.
 
 Development Version
 ~~~~~~~~~~~~~~~~~~~~~~~~
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/doc/motivation.rst 
new/asteval-0.9.22/doc/motivation.rst
--- old/asteval-0.9.18/doc/motivation.rst       2019-12-17 18:36:32.000000000 
+0100
+++ new/asteval-0.9.22/doc/motivation.rst       2021-02-11 22:05:29.000000000 
+0100
@@ -12,41 +12,41 @@
 A completely fair question is: Why is this desirable?  That is, why not simply
 use :py:func:`eval`, or just use Python itself?
 
-The short answer is that sometimes you want to allow evaluation of user input,
-or expose a simple (or even "scientific") calculator inside a larger
-application.  For this, :py:func:`eval` is pretty scary, as it exposes *all*
-of Python, which makes user input difficult to trust.  Since asteval does not
-support the **import** statement or many other constructs, user code cannot
-access the :py:mod:`os` and :py:mod:`sys` modules or any functions or classes
-outside those provided in the symbol table.
+The short answer is that sometimes you want to allow evaluation of user
+input, or expose a simple or even scientific calculator inside a larger
+application.  For this, :py:func:`eval` is pretty scary, as it exposes
+*all* of Python, which makes user input difficult to trust.  Since asteval
+does not support the **import** statement or many other constructs, user
+code cannot access the :py:mod:`os` and :py:mod:`sys` modules or any
+functions or classes outside those provided in the symbol table.
 
 Many of the other missing features (modules, classes, lambda, yield,
 generators) are similarly motivated by a desire for a safer version of
 :py:func:`eval`.  The idea for asteval is to make a simple procedural,
-mathematically oriented language that can be embedded into larger
+mathematically-oriented language that can be embedded into larger
 applications.
 
 In fact, the asteval module grew out the the need for a simple expression
 evaluator for scientific applications such as the `lmfit`_ and `xraylarch`_
 modules.  An early attempt using the pyparsing module worked but was
-error-prone and difficult to maintain.  While the simplest of calculators or
-expressiona-evaluators is not hard with pyparsing, it turned out that using
-the Python :py:mod:`ast` module makes for a much easier and feature rich
-simple calculator scientific calculator, including slicing, complex numbers,
-keyword arguments to functions, etc.  In fact, it is so easy that adding more
-complex programming constructs like conditionals, loops, exception handling,
-and even user-defined functions was fairly simple to implement.  Importantly,
-because parsing is done by the :py:mod:`ast` module, whole classes of
-implementation errors disappear.  Valid python expression will be parsed
-correctly and converted into an Abstract Syntax Tree.  Furthermore, the
-resulting AST is easy to walk through, greatly simplifying evaluation over any
-other approach.  What started as a desire for a simple expression evaluator
-grew into a quite useable procedural domain-specific language for mathematical
-applications.
-
-Asteval makes no claims about speed. Evaluating the AST involves many function
-calls, which is going to be slower than Python.  In preliminary tests, it's
-about 4x slower than Python.  That said, for certain use cases (see
+error-prone and difficult to maintain.  While the simplest of calculators
+or expressiona-evaluators is not hard with pyparsing, it turned out that
+using the Python :py:mod:`ast` module makes it much easier to implement a
+feature-rich scientific calculator, including slicing, complex numbers,
+keyword arguments to functions, etc. In fact, this approach meant that
+adding more complex programming constructs like conditionals, loops,
+exception handling, and even user-defined functions was fairly simple.  An
+important benefit of using the :py:mod:`ast` module is that whole
+categories of implementation errors involving parsing, lexing, and defining a
+grammar disappear.  Any valid python 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 applications.
+
+Asteval makes no claims about speed. Evaluating the AST involves many
+function calls, which is going to be slower than Python - often 4x slower
+than Python.  That said, for certain use cases (see
 https://stackoverflow.com/questions/34106484), use of asteval and numpy can
 approach the speed of `eval` and the `numexpr` modules.
 
@@ -105,12 +105,12 @@
 can take a noticeable amount of CPU time.  It is not hard to come up with
 short program that would run for hundreds of years, which probably exceeds
 anyones threshold for an acceptable run-time.  But there simply is not an
-obvious way to predict how long any code will take to run from the text of the
-code itself.  As a simple example, consider the expression `x**y**z`.  For
-values of `x`, `y`, and `z`.  For `x=y=z=5`, runtime will be well under 0.001
-seconds.  For `x=y=z=8`, runtime will still be under 1 sec.  For `x=8, y=9,
-z=9`, runtime will several seconds.  But for `x=y=z=9`, runtime may exceed 1
-hour on some machines.  In short, runtime cannot be determined lexically.
+obvious way to predict how long any code will take to run from the text of
+the code itself.  As a simple example, consider the expression `x**y**z`.
+For values `x=y=z=5`, runtime will be well under 0.001 seconds.  For
+`x=y=z=8`, runtime will still be under 1 sec.  For `x=8, y=9, z=9`, runtime
+will several seconds.  But for `x=y=z=9`, runtime may exceed 1 hour on some
+machines.  In short, runtime cannot be determined lexically.
 
 This example also demonstrates there is not a good way to check for a
 long-running calculation within a single Python process.  That calculation is
@@ -146,7 +146,7 @@
 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
+desirable, 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.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/requirements.txt 
new/asteval-0.9.22/requirements.txt
--- old/asteval-0.9.18/requirements.txt 1970-01-01 01:00:00.000000000 +0100
+++ new/asteval-0.9.22/requirements.txt 2021-02-11 22:05:29.000000000 +0100
@@ -0,0 +1,5 @@
+##
+## pip requirements file.  To install dependencies, use
+##
+##  pip install -r requirements.txt
+## numpy>=1.6
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/setup.py new/asteval-0.9.22/setup.py
--- old/asteval-0.9.18/setup.py 2019-12-17 18:36:32.000000000 +0100
+++ new/asteval-0.9.22/setup.py 2021-02-11 22:05:29.000000000 +0100
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 from setuptools import setup
+
 import versioneer
 
 long_description = """ASTEVAL provides a numpy-aware, safe(ish) 'eval' function
@@ -12,26 +13,22 @@
 Expressions can be compiled into ast node for later evaluation,
 using the values in the symbol table current at evaluation time.
 """
-install_reqs = []
-test_reqs = ['pytest']
-
 setup(name='asteval',
       version=versioneer.get_version(),
       cmdclass=versioneer.get_cmdclass(),
       author='Matthew Newville',
       author_email='[email protected]',
       url='http://github.com/newville/asteval',
-      license = 'OSI Approved :: MIT License',
-      python_requires='>=3.5',
+      license='OSI Approved :: MIT License',
+      python_requires='>=3.6',
       description="Safe, minimalistic evaluator of python expression using ast 
module",
       long_description=long_description,
       packages=['asteval'],
-      install_requires=install_reqs,
-      tests_require=test_reqs,
+      tests_require=['pytest'],
       classifiers=['Intended Audience :: End Users/Desktop',
                    'Intended Audience :: Developers',
                    'Intended Audience :: Science/Research',
                    'Operating System :: OS Independent',
                    'Programming Language :: Python',
-      ],
+                   ],
       )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/asteval-0.9.18/tests/test_asteval.py 
new/asteval-0.9.22/tests/test_asteval.py
--- old/asteval-0.9.18/tests/test_asteval.py    2019-12-17 18:36:32.000000000 
+0100
+++ new/asteval-0.9.22/tests/test_asteval.py    2021-02-11 22:05:29.000000000 
+0100
@@ -8,16 +8,14 @@
 import textwrap
 import time
 import unittest
-import pytest
-from io import StringIO
-
 from functools import partial
+from io import StringIO
 from sys import version_info
 from tempfile import NamedTemporaryFile
 
-from asteval import NameFinder, Interpreter, make_symbol_table
-
+import pytest
 
+from asteval import Interpreter, NameFinder, make_symbol_table
 
 HAS_NUMPY = False
 try:
@@ -28,6 +26,9 @@
     HAS_NUMPY = False
 
 
+version_info = (version_info.major, version_info.minor)
+
+
 class TestCase(unittest.TestCase):
     """testing of asteval"""
     def setUp(self):
@@ -95,7 +96,6 @@
         if HAS_NUMPY:
             assert_allclose(tval, val, rtol=1.e-4, atol=1.e-4)
 
-
     # noinspection PyUnresolvedReferences
     def istrue(self, expr):
         """assert that an expression evaluates to True"""
@@ -141,6 +141,20 @@
         self.istrue("a_dict['a'] == 1")
         self.istrue("a_dict['d'] == 4")
 
+    def test_dict_set_index(self):
+        """dictionary indexing"""
+        self.interp("a_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}")
+        self.interp("a_dict['a'] = -4")
+        self.interp("a_dict['e'] = 73")
+
+        self.istrue("a_dict['a'] == -4")
+        self.istrue("a_dict['e'] == 73")
+
+        self.interp("b_dict = {}")
+        self.interp("keyname = 'a'")
+        self.interp("b_dict[keyname] = (1, -1, 'x')")
+        self.istrue("b_dict[keyname] ==  (1, -1, 'x')")
+
     def test_list_index(self):
         """list indexing"""
         self.interp("a_list = ['a', 'b', 'c', 'd', 'o']")
@@ -166,8 +180,8 @@
         """nd array indexing"""
         if HAS_NUMPY:
             self.interp("a_ndarray = 5*arange(20)")
-            assert(self.interp("a_ndarray[2]")  == 10)
-            assert(self.interp("a_ndarray[4]")  == 20)
+            assert(self.interp("a_ndarray[2]") == 10)
+            assert(self.interp("a_ndarray[4]") == 20)
 
     def test_ndarrayslice(self):
         """array slicing"""
@@ -177,6 +191,7 @@
             self.interp("y = arange(20).reshape(4, 5)")
             self.istrue("y[:,3]  == array([3, 8, 13, 18])")
             self.istrue("y[...,1]  == array([1, 6, 11, 16])")
+            self.istrue("y[1,:] == array([5, 6, 7, 8, 9])")
             self.interp("y[...,1] = array([2, 2, 2, 2])")
             self.istrue("y[1,:] == array([5, 2, 7, 8, 9])")
 
@@ -265,6 +280,8 @@
         self.check_error(None)
         self.interp('assert n==7')
         self.check_error('AssertionError')
+        self.interp('assert n==7, "no match"')
+        self.check_error('AssertionError', 'no match')
 
     def test_for(self):
         """for loops"""
@@ -731,7 +748,7 @@
         """test function with kw args, no **kws"""
         self.interp(textwrap.dedent("""
             def fcn(x=0, y=0, z=0, t=0, square=False):
-                'test varargs function'
+                'test kwargs function'
                 out = 0
                 for i in (x, y, z, t):
                     if square:
@@ -804,8 +821,25 @@
         self.interp("o = fcn(1, x=2)")
         self.check_error('TypeError')
 
+    def test_kwargx(self):
+        """test passing and chaining in **kwargs"""
+        self.interp(textwrap.dedent("""
+            def inner(foo=None, bar=None):
+                return (foo, bar)
+
+            def outer(**kwargs):
+                return inner(**kwargs)
+            """))
+
+        ret = self.interp("inner(foo='a', bar=2)")
+        assert(ret == ('a', 2))
+        ret = self.interp("outer(foo='a', bar=7)")
+        assert(ret == ('a', 7))
+        ret = self.interp("outer(**dict(foo='b', bar=3))")
+        assert(ret == ('b', 3))
+
     def test_nested_functions(self):
-        setup="""
+        setup = """
         def a(x=10):
             if x > 5:
                 return 1
@@ -825,7 +859,6 @@
         self.isvalue('o1', 3.5)
         self.isvalue('o2', 1.5)
 
-
     def test_astdump(self):
         """test ast parsing and dumping"""
         astnode = self.interp.parse('x = 1')
@@ -855,7 +888,6 @@
         self.interp("1<<1001")
         self.check_error('RuntimeError')
 
-
     def test_safe_open(self):
         self.interp('open("foo1", "wb")')
         self.check_error('RuntimeError')
@@ -882,8 +914,12 @@
         self.interp("9**9**9**9**9**9**9**9")
         self.check_error('RuntimeError')  # Safe, safe_pow() catches this
         self.interp(
-            
"((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((1))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))")
-        self.check_error('MemoryError')  # Hmmm, this is caught, but its still 
concerning...
+            "x = 
((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((1))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))")
+        if version_info == (3, 9):
+            self.isvalue('x', 1)
+            self.check_error(None)
+        else:
+            self.check_error('MemoryError')  # Hmmm, this is caught, but its 
still concerning...
         self.interp("compile('xxx')")
         self.check_error('NameError')  # Safe, compile() is not supported
 
@@ -944,9 +980,9 @@
             x2 = aeval.symtable['x2']
             x3 = aeval.symtable['x3']
 
-            assert_allclose(x1, 0.50,     rtol=0.001)
+            assert_allclose(x1, 0.50, rtol=0.001)
             assert_allclose(x2, 0.866025, rtol=0.001)
-            assert_allclose(x3, 1.00,     rtol=0.001)
+            assert_allclose(x3, 1.00, rtol=0.001)
 
     def test_readonly_symbols(self):
 
@@ -984,7 +1020,6 @@
         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")
@@ -999,7 +1034,6 @@
         assert(aeval2("abs(8)") == 8)
         assert(aeval2("abs(-8)") == 8)
 
-
     def test_chained_compparisons(self):
         self.interp('a = 7')
         self.interp('b = 12')
@@ -1036,10 +1070,33 @@
         # uses the function's __name__ attribute. Partials don't have a
         # __name__ attribute, so we want to make sure that an AttributeError is
         # not raised.
-    
+
         result = aeval("sqrt(-1)")
         assert aeval.error.pop().exc == ValueError
 
+    def test_inner_return(self):
+        self.interp(textwrap.dedent("""
+            def func():
+                loop_cnt = 0
+                for i in range(5):
+                    for k in range(5):
+                        loop_cnt += 1
+                    return (i, k, loop_cnt)
+        """))
+        out = self.interp("func()")
+        assert out == (0, 4, 5)
+
+    def test_nested_break(self):
+        self.interp(textwrap.dedent("""
+        def func_w():
+            for k in range(5):
+                if k == 4:
+                    break
+                    k = 100
+            return k
+        """))
+        assert 4 == self.interp("func_w()")
+
 
 class TestCase2(unittest.TestCase):
     def test_stringio(self):
@@ -1050,5 +1107,6 @@
         intrep("print('out')")
         self.assertEqual(out.getvalue(), 'out\n')
 
+
 if __name__ == '__main__':
     pytest.main(['-v', '-x', '-s'])

Reply via email to