{
  "SPDXID": "SPDXRef-DOCUMENT",
  "name": "python-pure-eval-help-0.0.2.2-1.oe2403sp4.aarch64.rpm",
  "spdxVersion": "SPDX-2.2",
  "creationInfo": {
    "created": "2026-07-04T04:28:12.092529219Z",
    "creators": [
      "openeuler_creator"
    ]
  },
  "dataLicense": "CC0-1.0",
  "documentNamespace": "https://sbom.openEuler.org/python-pure-eval-help-0.0.2.2-1.oe2403sp4.aarch64.rpm",
  "packages": [
    {
      "SPDXID": "SPDXRef-rpm-python-pure-eval-help-0.2.2",
      "name": "python-pure-eval-help",
      "licenseConcluded": "MIT",
      "checksums": [
        {
          "algorithm": "SHA256",
          "checksumValue": "e205a9554a0ff98737bdcbbb0c7c754e85e06130d1ad9230ef270ceb5bb12b35"
        }
      ],
      "description": "\n\n[![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)\n\nThis is a Python package that lets you safely evaluate certain AST nodes without triggering arbitrary code that may have unwanted side effects.\n\nIt can be installed from PyPI:\n\n    pip install pure_eval\n\nTo demonstrate usage, suppose we have an object defined as follows:\n\n```python\nclass Rectangle:\n    def __init__(self, width, height):\n        self.width = width\n        self.height = height\n\n    @property\n    def area(self):\n        print(\"Calculating area...\")\n        return self.width * self.height\n\n\nrect = Rectangle(3, 5)\n```\n\nGiven the `rect` object, we want to evaluate whatever expressions we can in this source code:\n\n```python\nsource = \"(rect.width, rect.height, rect.area)\"\n```\n\nThis library works with the AST, so let's parse the source code and peek inside:\n\n```python\nimport ast\n\ntree = ast.parse(source)\nthe_tuple = tree.body[0].value\nfor node in the_tuple.elts:\n    print(ast.dump(node))\n```\n\nOutput:\n\n```python\nAttribute(value=Name(id='rect', ctx=Load()), attr='width', ctx=Load())\nAttribute(value=Name(id='rect', ctx=Load()), attr='height', ctx=Load())\nAttribute(value=Name(id='rect', ctx=Load()), attr='area', ctx=Load())\n```\n\nNow to actually use the library. First construct an Evaluator:\n\n```python\nfrom pure_eval import Evaluator\n\nevaluator = Evaluator({\"rect\": rect})\n```\n\nThe 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:\n\n```python\nevaluator = Evaluator.from_frame(frame)\n```\n\nNow to evaluate some nodes, using `evaluator[node]`:\n\n```python\nprint(\"rect.width:\", evaluator[the_tuple.elts[0]])\nprint(\"rect:\", evaluator[the_tuple.elts[0].value])\n```\n\nOutput:\n\n```\nrect.width: 3\nrect: <__main__.Rectangle object at 0x105b0dd30>\n```\n\nOK, 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.\n\n```python\nfrom pure_eval import CannotEval\n\ntry:\n    print(\"rect.area:\", evaluator[the_tuple.elts[2]])  # fails\nexcept CannotEval as e:\n    print(e)  # prints CannotEval\n```\n\nTo find all the expressions that can be evaluated in a tree:\n\n```python\nfor node, value in evaluator.find_expressions(tree):\n    print(ast.dump(node), value)\n```\n\nOutput:\n\n```python\nAttribute(value=Name(id='rect', ctx=Load()), attr='width', ctx=Load()) 3\nAttribute(value=Name(id='rect', ctx=Load()), attr='height', ctx=Load()) 5\nName(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>\nName(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>\nName(id='rect', ctx=Load()) <__main__.Rectangle object at 0x105568d30>\n```\n\nNote 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:\n\n```python\nfrom pure_eval import group_expressions\n\nfor nodes, values in group_expressions(evaluator.find_expressions(tree)):\n    print(len(nodes), \"nodes with value:\", values)\n```\n\nOutput:\n\n```\n1 nodes with value: 3\n1 nodes with value: 5\n3 nodes with value: <__main__.Rectangle object at 0x10d374d30>\n```\n\nIf 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`:\n\n```python\ndef foo():\n    pass\n```\n\nIf we refer to `foo` by its name as usual, then that's not interesting:\n\n```python\nfrom pure_eval import is_expression_interesting\n\nnode = ast.parse('foo').body[0].value\nprint(ast.dump(node))\nprint(is_expression_interesting(node, foo))\n```\n\nOutput:\n\n```python\nName(id='foo', ctx=Load())\nFalse\n```\n\nBut if we refer to it by a different name, then it's interesting:\n\n```python\nnode = ast.parse('bar').body[0].value\nprint(ast.dump(node))\nprint(is_expression_interesting(node, foo))\n```\n\nOutput:\n\n```python\nName(id='bar', ctx=Load())\nTrue\n```\n\nIn general `is_expression_interesting` returns False for the following values:\n- Literals (e.g. `123`, `'abc'`, `[1, 2, 3]`, `{'a': (), 'b': ([1, 2], [3])}`)\n- Variables or attributes whose name is equal to the value's `__name__`, such as `foo` above or `self.foo` if it was a method.\n- Builtins (e.g. `len`) referred to by their usual name.\n\nTo make things easier, you can combine finding expressions, grouping them, and filtering out the obvious ones with:\n\n```python\nevaluator.interesting_expressions_grouped(root)\n```\n\nTo get the source code of an AST node, I recommend [asttokens](https://github.com/gristlabs/asttokens).\n\nHere's a complete example that brings it all together:\n\n```python\nfrom asttokens import ASTTokens\nfrom pure_eval import Evaluator\n\nsource = \"\"\"\nx = 1\nd = {x: 2}\ny = d[x]\n\"\"\"\n\nnames = {}\nexec(source, names)\natok = ASTTokens(source, parse=True)\nfor nodes, value in Evaluator(names).interesting_expressions_grouped(atok.tree):\n    print(atok.get_text(nodes[0]), \"=\", value)\n```\n\nOutput:\n\n```python\nx = 1\nd = {1: 2}\ny = 2\nd[x] = 2\n```",
      "downloadLocation": "NOASSERTION",
      "externalRefs": [
        {
          "referenceCategory": "PACKAGE_MANAGER",
          "referenceLocator": "pkg:rpm/python-pure-eval-help@0.2.2-1.oe2403sp4?arch=noarch&epoch=0&upstream=python-pure-eval-0.2.2-1.oe2403sp4.src.rpm",
          "referenceType": "purl"
        }
      ],
      "filesAnalyzed": false,
      "homepage": "http://github.com/alexmojaki/pure_eval",
      "licenseDeclared": "MIT",
      "sourceInfo": "acquired package info from repodata DB: repodata/f1f85c23079e7764ad00378a9fc5d660b89a03657290e75426caf7be5b7da462-primary.sqlite.bz2",
      "summary": "Development documents and examples for pure-eval",
      "supplier": "Organization: http://openeuler.org",
      "versionInfo": "0:0.2.2-1.oe2403sp4"
    }
  ],
  "relationships": []
}
