Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-pure-eval for 
openSUSE:Factory checked in at 2022-10-10 18:44:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pure-eval (Old)
 and      /work/SRC/openSUSE:Factory/.python-pure-eval.new.2275 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pure-eval"

Mon Oct 10 18:44:11 2022 rev:2 rq:1008173 version:0.2.2

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-pure-eval/python-pure-eval.changes        
2022-01-15 20:05:20.477765629 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-pure-eval.new.2275/python-pure-eval.changes  
    2022-10-10 18:44:33.518868152 +0200
@@ -1,0 +2,7 @@
+Tue Oct  4 23:39:28 UTC 2022 - Yogalakshmi Arunachalam <[email protected]>
+
+- Update to Version 0.2.2 
+  Merge pull request #12 from alexmojaki/ensure_dict
+      Ensure dict
+
+-------------------------------------------------------------------

Old:
----
  pure_eval-0.2.1.tar.gz

New:
----
  pure_eval-0.2.2.tar.gz

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

Other differences:
------------------
++++++ python-pure-eval.spec ++++++
--- /var/tmp/diff_new_pack.GktnVC/_old  2022-10-10 18:44:33.958869099 +0200
+++ /var/tmp/diff_new_pack.GktnVC/_new  2022-10-10 18:44:33.966869116 +0200
@@ -18,7 +18,7 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-pure-eval
-Version:        0.2.1
+Version:        0.2.2
 Release:        0
 Summary:        Safely evaluate AST nodes without side effects
 License:        MIT

++++++ pure_eval-0.2.1.tar.gz -> pure_eval-0.2.2.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/.github/workflows/pytest.yml 
new/pure_eval-0.2.2/.github/workflows/pytest.yml
--- old/pure_eval-0.2.1/.github/workflows/pytest.yml    1970-01-01 
01:00:00.000000000 +0100
+++ new/pure_eval-0.2.2/.github/workflows/pytest.yml    2022-01-22 
16:40:30.000000000 +0100
@@ -0,0 +1,36 @@
+name: Tests
+on: [push, pull_request]
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        python-version: [3.7, 3.8, 3.9, 3.10-dev]
+    steps:
+    - uses: actions/checkout@v2
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v2
+      with:
+        python-version: ${{ matrix.python-version }}
+    - name: run tests
+      env:
+        PURE_EVAL_SLOW_TESTS: 1
+      run: |
+        pip install -U pip
+        pip install --upgrade coveralls setuptools setuptools_scm pep517
+        pip install .[tests]
+        coverage run --source pure_eval -m pytest
+        coverage report -m
+    - name: Coveralls Python
+      uses: AndreMiras/coveralls-python-action@v20201129
+      with:
+        parallel: true
+        flag-name: test-${{ matrix.python-version }}
+  coveralls_finish:
+    needs: build
+    runs-on: ubuntu-latest
+    steps:
+      - name: Coveralls Finished
+        uses: AndreMiras/coveralls-python-action@v20201129
+        with:
+          parallel-finished: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/.travis.yml 
new/pure_eval-0.2.2/.travis.yml
--- old/pure_eval-0.2.1/.travis.yml     2020-10-13 21:27:57.000000000 +0200
+++ new/pure_eval-0.2.2/.travis.yml     1970-01-01 01:00:00.000000000 +0100
@@ -1,32 +0,0 @@
-dist: xenial
-language: python
-sudo: false
-
-python:
-  - 3.5
-  - 3.6
-  - 3.7
-  - 3.8-dev
-  - 3.9-dev
-
-env:
-  global:
-    - PURE_EVAL_SLOW_TESTS=1
-    - COVERALLS_PARALLEL=true
-
-before_install:
-  - pip install --upgrade coveralls setuptools>=44 setuptools_scm>=3.4.3 pep517
-
-install:
-  - pip install ".[tests]"
-
-script:
-  - coverage run --branch --include='pure_eval/*' -m pytest 
--junitxml=./rspec.xml
-  - coverage report -m
-
-after_success:
-  - coveralls
-
-notifications:
-  webhooks: https://coveralls.io/webhook
-  email: false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/MANIFEST.in 
new/pure_eval-0.2.2/MANIFEST.in
--- old/pure_eval-0.2.1/MANIFEST.in     2020-10-13 21:27:57.000000000 +0200
+++ new/pure_eval-0.2.2/MANIFEST.in     2022-01-22 16:40:30.000000000 +0100
@@ -1 +1,3 @@
 include LICENSE.txt
+include pure_eval/py.typed
+include README.md
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/PKG-INFO new/pure_eval-0.2.2/PKG-INFO
--- old/pure_eval-0.2.1/PKG-INFO        2021-03-26 16:18:03.483309000 +0100
+++ new/pure_eval-0.2.2/PKG-INFO        2022-01-22 16:41:17.320512300 +0100
@@ -1,216 +1,11 @@
 Metadata-Version: 2.1
 Name: pure_eval
-Version: 0.2.1
+Version: 0.2.2
 Summary: Safely evaluate AST nodes without side effects
 Home-page: http://github.com/alexmojaki/pure_eval
 Author: Alex Hall
 Author-email: [email protected]
 License: MIT
-Description: # `pure_eval`
-        
-        [![Build 
Status](https://travis-ci.org/alexmojaki/pure_eval.svg?branch=master)](https://travis-ci.org/alexmojaki/pure_eval)
 [![Coverage 
Status](https://coveralls.io/repos/github/alexmojaki/pure_eval/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/pure_eval?branch=master)
 [![Supports Python versions 
3.5+](https://img.shields.io/pypi/pyversions/pure_eval.svg)](https://pypi.python.org/pypi/pure_eval)
-        
-        This is a Python package that lets you safely evaluate certain AST 
nodes without triggering arbitrary code that may have unwanted side effects.
-        
-        It can be installed from PyPI:
-        
-            pip install pure_eval
-        
-        To demonstrate usage, suppose we have an object defined as follows:
-        
-        ```python
-        class Rectangle:
-            def __init__(self, width, height):
-                self.width = width
-                self.height = height
-        
-            @property
-            def area(self):
-                print("Calculating area...")
-                return self.width * self.height
-        
-        
-        rect = Rectangle(3, 5)
-        ```
-        
-        Given the `rect` object, we want to evaluate whatever expressions we 
can in this source code:
-        
-        ```python
-        source = "(rect.width, rect.height, rect.area)"
-        ```
-        
-        This library works with the AST, so let's parse the source code and 
peek inside:
-        
-        ```python
-        import ast
-        
-        tree = ast.parse(source)
-        the_tuple = tree.body[0].value
-        for node in the_tuple.elts:
-            print(ast.dump(node))
-        ```
-        
-        Output:
-        
-        ```python
-        Attribute(value=Name(id='rect', ctx=Load()), attr='width', ctx=Load())
-        Attribute(value=Name(id='rect', ctx=Load()), attr='height', ctx=Load())
-        Attribute(value=Name(id='rect', ctx=Load()), attr='area', ctx=Load())
-        ```
-        
-        Now to actually use the library. First construct an Evaluator:
-        
-        ```python
-        from pure_eval import Evaluator
-        
-        evaluator = Evaluator({"rect": rect})
-        ```
-        
-        The argument to `Evaluator` should be a mapping from variable names to 
their values. Or if you have access to the stack frame where `rect` is defined, 
you can instead use:
-        
-        ```python
-        evaluator = Evaluator.from_frame(frame)
-        ```
-        
-        Now to evaluate some nodes, using `evaluator[node]`:
-        
-        ```python
-        print("rect.width:", evaluator[the_tuple.elts[0]])
-        print("rect:", evaluator[the_tuple.elts[0].value])
-        ```
-        
-        Output:
-        
-        ```
-        rect.width: 3
-        rect: <__main__.Rectangle object at 0x105b0dd30>
-        ```
-        
-        OK, but you could have done the same thing with `eval`. The useful 
part is that it will refuse to evaluate the property `rect.area` because that 
would trigger unknown code. If we try, it'll raise a `CannotEval` exception.
-        
-        ```python
-        from pure_eval import CannotEval
-        
-        try:
-            print("rect.area:", evaluator[the_tuple.elts[2]])  # fails
-        except CannotEval as e:
-            print(e)  # prints CannotEval
-        ```
-        
-        To find all the expressions that can be evaluated in a tree:
-        
-        ```python
-        for node, value in evaluator.find_expressions(tree):
-            print(ast.dump(node), value)
-        ```
-        
-        Output:
-        
-        ```python
-        Attribute(value=Name(id='rect', ctx=Load()), attr='width', ctx=Load()) 
3
-        Attribute(value=Name(id='rect', ctx=Load()), attr='height', 
ctx=Load()) 5
-        Name(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>
-        Name(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>
-        Name(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>
-        ```
-        
-        Note that this includes `rect` three times, once for each appearance 
in the source code. Since all these nodes are equivalent, we can group them 
together:
-        
-        ```python
-        from pure_eval import group_expressions
-        
-        for nodes, values in 
group_expressions(evaluator.find_expressions(tree)):
-            print(len(nodes), "nodes with value:", values)
-        ```
-        
-        Output:
-        
-        ```
-        1 nodes with value: 3
-        1 nodes with value: 5
-        3 nodes with value: <__main__.Rectangle object at 0x10d374d30>
-        ```
-        
-        If we want to list all the expressions in a tree, we may want to 
filter out certain expressions whose values are obvious. For example, suppose 
we have a function `foo`:
-        
-        ```python
-        def foo():
-            pass
-        ```
-        
-        If we refer to `foo` by its name as usual, then that's not interesting:
-        
-        ```python
-        from pure_eval import is_expression_interesting
-        
-        node = ast.parse('foo').body[0].value
-        print(ast.dump(node))
-        print(is_expression_interesting(node, foo))
-        ```
-        
-        Output:
-        
-        ```python
-        Name(id='foo', ctx=Load())
-        False
-        ```
-        
-        But if we refer to it by a different name, then it's interesting:
-        
-        ```python
-        node = ast.parse('bar').body[0].value
-        print(ast.dump(node))
-        print(is_expression_interesting(node, foo))
-        ```
-        
-        Output:
-        
-        ```python
-        Name(id='bar', ctx=Load())
-        True
-        ```
-        
-        In general `is_expression_interesting` returns False for the following 
values:
-        - Literals (e.g. `123`, `'abc'`, `[1, 2, 3]`, `{'a': (), 'b': ([1, 2], 
[3])}`)
-        - Variables or attributes whose name is equal to the value's 
`__name__`, such as `foo` above or `self.foo` if it was a method.
-        - Builtins (e.g. `len`) referred to by their usual name.
-        
-        To make things easier, you can combine finding expressions, grouping 
them, and filtering out the obvious ones with:
-        
-        ```python
-        evaluator.interesting_expressions_grouped(root)
-        ```
-        
-        To get the source code of an AST node, I recommend 
[asttokens](https://github.com/gristlabs/asttokens).
-        
-        Here's a complete example that brings it all together:
-        
-        ```python
-        from asttokens import ASTTokens
-        from pure_eval import Evaluator
-        
-        source = """
-        x = 1
-        d = {x: 2}
-        y = d[x]
-        """
-        
-        names = {}
-        exec(source, names)
-        atok = ASTTokens(source, parse=True)
-        for nodes, value in 
Evaluator(names).interesting_expressions_grouped(atok.tree):
-            print(atok.get_text(nodes[0]), "=", value)
-        ```
-        
-        Output:
-        
-        ```python
-        x = 1
-        d = {1: 2}
-        y = 2
-        d[x] = 2
-        ```
-        
 Platform: UNKNOWN
 Classifier: Intended Audience :: Developers
 Classifier: Programming Language :: Python :: 3.5
@@ -218,7 +13,216 @@
 Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
 Description-Content-Type: text/markdown
 Provides-Extra: tests
+License-File: LICENSE.txt
+
+# `pure_eval`
+
+[![Build 
Status](https://travis-ci.org/alexmojaki/pure_eval.svg?branch=master)](https://travis-ci.org/alexmojaki/pure_eval)
 [![Coverage 
Status](https://coveralls.io/repos/github/alexmojaki/pure_eval/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/pure_eval?branch=master)
 [![Supports Python versions 
3.5+](https://img.shields.io/pypi/pyversions/pure_eval.svg)](https://pypi.python.org/pypi/pure_eval)
+
+This is a Python package that lets you safely evaluate certain AST nodes 
without triggering arbitrary code that may have unwanted side effects.
+
+It can be installed from PyPI:
+
+    pip install pure_eval
+
+To demonstrate usage, suppose we have an object defined as follows:
+
+```python
+class Rectangle:
+    def __init__(self, width, height):
+        self.width = width
+        self.height = height
+
+    @property
+    def area(self):
+        print("Calculating area...")
+        return self.width * self.height
+
+
+rect = Rectangle(3, 5)
+```
+
+Given the `rect` object, we want to evaluate whatever expressions we can in 
this source code:
+
+```python
+source = "(rect.width, rect.height, rect.area)"
+```
+
+This library works with the AST, so let's parse the source code and peek 
inside:
+
+```python
+import ast
+
+tree = ast.parse(source)
+the_tuple = tree.body[0].value
+for node in the_tuple.elts:
+    print(ast.dump(node))
+```
+
+Output:
+
+```python
+Attribute(value=Name(id='rect', ctx=Load()), attr='width', ctx=Load())
+Attribute(value=Name(id='rect', ctx=Load()), attr='height', ctx=Load())
+Attribute(value=Name(id='rect', ctx=Load()), attr='area', ctx=Load())
+```
+
+Now to actually use the library. First construct an Evaluator:
+
+```python
+from pure_eval import Evaluator
+
+evaluator = Evaluator({"rect": rect})
+```
+
+The argument to `Evaluator` should be a mapping from variable names to their 
values. Or if you have access to the stack frame where `rect` is defined, you 
can instead use:
+
+```python
+evaluator = Evaluator.from_frame(frame)
+```
+
+Now to evaluate some nodes, using `evaluator[node]`:
+
+```python
+print("rect.width:", evaluator[the_tuple.elts[0]])
+print("rect:", evaluator[the_tuple.elts[0].value])
+```
+
+Output:
+
+```
+rect.width: 3
+rect: <__main__.Rectangle object at 0x105b0dd30>
+```
+
+OK, but you could have done the same thing with `eval`. The useful part is 
that it will refuse to evaluate the property `rect.area` because that would 
trigger unknown code. If we try, it'll raise a `CannotEval` exception.
+
+```python
+from pure_eval import CannotEval
+
+try:
+    print("rect.area:", evaluator[the_tuple.elts[2]])  # fails
+except CannotEval as e:
+    print(e)  # prints CannotEval
+```
+
+To find all the expressions that can be evaluated in a tree:
+
+```python
+for node, value in evaluator.find_expressions(tree):
+    print(ast.dump(node), value)
+```
+
+Output:
+
+```python
+Attribute(value=Name(id='rect', ctx=Load()), attr='width', ctx=Load()) 3
+Attribute(value=Name(id='rect', ctx=Load()), attr='height', ctx=Load()) 5
+Name(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>
+Name(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>
+Name(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>
+```
+
+Note that this includes `rect` three times, once for each appearance in the 
source code. Since all these nodes are equivalent, we can group them together:
+
+```python
+from pure_eval import group_expressions
+
+for nodes, values in group_expressions(evaluator.find_expressions(tree)):
+    print(len(nodes), "nodes with value:", values)
+```
+
+Output:
+
+```
+1 nodes with value: 3
+1 nodes with value: 5
+3 nodes with value: <__main__.Rectangle object at 0x10d374d30>
+```
+
+If we want to list all the expressions in a tree, we may want to filter out 
certain expressions whose values are obvious. For example, suppose we have a 
function `foo`:
+
+```python
+def foo():
+    pass
+```
+
+If we refer to `foo` by its name as usual, then that's not interesting:
+
+```python
+from pure_eval import is_expression_interesting
+
+node = ast.parse('foo').body[0].value
+print(ast.dump(node))
+print(is_expression_interesting(node, foo))
+```
+
+Output:
+
+```python
+Name(id='foo', ctx=Load())
+False
+```
+
+But if we refer to it by a different name, then it's interesting:
+
+```python
+node = ast.parse('bar').body[0].value
+print(ast.dump(node))
+print(is_expression_interesting(node, foo))
+```
+
+Output:
+
+```python
+Name(id='bar', ctx=Load())
+True
+```
+
+In general `is_expression_interesting` returns False for the following values:
+- Literals (e.g. `123`, `'abc'`, `[1, 2, 3]`, `{'a': (), 'b': ([1, 2], [3])}`)
+- Variables or attributes whose name is equal to the value's `__name__`, such 
as `foo` above or `self.foo` if it was a method.
+- Builtins (e.g. `len`) referred to by their usual name.
+
+To make things easier, you can combine finding expressions, grouping them, and 
filtering out the obvious ones with:
+
+```python
+evaluator.interesting_expressions_grouped(root)
+```
+
+To get the source code of an AST node, I recommend 
[asttokens](https://github.com/gristlabs/asttokens).
+
+Here's a complete example that brings it all together:
+
+```python
+from asttokens import ASTTokens
+from pure_eval import Evaluator
+
+source = """
+x = 1
+d = {x: 2}
+y = d[x]
+"""
+
+names = {}
+exec(source, names)
+atok = ASTTokens(source, parse=True)
+for nodes, value in 
Evaluator(names).interesting_expressions_grouped(atok.tree):
+    print(atok.get_text(nodes[0]), "=", value)
+```
+
+Output:
+
+```python
+x = 1
+d = {1: 2}
+y = 2
+d[x] = 2
+```
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/make_release.sh 
new/pure_eval-0.2.2/make_release.sh
--- old/pure_eval-0.2.1/make_release.sh 2021-03-26 16:17:36.000000000 +0100
+++ new/pure_eval-0.2.2/make_release.sh 2022-01-22 16:40:30.000000000 +0100
@@ -26,5 +26,5 @@
 git tag "${TAG}"
 git push origin master "${TAG}"
 rm -rf ./build ./dist
-python3 -m pep517.build -b .
-twine upload ./dist/*.whl
+python -m build --sdist --wheel .
+twine upload ./dist/*.whl dist/*.tar.gz
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/pure_eval/core.py 
new/pure_eval-0.2.2/pure_eval/core.py
--- old/pure_eval-0.2.1/pure_eval/core.py       2021-03-26 16:11:43.000000000 
+0100
+++ new/pure_eval-0.2.2/pure_eval/core.py       2022-01-22 16:40:30.000000000 
+0100
@@ -15,6 +15,7 @@
     of_standard_types,
     is_any,
     of_type,
+    ensure_dict,
 )
 
 
@@ -39,9 +40,9 @@
         """
 
         return cls(ChainMap(
-            frame.f_locals,
-            frame.f_globals,
-            frame.f_builtins,
+            ensure_dict(frame.f_locals),
+            ensure_dict(frame.f_globals),
+            ensure_dict(frame.f_builtins),
         ))
 
     def __getitem__(self, node: ast.expr) -> Any:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/pure_eval/py.typed 
new/pure_eval-0.2.2/pure_eval/py.typed
--- old/pure_eval-0.2.1/pure_eval/py.typed      1970-01-01 01:00:00.000000000 
+0100
+++ new/pure_eval-0.2.2/pure_eval/py.typed      2022-01-22 16:24:35.000000000 
+0100
@@ -0,0 +1 @@
+# Marker file for PEP 561. The pure_eval package uses inline types.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/pure_eval/utils.py 
new/pure_eval-0.2.2/pure_eval/utils.py
--- old/pure_eval-0.2.1/pure_eval/utils.py      2021-03-26 14:22:14.000000000 
+0100
+++ new/pure_eval-0.2.2/pure_eval/utils.py      2022-01-22 16:40:30.000000000 
+0100
@@ -189,3 +189,13 @@
         return list(map(copy_ast_without_context, x))
     else:
         return x
+
+
+def ensure_dict(x):
+    """
+    Handles invalid non-dict inputs
+    """
+    try:
+        return dict(x)
+    except Exception:
+        return {}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/pure_eval/version.py 
new/pure_eval-0.2.2/pure_eval/version.py
--- old/pure_eval-0.2.1/pure_eval/version.py    2021-03-26 16:18:03.000000000 
+0100
+++ new/pure_eval-0.2.2/pure_eval/version.py    2022-01-22 16:41:17.000000000 
+0100
@@ -1 +1 @@
-__version__ = '0.2.1'
\ No newline at end of file
+__version__ = '0.2.2'
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/pure_eval.egg-info/PKG-INFO 
new/pure_eval-0.2.2/pure_eval.egg-info/PKG-INFO
--- old/pure_eval-0.2.1/pure_eval.egg-info/PKG-INFO     2021-03-26 
16:18:03.000000000 +0100
+++ new/pure_eval-0.2.2/pure_eval.egg-info/PKG-INFO     2022-01-22 
16:41:17.000000000 +0100
@@ -1,216 +1,11 @@
 Metadata-Version: 2.1
 Name: pure-eval
-Version: 0.2.1
+Version: 0.2.2
 Summary: Safely evaluate AST nodes without side effects
 Home-page: http://github.com/alexmojaki/pure_eval
 Author: Alex Hall
 Author-email: [email protected]
 License: MIT
-Description: # `pure_eval`
-        
-        [![Build 
Status](https://travis-ci.org/alexmojaki/pure_eval.svg?branch=master)](https://travis-ci.org/alexmojaki/pure_eval)
 [![Coverage 
Status](https://coveralls.io/repos/github/alexmojaki/pure_eval/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/pure_eval?branch=master)
 [![Supports Python versions 
3.5+](https://img.shields.io/pypi/pyversions/pure_eval.svg)](https://pypi.python.org/pypi/pure_eval)
-        
-        This is a Python package that lets you safely evaluate certain AST 
nodes without triggering arbitrary code that may have unwanted side effects.
-        
-        It can be installed from PyPI:
-        
-            pip install pure_eval
-        
-        To demonstrate usage, suppose we have an object defined as follows:
-        
-        ```python
-        class Rectangle:
-            def __init__(self, width, height):
-                self.width = width
-                self.height = height
-        
-            @property
-            def area(self):
-                print("Calculating area...")
-                return self.width * self.height
-        
-        
-        rect = Rectangle(3, 5)
-        ```
-        
-        Given the `rect` object, we want to evaluate whatever expressions we 
can in this source code:
-        
-        ```python
-        source = "(rect.width, rect.height, rect.area)"
-        ```
-        
-        This library works with the AST, so let's parse the source code and 
peek inside:
-        
-        ```python
-        import ast
-        
-        tree = ast.parse(source)
-        the_tuple = tree.body[0].value
-        for node in the_tuple.elts:
-            print(ast.dump(node))
-        ```
-        
-        Output:
-        
-        ```python
-        Attribute(value=Name(id='rect', ctx=Load()), attr='width', ctx=Load())
-        Attribute(value=Name(id='rect', ctx=Load()), attr='height', ctx=Load())
-        Attribute(value=Name(id='rect', ctx=Load()), attr='area', ctx=Load())
-        ```
-        
-        Now to actually use the library. First construct an Evaluator:
-        
-        ```python
-        from pure_eval import Evaluator
-        
-        evaluator = Evaluator({"rect": rect})
-        ```
-        
-        The argument to `Evaluator` should be a mapping from variable names to 
their values. Or if you have access to the stack frame where `rect` is defined, 
you can instead use:
-        
-        ```python
-        evaluator = Evaluator.from_frame(frame)
-        ```
-        
-        Now to evaluate some nodes, using `evaluator[node]`:
-        
-        ```python
-        print("rect.width:", evaluator[the_tuple.elts[0]])
-        print("rect:", evaluator[the_tuple.elts[0].value])
-        ```
-        
-        Output:
-        
-        ```
-        rect.width: 3
-        rect: <__main__.Rectangle object at 0x105b0dd30>
-        ```
-        
-        OK, but you could have done the same thing with `eval`. The useful 
part is that it will refuse to evaluate the property `rect.area` because that 
would trigger unknown code. If we try, it'll raise a `CannotEval` exception.
-        
-        ```python
-        from pure_eval import CannotEval
-        
-        try:
-            print("rect.area:", evaluator[the_tuple.elts[2]])  # fails
-        except CannotEval as e:
-            print(e)  # prints CannotEval
-        ```
-        
-        To find all the expressions that can be evaluated in a tree:
-        
-        ```python
-        for node, value in evaluator.find_expressions(tree):
-            print(ast.dump(node), value)
-        ```
-        
-        Output:
-        
-        ```python
-        Attribute(value=Name(id='rect', ctx=Load()), attr='width', ctx=Load()) 
3
-        Attribute(value=Name(id='rect', ctx=Load()), attr='height', 
ctx=Load()) 5
-        Name(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>
-        Name(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>
-        Name(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>
-        ```
-        
-        Note that this includes `rect` three times, once for each appearance 
in the source code. Since all these nodes are equivalent, we can group them 
together:
-        
-        ```python
-        from pure_eval import group_expressions
-        
-        for nodes, values in 
group_expressions(evaluator.find_expressions(tree)):
-            print(len(nodes), "nodes with value:", values)
-        ```
-        
-        Output:
-        
-        ```
-        1 nodes with value: 3
-        1 nodes with value: 5
-        3 nodes with value: <__main__.Rectangle object at 0x10d374d30>
-        ```
-        
-        If we want to list all the expressions in a tree, we may want to 
filter out certain expressions whose values are obvious. For example, suppose 
we have a function `foo`:
-        
-        ```python
-        def foo():
-            pass
-        ```
-        
-        If we refer to `foo` by its name as usual, then that's not interesting:
-        
-        ```python
-        from pure_eval import is_expression_interesting
-        
-        node = ast.parse('foo').body[0].value
-        print(ast.dump(node))
-        print(is_expression_interesting(node, foo))
-        ```
-        
-        Output:
-        
-        ```python
-        Name(id='foo', ctx=Load())
-        False
-        ```
-        
-        But if we refer to it by a different name, then it's interesting:
-        
-        ```python
-        node = ast.parse('bar').body[0].value
-        print(ast.dump(node))
-        print(is_expression_interesting(node, foo))
-        ```
-        
-        Output:
-        
-        ```python
-        Name(id='bar', ctx=Load())
-        True
-        ```
-        
-        In general `is_expression_interesting` returns False for the following 
values:
-        - Literals (e.g. `123`, `'abc'`, `[1, 2, 3]`, `{'a': (), 'b': ([1, 2], 
[3])}`)
-        - Variables or attributes whose name is equal to the value's 
`__name__`, such as `foo` above or `self.foo` if it was a method.
-        - Builtins (e.g. `len`) referred to by their usual name.
-        
-        To make things easier, you can combine finding expressions, grouping 
them, and filtering out the obvious ones with:
-        
-        ```python
-        evaluator.interesting_expressions_grouped(root)
-        ```
-        
-        To get the source code of an AST node, I recommend 
[asttokens](https://github.com/gristlabs/asttokens).
-        
-        Here's a complete example that brings it all together:
-        
-        ```python
-        from asttokens import ASTTokens
-        from pure_eval import Evaluator
-        
-        source = """
-        x = 1
-        d = {x: 2}
-        y = d[x]
-        """
-        
-        names = {}
-        exec(source, names)
-        atok = ASTTokens(source, parse=True)
-        for nodes, value in 
Evaluator(names).interesting_expressions_grouped(atok.tree):
-            print(atok.get_text(nodes[0]), "=", value)
-        ```
-        
-        Output:
-        
-        ```python
-        x = 1
-        d = {1: 2}
-        y = 2
-        d[x] = 2
-        ```
-        
 Platform: UNKNOWN
 Classifier: Intended Audience :: Developers
 Classifier: Programming Language :: Python :: 3.5
@@ -218,7 +13,216 @@
 Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Operating System :: OS Independent
 Description-Content-Type: text/markdown
 Provides-Extra: tests
+License-File: LICENSE.txt
+
+# `pure_eval`
+
+[![Build 
Status](https://travis-ci.org/alexmojaki/pure_eval.svg?branch=master)](https://travis-ci.org/alexmojaki/pure_eval)
 [![Coverage 
Status](https://coveralls.io/repos/github/alexmojaki/pure_eval/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/pure_eval?branch=master)
 [![Supports Python versions 
3.5+](https://img.shields.io/pypi/pyversions/pure_eval.svg)](https://pypi.python.org/pypi/pure_eval)
+
+This is a Python package that lets you safely evaluate certain AST nodes 
without triggering arbitrary code that may have unwanted side effects.
+
+It can be installed from PyPI:
+
+    pip install pure_eval
+
+To demonstrate usage, suppose we have an object defined as follows:
+
+```python
+class Rectangle:
+    def __init__(self, width, height):
+        self.width = width
+        self.height = height
+
+    @property
+    def area(self):
+        print("Calculating area...")
+        return self.width * self.height
+
+
+rect = Rectangle(3, 5)
+```
+
+Given the `rect` object, we want to evaluate whatever expressions we can in 
this source code:
+
+```python
+source = "(rect.width, rect.height, rect.area)"
+```
+
+This library works with the AST, so let's parse the source code and peek 
inside:
+
+```python
+import ast
+
+tree = ast.parse(source)
+the_tuple = tree.body[0].value
+for node in the_tuple.elts:
+    print(ast.dump(node))
+```
+
+Output:
+
+```python
+Attribute(value=Name(id='rect', ctx=Load()), attr='width', ctx=Load())
+Attribute(value=Name(id='rect', ctx=Load()), attr='height', ctx=Load())
+Attribute(value=Name(id='rect', ctx=Load()), attr='area', ctx=Load())
+```
+
+Now to actually use the library. First construct an Evaluator:
+
+```python
+from pure_eval import Evaluator
+
+evaluator = Evaluator({"rect": rect})
+```
+
+The argument to `Evaluator` should be a mapping from variable names to their 
values. Or if you have access to the stack frame where `rect` is defined, you 
can instead use:
+
+```python
+evaluator = Evaluator.from_frame(frame)
+```
+
+Now to evaluate some nodes, using `evaluator[node]`:
+
+```python
+print("rect.width:", evaluator[the_tuple.elts[0]])
+print("rect:", evaluator[the_tuple.elts[0].value])
+```
+
+Output:
+
+```
+rect.width: 3
+rect: <__main__.Rectangle object at 0x105b0dd30>
+```
+
+OK, but you could have done the same thing with `eval`. The useful part is 
that it will refuse to evaluate the property `rect.area` because that would 
trigger unknown code. If we try, it'll raise a `CannotEval` exception.
+
+```python
+from pure_eval import CannotEval
+
+try:
+    print("rect.area:", evaluator[the_tuple.elts[2]])  # fails
+except CannotEval as e:
+    print(e)  # prints CannotEval
+```
+
+To find all the expressions that can be evaluated in a tree:
+
+```python
+for node, value in evaluator.find_expressions(tree):
+    print(ast.dump(node), value)
+```
+
+Output:
+
+```python
+Attribute(value=Name(id='rect', ctx=Load()), attr='width', ctx=Load()) 3
+Attribute(value=Name(id='rect', ctx=Load()), attr='height', ctx=Load()) 5
+Name(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>
+Name(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>
+Name(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>
+```
+
+Note that this includes `rect` three times, once for each appearance in the 
source code. Since all these nodes are equivalent, we can group them together:
+
+```python
+from pure_eval import group_expressions
+
+for nodes, values in group_expressions(evaluator.find_expressions(tree)):
+    print(len(nodes), "nodes with value:", values)
+```
+
+Output:
+
+```
+1 nodes with value: 3
+1 nodes with value: 5
+3 nodes with value: <__main__.Rectangle object at 0x10d374d30>
+```
+
+If we want to list all the expressions in a tree, we may want to filter out 
certain expressions whose values are obvious. For example, suppose we have a 
function `foo`:
+
+```python
+def foo():
+    pass
+```
+
+If we refer to `foo` by its name as usual, then that's not interesting:
+
+```python
+from pure_eval import is_expression_interesting
+
+node = ast.parse('foo').body[0].value
+print(ast.dump(node))
+print(is_expression_interesting(node, foo))
+```
+
+Output:
+
+```python
+Name(id='foo', ctx=Load())
+False
+```
+
+But if we refer to it by a different name, then it's interesting:
+
+```python
+node = ast.parse('bar').body[0].value
+print(ast.dump(node))
+print(is_expression_interesting(node, foo))
+```
+
+Output:
+
+```python
+Name(id='bar', ctx=Load())
+True
+```
+
+In general `is_expression_interesting` returns False for the following values:
+- Literals (e.g. `123`, `'abc'`, `[1, 2, 3]`, `{'a': (), 'b': ([1, 2], [3])}`)
+- Variables or attributes whose name is equal to the value's `__name__`, such 
as `foo` above or `self.foo` if it was a method.
+- Builtins (e.g. `len`) referred to by their usual name.
+
+To make things easier, you can combine finding expressions, grouping them, and 
filtering out the obvious ones with:
+
+```python
+evaluator.interesting_expressions_grouped(root)
+```
+
+To get the source code of an AST node, I recommend 
[asttokens](https://github.com/gristlabs/asttokens).
+
+Here's a complete example that brings it all together:
+
+```python
+from asttokens import ASTTokens
+from pure_eval import Evaluator
+
+source = """
+x = 1
+d = {x: 2}
+y = d[x]
+"""
+
+names = {}
+exec(source, names)
+atok = ASTTokens(source, parse=True)
+for nodes, value in 
Evaluator(names).interesting_expressions_grouped(atok.tree):
+    print(atok.get_text(nodes[0]), "=", value)
+```
+
+Output:
+
+```python
+x = 1
+d = {1: 2}
+y = 2
+d[x] = 2
+```
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/pure_eval.egg-info/SOURCES.txt 
new/pure_eval-0.2.2/pure_eval.egg-info/SOURCES.txt
--- old/pure_eval-0.2.1/pure_eval.egg-info/SOURCES.txt  2021-03-26 
16:18:03.000000000 +0100
+++ new/pure_eval-0.2.2/pure_eval.egg-info/SOURCES.txt  2022-01-22 
16:41:17.000000000 +0100
@@ -1,5 +1,4 @@
 .gitignore
-.travis.yml
 LICENSE.txt
 MANIFEST.in
 README.md
@@ -8,9 +7,11 @@
 setup.cfg
 setup.py
 tox.ini
+.github/workflows/pytest.yml
 pure_eval/__init__.py
 pure_eval/core.py
 pure_eval/my_getattr_static.py
+pure_eval/py.typed
 pure_eval/utils.py
 pure_eval/version.py
 pure_eval.egg-info/PKG-INFO
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/setup.cfg 
new/pure_eval-0.2.2/setup.cfg
--- old/pure_eval-0.2.1/setup.cfg       2021-03-26 16:18:03.483309000 +0100
+++ new/pure_eval-0.2.2/setup.cfg       2022-01-22 16:41:17.320512300 +0100
@@ -14,6 +14,7 @@
        Programming Language :: Python :: 3.7
        Programming Language :: Python :: 3.8
        Programming Language :: Python :: 3.9
+       Programming Language :: Python :: 3.10
        License :: OSI Approved :: MIT License
        Operating System :: OS Independent
 
@@ -22,11 +23,14 @@
 install_requires = 
 include_package_data = True
 tests_require = pytest
-setup_requires = setuptools>=44; wheel; setuptools_scm[toml]>=3.4.3
+setup_requires = setuptools>=44; setuptools_scm[toml]>=3.4.3
 
 [options.extras_require]
 tests = pytest
 
+[options.package_data]
+pure_eval = py.typed
+
 [egg_info]
 tag_build = 
 tag_date = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/tests/test_utils.py 
new/pure_eval-0.2.2/tests/test_utils.py
--- old/pure_eval-0.2.1/tests/test_utils.py     2021-03-26 14:22:14.000000000 
+0100
+++ new/pure_eval-0.2.2/tests/test_utils.py     2022-01-22 16:40:30.000000000 
+0100
@@ -17,6 +17,7 @@
     safe_name,
     typing_annotation_samples,
     is_standard_types,
+    ensure_dict,
 )
 
 
@@ -126,3 +127,10 @@
     assert is_standard_types(lst, deep=False, check_dict_values=True)
     assert is_standard_types(lst[0], deep=True, check_dict_values=True)
     assert not is_standard_types(lst, deep=True, check_dict_values=True)
+
+
+def test_ensure_dict():
+    assert ensure_dict({}) == {}
+    assert ensure_dict([]) == {}
+    assert ensure_dict('foo') == {}
+    assert ensure_dict({'a': 1}) == {'a': 1}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pure_eval-0.2.1/tox.ini new/pure_eval-0.2.2/tox.ini
--- old/pure_eval-0.2.1/tox.ini 2020-10-13 21:27:57.000000000 +0200
+++ new/pure_eval-0.2.2/tox.ini 2022-01-22 16:40:30.000000000 +0100
@@ -1,9 +1,8 @@
 [tox]
-envlist = py{35,36,37,38,39}
+envlist = py{35,36,37,38,39,310}
 
 [testenv]
 commands = pytest
-deps =
-    .[tests]
+extras = tests
 passenv =
     PURE_EVAL_SLOW_TESTS

Reply via email to