diff --git a/.github/release_preamble.md b/.github/release_preamble.md new file mode 100644 index 00000000..15a37b12 --- /dev/null +++ b/.github/release_preamble.md @@ -0,0 +1,5 @@ +:information_source: Note that python-minifier depends on the python interpreter for parsing source code, +and will output source code compatible with the version of the interpreter it is run with. + +This means that if you minify code written for Python 3.11 using python-minifier running with Python 3.12, +the minified code may only run with Python 3.12. diff --git a/.github/workflows/create_draft_release.yaml b/.github/workflows/create_draft_release.yaml new file mode 100644 index 00000000..f0acb74f --- /dev/null +++ b/.github/workflows/create_draft_release.yaml @@ -0,0 +1,328 @@ +name: Create Draft Release + +on: + workflow_call: + inputs: + release_version: + description: The version to set in setup.py + required: true + type: string + outputs: + release_id: + description: The created release ID + value: ${{ jobs.create_release.outputs.release_id }} + +permissions: + contents: none + +jobs: + + package_python3: + name: Create sdist and Python 3 Wheel + runs-on: ubuntu-24.04 + outputs: + sdist: ${{ steps.package.outputs.sdist }} + wheel: ${{ steps.package.outputs.wheel }} + container: + image: danielflook/python-minifier-build:python3.14-2025-09-26 + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@v4.2.2 + with: + fetch-depth: 1 + show-progress: false + persist-credentials: false + + - name: Set version statically + env: + VERSION: ${{ inputs.release_version }} + run: | + python3 -c " + import re, os + version = os.environ['VERSION'] + + with open('setup.py', 'r') as f: + content = f.read() + + # Remove setuptools_scm configuration and set static version + content = re.sub(r'setup_requires=.*', f\"version='{version}',\", content) + content = re.sub(r'use_scm_version=.*,?\s*', '', content) + + with open('setup.py', 'w') as f: + f.write(content) + " + echo "Version: $VERSION" + + - name: Build distribution packages + id: package + run: | + pip3 install --upgrade build + python3 -m build + + echo "sdist=$(find dist -name '*.tar.gz' -printf "%f\n")" >> "$GITHUB_OUTPUT" + echo "wheel=$(find dist -name '*-py3-*.whl' -printf "%f\n")" >> "$GITHUB_OUTPUT" + + - name: Upload sdist artifact + uses: actions/upload-artifact@v4.4.3 + with: + name: dist-sdist + path: dist/${{ steps.package.outputs.sdist }} + if-no-files-found: error + + - name: Upload Python 3 wheel artifact + uses: actions/upload-artifact@v4.4.3 + with: + name: dist-py3-wheel + path: dist/${{ steps.package.outputs.wheel }} + if-no-files-found: error + + package_python2: + name: Create Python 2 Wheel + runs-on: ubuntu-24.04 + needs: [package_python3] + outputs: + wheel: ${{ steps.package.outputs.wheel }} + container: + image: danielflook/python-minifier-build:python2.7-2025-09-26 + steps: + - name: Download source distribution artifact + uses: actions/download-artifact@v4.1.8 + with: + name: dist-sdist + path: dist/ + + - name: Build Python 2 wheel + id: package + env: + PYTHON3_SDIST: ${{ needs.package_python3.outputs.sdist }} + run: | + dnf install -y findutils + pip install --upgrade wheel + pip wheel dist/"$PYTHON3_SDIST" -w dist + echo "wheel=$(find dist -name '*-py2-*.whl' -printf "%f\n")" >> "$GITHUB_OUTPUT" + + - name: Upload Python 2 wheel artifact + uses: actions/upload-artifact@v4.4.3 + with: + name: dist-py2-wheel + path: dist/${{ steps.package.outputs.wheel }} + if-no-files-found: error + + documentation: + name: Build Documentation + runs-on: ubuntu-24.04 + needs: [package_python3] + container: + image: danielflook/python-minifier-build:python3.14-2025-09-26 + permissions: + contents: read + steps: + - uses: actions/download-artifact@v4.1.8 + with: + name: dist-sdist + path: dist/ + + - name: Install package + env: + PYTHON3_SDIST: ${{ needs.package_python3.outputs.sdist }} + run: | + pip3 install dist/"$PYTHON3_SDIST" + pyminify --version + + - name: Checkout + uses: actions/checkout@v4.2.2 + with: + fetch-depth: 1 + show-progress: false + persist-credentials: false + + - name: Build documentation + run: | + pip3 install sphinx sphinxcontrib-programoutput sphinx_rtd_theme + sphinx-build docs/source /tmp/build + + - name: Upload documentation artifact + uses: actions/upload-pages-artifact@v3.0.1 + with: + path: /tmp/build + + test_package: + name: Test Package + runs-on: ubuntu-24.04 + needs: [package_python2, package_python3] + permissions: + contents: read + strategy: + fail-fast: false + matrix: + python: ["2.7", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + package_type: [sdist, wheel] + steps: + - name: Checkout + uses: actions/checkout@v4.2.2 + with: + fetch-depth: 1 + show-progress: false + persist-credentials: false + + - name: Download distribution artifacts + uses: actions/download-artifact@v4.1.8 + with: + pattern: dist-* + path: dist/ + merge-multiple: true + + - name: Test + uses: ./.github/actions/run-in-container + with: + image: danielflook/python-minifier-build:python${{ matrix.python }}-2025-09-26 + run: | + if [[ "${{ matrix.package_type }}" == "sdist" ]]; then + pip${{ matrix.python }} install dist/${{needs.package_python3.outputs.sdist}} + + # Extract sdist to access tests + mkdir -p /tmp/sdist-extract + cd /tmp/sdist-extract + tar -xzf /github/workspace/dist/${{needs.package_python3.outputs.sdist}} --strip-components=1 + + # Install test dependencies and package + pip${{ matrix.python }} install -r test/requirements.txt + + # Run unit tests from sdist + python${{ matrix.python }} -m pytest test/ -v + + elif [[ "${{ matrix.python }}" == "2.7" ]]; then + pip${{ matrix.python }} install dist/${{needs.package_python2.outputs.wheel}} + else + pip${{ matrix.python }} install dist/${{needs.package_python3.outputs.wheel}} + fi + + pyminify --version + + set -x + cat setup.py | pyminify - + pyminify setup.py > /tmp/out.min.py + pyminify setup.py --output /tmp/out.min.py2 + pyminify setup.py src test --in-place + + test_typing: + name: Test Typing + runs-on: ubuntu-24.04 + needs: [package_python3] + strategy: + matrix: + package_type: [sdist, wheel] + permissions: + contents: read + container: + image: danielflook/python-minifier-build:python3.14-2025-09-26 + steps: + - name: Download distribution artifacts + uses: actions/download-artifact@v4.1.8 + with: + pattern: dist-* + path: dist/ + merge-multiple: true + + - name: Install package + env: + PYTHON3_SDIST: ${{ needs.package_python3.outputs.sdist }} + PYTHON3_WHEEL: ${{ needs.package_python3.outputs.wheel }} + run: | + if [[ "${{ matrix.package_type }}" == "sdist" ]]; then + pip3.14 install "dist/$PYTHON3_SDIST" + else + pip3.14 install "dist/$PYTHON3_WHEEL" + fi + + - name: Checkout + uses: actions/checkout@v4.2.2 + with: + fetch-depth: 1 + show-progress: false + persist-credentials: false + + - name: Test typing + run: | + pip3.14 install 'mypy<1.12.0' types-setuptools + mypy --strict typing_test/test_typing.py + + if mypy --strict typing_test/test_badtyping.py; then + echo "Bad types weren't detected" + exit 1 + fi + + stubtest python_minifier --allowlist typing_test/stubtest-allowlist.txt + + create_release: + name: Create Draft Release + runs-on: ubuntu-24.04 + needs: + - package_python2 + - package_python3 + - documentation + - test_package + - test_typing + permissions: + contents: write + outputs: + release_id: ${{ steps.create_release.outputs.release_id }} + steps: + - name: Checkout + uses: actions/checkout@v4.2.2 + with: + fetch-depth: 1 + show-progress: false + persist-credentials: false + + - name: Generate Release Notes + run: | + cp .github/release_preamble.md release_body.md + + # Extract the topmost changelog section (first version found) + changelog_section=$(awk '/^## \[.*\]/{if(!found){found=1; next}} /^## \[.*\]/{if(found) exit} found' CHANGELOG.md) + if [ -z "$changelog_section" ]; then + echo "No changelog section found, using only release preamble" + else + echo "$changelog_section" >> release_body.md + fi + + - name: Create Draft Release + id: create_release + env: + VERSION: ${{ inputs.release_version }} + GH_TOKEN: ${{ github.token }} + run: | + set -e + release_url=$(gh release create "$VERSION" \ + --draft \ + --title "$VERSION" \ + --notes-file release_body.md) + echo "Draft release created: $release_url" + + # Extract the untagged release ID from the URL + untagged_id="${release_url##*/tag/}" + echo "release_id=$untagged_id" >> "$GITHUB_OUTPUT" + + - name: Download distribution artifacts + uses: actions/download-artifact@v4.1.8 + with: + pattern: dist-* + path: dist/ + merge-multiple: true + + - name: Upload Release Assets + env: + RELEASE_ID: ${{ steps.create_release.outputs.release_id }} + GH_TOKEN: ${{ github.token }} + SDIST: ${{ needs.package_python3.outputs.sdist }} + PYTHON3_WHEEL: ${{ needs.package_python3.outputs.wheel }} + PYTHON2_WHEEL: ${{ needs.package_python2.outputs.wheel }} + run: | + gh release upload "$RELEASE_ID" \ + --repo ${{ github.repository }} \ + "dist/${SDIST}" \ + "dist/${PYTHON3_WHEEL}" \ + "dist/${PYTHON2_WHEEL}" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5ccd5df5..7b66dc5a 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,8 +1,12 @@ name: Release on: - release: - types: [released] + workflow_dispatch: + inputs: + version: + description: 'Release version (e.g., 2.11.4)' + required: true + type: string concurrency: group: release @@ -13,135 +17,25 @@ permissions: jobs: - package_python3: - name: Create sdist and Python 3 Wheel - runs-on: ubuntu-24.04 - outputs: - sdist: ${{ steps.package.outputs.sdist }} - wheel: ${{ steps.package.outputs.wheel }} - container: - image: danielflook/python-minifier-build:python3.13-2024-09-15 + create_draft_release: + name: Create Draft Release + uses: ./.github/workflows/create_draft_release.yaml + if: github.ref == 'refs/heads/main' permissions: - contents: read - steps: - - name: Checkout - uses: actions/checkout@v4.2.2 - with: - fetch-depth: 1 - show-progress: false - persist-credentials: false - - - name: Set version statically - env: - VERSION: ${{ github.event.release.tag_name }} - run: | - sed -i "s/setup_requires=.*/version='$VERSION',/; s/use_scm_version=.*//" setup.py - echo "Version: $VERSION" - - - name: Build distribution packages - id: package - run: | - pip3 install --upgrade build - python3 -m build - - echo "sdist=$(find dist -name '*.tar.gz' -printf "%f\n")" >> "$GITHUB_OUTPUT" - echo "wheel=$(find dist -name '*-py3-*.whl' -printf "%f\n")" >> "$GITHUB_OUTPUT" - - - name: Upload sdist artifact - uses: actions/upload-artifact@v4.4.3 - with: - name: dist-sdist - path: dist/${{ steps.package.outputs.sdist }} - if-no-files-found: error - - - name: Upload Python 3 wheel artifact - uses: actions/upload-artifact@v4.4.3 - with: - name: dist-py3-wheel - path: dist/${{ steps.package.outputs.wheel }} - if-no-files-found: error - - package_python2: - name: Create Python 2 Wheel - runs-on: ubuntu-24.04 - needs: [package_python3] - outputs: - wheel: ${{ steps.package.outputs.wheel }} - container: - image: danielflook/python-minifier-build:python2.7-2024-09-15 - steps: - - name: Download source distribution artifact - uses: actions/download-artifact@v4.1.8 - with: - name: dist-sdist - path: dist/ - - - name: Build Python 2 wheel - id: package - env: - PYTHON3_SDIST: ${{ needs.package_python3.outputs.sdist }} - run: | - dnf install -y findutils - pip install --upgrade wheel - pip wheel dist/"$PYTHON3_SDIST" -w dist - echo "wheel=$(find dist -name '*-py2-*.whl' -printf "%f\n")" >> "$GITHUB_OUTPUT" - - - name: Upload Python 2 wheel artifact - uses: actions/upload-artifact@v4.4.3 - with: - name: dist-py2-wheel - path: dist/${{ steps.package.outputs.wheel }} - if-no-files-found: error + contents: write + with: + release_version: ${{ inputs.version }} - documentation: - name: Test Documentation - runs-on: ubuntu-24.04 - needs: [package_python3] - container: - image: danielflook/python-minifier-build:python3.13-2024-09-15 - permissions: - contents: read - steps: - - uses: actions/download-artifact@v4.1.8 - with: - name: dist-sdist - path: dist/ - - - name: Install package - env: - PYTHON3_SDIST: ${{ needs.package_python3.outputs.sdist }} - run: | - pip3 install dist/"$PYTHON3_SDIST" - pyminify --version - - - name: Checkout - uses: actions/checkout@v4.2.2 - with: - fetch-depth: 1 - show-progress: false - persist-credentials: false - - - name: Build documentation - run: | - pip3 install sphinx sphinxcontrib-programoutput sphinx_rtd_theme - sphinx-build docs/source /tmp/build - - - name: Upload documentation artifact - uses: actions/upload-pages-artifact@v3.0.1 - with: - path: /tmp/build - - publish-to-pypi: + publish_to_pypi: name: Publish to PyPI needs: - - package_python3 - - package_python2 + - create_draft_release runs-on: ubuntu-24.04 permissions: id-token: write environment: name: pypi - url: https://pypi.org/project/python-minifier/${{ github.event.release.tag_name }} + url: https://pypi.org/project/python-minifier/${{ inputs.version }} steps: - name: Download distribution artifacts uses: actions/download-artifact@v4.1.8 @@ -151,15 +45,15 @@ jobs: merge-multiple: true - name: Publish package distributions to PyPI - uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 + uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 with: print-hash: true verbose: true - publish-docs: + publish_docs: name: Publish Documentation needs: - - documentation + - create_draft_release runs-on: ubuntu-24.04 permissions: pages: write @@ -171,3 +65,22 @@ jobs: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4.0.5 + + publish_release: + name: Publish Release + needs: + - create_draft_release + - publish_to_pypi + - publish_docs + runs-on: ubuntu-24.04 + permissions: + contents: write + steps: + - name: Publish Release + env: + RELEASE_ID: ${{ needs.create_draft_release.outputs.release_id }} + GH_TOKEN: ${{ github.token }} + run: | + gh release edit "$RELEASE_ID" \ + --repo ${{ github.repository }} \ + --draft=false diff --git a/.github/workflows/release_test.yaml b/.github/workflows/release_test.yaml index 1c72b048..36c177dd 100644 --- a/.github/workflows/release_test.yaml +++ b/.github/workflows/release_test.yaml @@ -3,210 +3,41 @@ name: Release Test on: [push] permissions: - contents: read + contents: none jobs: - package_python3: - name: Create sdist and Python 3 Wheel + determine_version: + name: Determine Version runs-on: ubuntu-24.04 + permissions: + contents: read outputs: - sdist: ${{ steps.package.outputs.sdist }} - wheel: ${{ steps.package.outputs.wheel }} + release_version: ${{ steps.set_version.outputs.version }} container: - image: danielflook/python-minifier-build:python3.13-2024-09-15 + image: danielflook/python-minifier-build:python3.14-2025-09-26 steps: - name: Checkout uses: actions/checkout@v4.2.2 with: - fetch-depth: 1 + fetch-depth: 0 show-progress: false persist-credentials: false - - name: Set version statically + - name: Discover version + id: set_version run: | pip3 install setuptools_scm VERSION="$(python3 -m setuptools_scm)" - sed -i "s/setup_requires=.*/version='$VERSION',/; s/use_scm_version=.*//" setup.py echo "Version: $VERSION" - - - name: Build distribution packages - id: package - run: | - pip3 install --upgrade build - python3 -m build - - echo "sdist=$(find dist -name '*.tar.gz' -printf "%f\n")" >> "$GITHUB_OUTPUT" - echo "wheel=$(find dist -name '*-py3-*.whl' -printf "%f\n")" >> "$GITHUB_OUTPUT" - - - name: Upload sdist artifact - uses: actions/upload-artifact@v4.4.3 - with: - name: dist-sdist - path: dist/${{ steps.package.outputs.sdist }} - if-no-files-found: error - - - name: Upload Python 3 wheel artifact - uses: actions/upload-artifact@v4.4.3 - with: - name: dist-py3-wheel - path: dist/${{ steps.package.outputs.wheel }} - if-no-files-found: error - - package_python2: - name: Create Python 2 Wheel - runs-on: ubuntu-24.04 - needs: [package_python3] - outputs: - wheel: ${{ steps.package.outputs.wheel }} - container: - image: danielflook/python-minifier-build:python2.7-2024-09-15 - steps: - - name: Download source distribution artifact - uses: actions/download-artifact@v4.1.8 - with: - name: dist-sdist - path: dist/ - - - name: Build Python 2 wheel - id: package - env: - PYTHON3_SDIST: ${{ needs.package_python3.outputs.sdist }} - run: | - dnf install -y findutils - pip install --upgrade wheel - pip wheel "dist/$PYTHON3_SDIST" -w dist - echo "wheel=$(find dist -name '*-py2-*.whl' -printf "%f\n")" >> "$GITHUB_OUTPUT" - - - name: Upload Python 2 wheel artifact - uses: actions/upload-artifact@v4.4.3 - with: - name: dist-py2-wheel - path: dist/${{ steps.package.outputs.wheel }} - if-no-files-found: error - - documentation: - name: Test Documentation - runs-on: ubuntu-24.04 - needs: [package_python3] - container: - image: danielflook/python-minifier-build:python3.13-2024-09-15 - steps: - - uses: actions/download-artifact@v4.1.8 - with: - name: dist-sdist - path: dist/ - - - name: Install package - env: - PYTHON3_SDIST: ${{ needs.package_python3.outputs.sdist }} - run: | - pip3 install "dist/$PYTHON3_SDIST" - pyminify --version - - - name: Checkout - uses: actions/checkout@v4.2.2 - with: - fetch-depth: 1 - fetch-tags: true - show-progress: false - persist-credentials: false - - - name: Build documentation - run: | - pip3 install sphinx sphinxcontrib-programoutput sphinx_rtd_theme - sphinx-build docs/source /tmp/build - - test_package: - name: Test Package - runs-on: ubuntu-24.04 - needs: [package_python3, package_python2] - strategy: - fail-fast: false - matrix: - python: ["2.7", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] - package_type: [sdist, wheel] - steps: - - name: Checkout - uses: actions/checkout@v4.2.2 - with: - fetch-depth: 1 - fetch-tags: true - show-progress: false - persist-credentials: false - - - name: Download distribution artifacts - uses: actions/download-artifact@v4.1.8 - with: - pattern: dist-* - path: dist/ - merge-multiple: true - - - name: Test - uses: ./.github/actions/run-in-container - with: - image: danielflook/python-minifier-build:python${{ matrix.python }}-2024-09-15 - run: | - if [[ "${{ matrix.package_type }}" == "sdist" ]]; then - pip${{ matrix.python }} install dist/${{needs.package_python3.outputs.sdist}} - elif [[ "${{ matrix.python }}" == "2.7" ]]; then - pip${{ matrix.python }} install dist/${{needs.package_python2.outputs.wheel}} - else - pip${{ matrix.python }} install dist/${{needs.package_python3.outputs.wheel}} - fi - - pyminify --version - - set -x - cat setup.py | pyminify - - pyminify setup.py > /tmp/out.min.py - pyminify setup.py --output /tmp/out.min.py2 - pyminify setup.py src test --in-place - - test_typing: - name: Test Typing - runs-on: ubuntu-24.04 - needs: [package_python3] - strategy: - matrix: - package_type: [sdist, wheel] - container: - image: danielflook/python-minifier-build:python3.13-2024-09-15 - steps: - - name: Download distribution artifacts - uses: actions/download-artifact@v4.1.8 - with: - pattern: dist-* - path: dist/ - merge-multiple: true - - - name: Install package - env: - PYTHON3_SDIST: ${{ needs.package_python3.outputs.sdist }} - PYTHON3_WHEEL: ${{ needs.package_python3.outputs.wheel }} - run: | - if [[ "${{ matrix.package_type }}" == "sdist" ]]; then - pip3.13 install "dist/$PYTHON3_SDIST" - else - pip3.13 install "dist/$PYTHON3_WHEEL" - fi - - - name: Checkout - uses: actions/checkout@v4.2.2 - with: - fetch-depth: 1 - fetch-tags: true - show-progress: false - persist-credentials: false - - - name: Test typing - run: | - pip3.13 install 'mypy<1.12.0' types-setuptools - mypy --strict typing_test/test_typing.py - - if mypy --strict typing_test/test_badtyping.py; then - echo "Bad types weren't detected" - exit 1 - fi - - stubtest python_minifier --allowlist typing_test/stubtest-allowlist.txt + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + create_draft_release: + name: Create Draft Release + uses: ./.github/workflows/create_draft_release.yaml + needs: + - determine_version + permissions: + contents: write + with: + release_version: ${{ needs.determine_version.outputs.release_version }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 9e67b7ac..91f3cf89 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - python: ["python2.7", "python3.3", "python3.4", "python3.5", "python3.6", "python3.7", "python3.8", "python3.9", "python3.10", "python3.11", "python3.12", "python3.13", "pypy", "pypy3"] + python: ["python2.7", "python3.3", "python3.4", "python3.5", "python3.6", "python3.7", "python3.8", "python3.9", "python3.10", "python3.11", "python3.12", "python3.13", "python3.14", "pypy", "pypy3"] steps: - name: Checkout uses: actions/checkout@v4.2.2 @@ -30,7 +30,7 @@ jobs: - name: Run tests uses: ./.github/actions/run-in-container with: - image: danielflook/python-minifier-build:${{ matrix.python }}-2024-09-15 + image: danielflook/python-minifier-build:${{ matrix.python }}-2025-09-26 run: | tox -r -e $(echo "${{ matrix.python }}" | tr -d .) @@ -40,7 +40,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['2.7', '3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] + python-version: ['2.7', '3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14'] steps: - name: Checkout uses: actions/checkout@v4.2.2 @@ -50,11 +50,17 @@ jobs: persist-credentials: false - name: Set up Python - if: ${{ matrix.python-version != '2.7' }} + if: ${{ matrix.python-version != '2.7' && matrix.python-version != '3.14' }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + - name: Set up Python 3.14 + if: ${{ matrix.python-version == '3.14' }} + uses: actions/setup-python@v5 + with: + python-version: '3.14.0-rc.3' + - name: Set up Python if: ${{ matrix.python-version == '2.7' }} uses: LizardByte/actions/actions/setup_python@eddc8fc8b27048e25040e37e3585bd3ef9a968ed # master @@ -103,20 +109,20 @@ jobs: uvx zizmor --format plain . - name: Lint CHANGELOG - uses: DavidAnson/markdownlint-cli2-action@05f32210e84442804257b2a6f20b273450ec8265 # v19 + uses: DavidAnson/markdownlint-cli2-action@992badcdf24e3b8eb7e87ff9287fe931bcb00c6e # v20.0.0 with: config: '.config/changelog.markdownlint.yaml' globs: 'CHANGELOG.md' - name: Lint Other Markdown - uses: DavidAnson/markdownlint-cli2-action@05f32210e84442804257b2a6f20b273450ec8265 # v19 + uses: DavidAnson/markdownlint-cli2-action@992badcdf24e3b8eb7e87ff9287fe931bcb00c6e # v20.0.0 with: config: '.config/.markdownlint.yaml' globs: | **/README.md - name: Lint Python code - uses: astral-sh/ruff-action@9828f49eb4cadf267b40eaa330295c412c68c1f9 # v3 + uses: astral-sh/ruff-action@57714a7c8a2e59f32539362ba31877a1957dded1 # v3.5.1 with: args: --config=.config/ruff.toml check src: src @@ -135,6 +141,7 @@ jobs: - Dockerfile-fedora36 - Dockerfile-fedora38 - Dockerfile-fedora40 + - Dockerfile-fedora42 - Dockerfile-fuzz steps: - name: Checkout diff --git a/.github/workflows/test_corpus.yaml b/.github/workflows/test_corpus.yaml index 2bdb182d..7e95a4ae 100644 --- a/.github/workflows/test_corpus.yaml +++ b/.github/workflows/test_corpus.yaml @@ -44,7 +44,7 @@ jobs: strategy: fail-fast: false matrix: - python: ["2.7", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] + python: ["2.7", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] ref: ["${{ inputs.ref }}", "${{ inputs.base-ref }}"] steps: - name: Clear workspace @@ -72,7 +72,7 @@ jobs: - name: Run tests uses: dflook/run-in-container@main with: - image: danielflook/python-minifier-build:python${{ matrix.python }}-2024-09-15 + image: danielflook/python-minifier-build:python${{ matrix.python }}-2025-09-26 volumes: | /corpus:/corpus /corpus-results:/corpus-results @@ -143,11 +143,11 @@ jobs: - name: Generate Report uses: dflook/run-in-container@main with: - image: danielflook/python-minifier-build:python3.13-2024-09-15 + image: danielflook/python-minifier-build:python3.14-2025-09-26 volumes: | /corpus-results:/corpus-results run: | - python3.13 workflow/corpus_test/generate_report.py /corpus-results ${{ inputs.ref }} ${{ steps.ref.outputs.commit }} ${{ inputs.base-ref }} ${{ steps.base-ref.outputs.commit }} | tee -a $GITHUB_STEP_SUMMARY > report.md + python3.14 workflow/corpus_test/generate_report.py /corpus-results ${{ inputs.ref }} ${{ steps.ref.outputs.commit }} ${{ inputs.base-ref }} ${{ steps.base-ref.outputs.commit }} | tee -a $GITHUB_STEP_SUMMARY > report.md - name: Lint Report uses: DavidAnson/markdownlint-cli2-action@05f32210e84442804257b2a6f20b273450ec8265 # v19 diff --git a/.github/workflows/verify_release.yaml b/.github/workflows/verify_release.yaml index 32785814..cab2b903 100644 --- a/.github/workflows/verify_release.yaml +++ b/.github/workflows/verify_release.yaml @@ -17,9 +17,9 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - python: ["2.7", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] + python: ["2.7", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] container: - image: danielflook/python-minifier-build:python${{ matrix.python }}-2024-09-15 + image: danielflook/python-minifier-build:python${{ matrix.python }}-2025-09-26 steps: - name: Test env: diff --git a/.github/workflows/xtest.yaml b/.github/workflows/xtest.yaml index 738d6d19..02d50b9b 100644 --- a/.github/workflows/xtest.yaml +++ b/.github/workflows/xtest.yaml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - python: ["python2.7", "python3.3", "python3.4", "python3.5", "python3.6", "python3.7", "python3.8", "python3.9", "python3.10", "python3.11", "python3.12", "python3.13", "pypy3"] + python: ["python2.7", "python3.3", "python3.4", "python3.5", "python3.6", "python3.7", "python3.8", "python3.9", "python3.10", "python3.11", "python3.12", "python3.13", "python3.14", "pypy3"] steps: - name: Clear workspace run: rm -rf "${GITHUB_WORKSPACE:?}/*" @@ -33,7 +33,7 @@ jobs: - name: Run tests uses: ./.github/actions/run-in-container with: - image: danielflook/python-minifier-build:${{ matrix.python }}-2024-09-15 + image: danielflook/python-minifier-build:${{ matrix.python }}-2025-09-26 run: | if [[ "${{ matrix.python }}" == "python3.4" ]]; then @@ -46,6 +46,36 @@ jobs: tox -r -e $(echo "${{ matrix.python }}" | tr -d .) -- xtest + hypo_test: + name: Property Based Tests + runs-on: self-hosted + steps: + - name: Clear workspace + run: rm -rf "${GITHUB_WORKSPACE:?}/*" + + - name: Checkout + uses: actions/checkout@v4.2.2 + with: + fetch-depth: 1 + show-progress: false + persist-credentials: false + + - name: Set version statically + run: | + VERSION=0.0.0 + sed -i "s/setup_requires=.*/version='$VERSION',/; s/use_scm_version=.*//" setup.py + + - name: Run tests + uses: ./.github/actions/run-in-container + with: + image: danielflook/python-minifier-build:python3.14-2025-09-26 + run: | + + pip3.14 install . + pip3.14 install hypothesis pytest + + pytest hypo_test --hypothesis-show-statistics + test-corpus: needs: test name: Minify Corpus diff --git a/CHANGELOG.md b/CHANGELOG.md index fc5438a4..a4c98533 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,15 @@ and will output source code compatible with the version of the interpreter it is This means that if you minify code written for Python 3.11 using python-minifier running with Python 3.12, the minified code may only run with Python 3.12. +## [3.1.0] - 2025-10-11 + +### Added +- Python 3.14 support, including: + + PEP 750 Template strings (t-strings) + +### Fixed +- Failure to minify modules with special characters appearing in f-strings (e.g. null) + ## [3.0.0] - 2025-08-13 ### Fixed @@ -297,6 +306,7 @@ the minified code may only run with Python 3.12. - python-minifier package - pyminify command +[3.1.0]: https://github.com/dflook/python-minifier/compare/3.0.0...3.1.0 [3.0.0]: https://github.com/dflook/python-minifier/compare/2.11.3...3.0.0 [2.11.3]: https://github.com/dflook/python-minifier/compare/2.11.2...2.11.3 [2.11.2]: https://github.com/dflook/python-minifier/compare/2.11.1...2.11.2 diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..1d920f1d --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,21 @@ +include README.md +include LICENSE +include setup.py +graft src/python_minifier +graft test +exclude .gitignore +exclude tox.ini +exclude tox-windows.ini +exclude requirements-dev.txt +exclude CHANGELOG.md +prune .github +prune .config +prune docker +prune docs +prune corpus_test +prune hypo_test +prune typing_test +prune xtest +prune tox +global-exclude *.pyc +global-exclude __pycache__ diff --git a/README.md b/README.md index d7f62f22..9d0b685a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Transforms Python source code into its most compact representation. [Try it out!](https://python-minifier.com) -python-minifier currently supports Python 2.7 and Python 3.3 to 3.13. Previous releases supported Python 2.6. +python-minifier currently supports Python 2.7 and Python 3.3 to 3.14. Previous releases supported Python 2.6. * [PyPI](https://pypi.org/project/python-minifier/) * [Documentation](https://dflook.github.io/python-minifier/) diff --git a/corpus_test/generate_report.py b/corpus_test/generate_report.py index 76d70fb7..7da3fbbd 100644 --- a/corpus_test/generate_report.py +++ b/corpus_test/generate_report.py @@ -301,7 +301,7 @@ def report_larger_than_base(results_dir: str, python_versions: list[str], minifi yield f'| {entry.corpus_entry} | {entry.original_size} | {entry.minified_size} ({entry.minified_size - base_summary.entries[entry.corpus_entry].minified_size:+}) |' if not there_are_some_larger_than_base: - yield '| N/A | N/A | N/A |' + yield '| None | | |' def report_slowest(results_dir: str, python_versions: list[str], minifier_sha: str) -> str: @@ -350,8 +350,7 @@ def report(results_dir: str, minifier_ref: str, minifier_sha: str, base_ref: str :param base_sha: The git sha of the base version of python-minifier we are comparing against """ - yield f''' -# Python Minifier Test Report + yield f'''# Python Minifier Test Report Git Ref: {minifier_ref} Git Sha: {minifier_sha} @@ -365,7 +364,7 @@ def report(results_dir: str, minifier_ref: str, minifier_sha: str, base_ref: str | Python Version | Valid Corpus Entries | Average Time | Minified Size | Larger than original | Recursion Error | Unstable Minification | Exception | |----------------|---------------------:|-------------:|--------------:|---------------------:|----------------:|----------------------:|----------:|''' - for python_version in ['2.7', '3.3', '3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13']: + for python_version in ['2.7', '3.3', '3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14']: try: summary = result_summary(results_dir, python_version, minifier_sha) except FileNotFoundError: @@ -375,27 +374,39 @@ def report(results_dir: str, minifier_ref: str, minifier_sha: str, base_ref: str try: base_summary = result_summary(results_dir, python_version, base_sha) except FileNotFoundError: - base_summary = ResultSet(python_version, base_ref) - - mean_time_change = summary.mean_time - base_summary.mean_time - - yield ( - f'| {python_version} ' + - f'| {summary.valid_count} ' + - f'| {summary.mean_time:.3f} ({mean_time_change:+.3f}) ' + - f'| {format_size_change_detail(summary, base_summary)} ' + - f'| {format_difference(summary.larger_than_original(), base_summary.larger_than_original())} ' + - f'| {format_difference(summary.recursion_error(), base_summary.recursion_error())} ' + - f'| {format_difference(summary.unstable_minification(), base_summary.unstable_minification())} ' + - f'| {format_difference(summary.exception(), base_summary.exception())} |' - ) + base_summary = None + + if base_summary is None: + yield ( + f'| {python_version} ' + + f'| {summary.valid_count} ' + + f'| {summary.mean_time:.3f} ' + + f'| {summary.mean_percent_of_original:.3f}% ' + + f'| {len(list(summary.larger_than_original()))} ' + + f'| {len(list(summary.recursion_error()))} ' + + f'| {len(list(summary.unstable_minification()))} ' + + f'| {len(list(summary.exception()))} |' + ) + else: + mean_time_change = summary.mean_time - base_summary.mean_time + + yield ( + f'| {python_version} ' + + f'| {summary.valid_count} ' + + f'| {summary.mean_time:.3f} ({mean_time_change:+.3f}) ' + + f'| {format_size_change_detail(summary, base_summary)} ' + + f'| {format_difference(summary.larger_than_original(), base_summary.larger_than_original())} ' + + f'| {format_difference(summary.recursion_error(), base_summary.recursion_error())} ' + + f'| {format_difference(summary.unstable_minification(), base_summary.unstable_minification())} ' + + f'| {format_difference(summary.exception(), base_summary.exception())} |' + ) if ENHANCED_REPORT: - yield from report_larger_than_original(results_dir, ['3.13'], minifier_sha) + yield from report_larger_than_original(results_dir, ['3.14'], minifier_sha) yield from report_larger_than_base(results_dir, ['3.13'], minifier_sha, base_sha) - yield from report_slowest(results_dir, ['3.13'], minifier_sha) - yield from report_unstable(results_dir, ['2.7', '3.3', '3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13'], minifier_sha) - yield from report_exceptions(results_dir, ['2.7', '3.3', '3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13'], minifier_sha) + yield from report_slowest(results_dir, ['3.14'], minifier_sha) + yield from report_unstable(results_dir, ['2.7', '3.3', '3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14'], minifier_sha) + yield from report_exceptions(results_dir, ['2.7', '3.3', '3.4', '3.5', '3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14'], minifier_sha) def main(): diff --git a/docker/Dockerfile-fedora28 b/docker/Dockerfile-fedora28 index 33ee2832..5018c4ab 100644 --- a/docker/Dockerfile-fedora28 +++ b/docker/Dockerfile-fedora28 @@ -59,7 +59,7 @@ RUN < ast.AST: def to_node(n) -> ast.AST: if isinstance(n, int): - return ast.Num(n) if n >= 0 else ast.UnaryOp(ast.USub(), ast.Num(abs(n))) + return ast.Constant(value=n) if n >= 0 else ast.UnaryOp(ast.USub(), ast.Constant(value=abs(n))) elif isinstance(n, float): - return ast.Num(n) if math.copysign(1.0, n) > 0.0 else ast.UnaryOp(ast.USub(), ast.Num(abs(n))) + return ast.Constant(value=n) if math.copysign(1.0, n) > 0.0 else ast.UnaryOp(ast.USub(), ast.Constant(value=abs(n))) elif isinstance(n, complex): node = ast.parse(str(n), mode='eval') return node.body raise ValueError(n) - return to_node(draw(integers() | floats(allow_nan=False) | complex_numbers(allow_infinity=True, allow_nan=False))) + return to_node(draw(one_of( + integers(), # Shrinks to 0 + floats(allow_nan=False), # Shrinks to 0.0 + complex_numbers(allow_infinity=True, allow_nan=False) # Most complex + ))) @composite -def Str(draw) -> ast.Str: - return ast.Str(''.join(draw(lists(characters(), min_size=0, max_size=3)))) +def Str(draw) -> ast.Constant: + # Choose between simple and complex strings for better shrinking + use_simple = draw(booleans()) + + if use_simple: + # Simple ASCII strings that shrink well + s = draw(text(string.ascii_letters + string.digits + ' ', min_size=0, max_size=3)) + else: + # Complex unicode for thorough testing + # Only filter out surrogates which are invalid in Python strings + safe_chars = characters( + blacklist_categories=['Cs'], # No surrogates + max_codepoint=0xFFFF # Stay within BMP for simplicity + ) + s = ''.join(draw(lists(safe_chars, min_size=0, max_size=3))) + + return ast.Constant(value=s) @composite -def Bytes(draw) -> ast.Bytes: - return ast.Bytes(draw(binary(max_size=3))) +def Bytes(draw) -> ast.Constant: + return ast.Constant(value=draw(binary(max_size=3))) @composite @@ -88,40 +107,57 @@ def Set(draw, expression) -> ast.Set: @composite def Dict(draw, expression) -> ast.Dict: d = draw(dictionaries(expression, expression, min_size=0, max_size=3)) - return ast.Dict(keys=list(d.keys()), values=list(d.values())) + items = list(d.items()) # Get items as pairs to maintain key-value relationships + return ast.Dict(keys=[k for k, v in items], values=[v for k, v in items]) @composite -def NameConstant(draw) -> ast.NameConstant: - return ast.NameConstant(draw(sampled_from([None, True, False]))) +def NameConstant(draw) -> ast.Constant: + return ast.Constant(value=draw(sampled_from([None, False, True]))) # endregion @composite def name(draw) -> SearchStrategy: - other_id_start = [chr(i) for i in [0x1885, 0x1886, 0x2118, 0x212E, 0x309B, 0x309C]] - other_id_continue = [chr(i) for i in [0x00B7, 0x0387, 0x19DA] + list(range(1369, 1371 + 1))] - - xid_start = draw(characters(whitelist_categories=['Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl'], whitelist_characters=['_'] + other_id_start, blacklist_characters=' ')) - xid_continue = draw( - lists( - characters(whitelist_categories=['Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl', 'Mn', 'Mc', 'Nd', 'Pc'], whitelist_characters=['_'] + other_id_start + other_id_continue, blacklist_characters=' '), - min_size=0, - max_size=2 + # Choose between simple and complex, but in a way that shrinks to simple + use_unicode = draw(booleans()) + + if not use_unicode: + # Simple ASCII names (will be the shrunk case) + first = draw(sampled_from(string.ascii_letters + '_')) + rest = draw(text(string.ascii_letters + string.digits + '_', min_size=0, max_size=2)) + n = first + rest + else: + # Complex unicode names (for thorough testing) + other_id_start = [chr(i) for i in [0x1885, 0x1886, 0x2118, 0x212E, 0x309B, 0x309C]] + other_id_continue = [chr(i) for i in [0x00B7, 0x0387, 0x19DA] + list(range(1369, 1371 + 1))] + + xid_start = draw(characters(whitelist_categories=['Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl'], + whitelist_characters=['_'] + other_id_start, + blacklist_characters=' ')) + xid_continue = draw( + lists( + characters(whitelist_categories=['Lu', 'Ll', 'Lt', 'Lm', 'Lo', 'Nl', 'Mn', 'Mc', 'Nd', 'Pc'], + whitelist_characters=['_'] + other_id_start + other_id_continue, + blacklist_characters=' '), + min_size=0, + max_size=2 + ) ) - ) + n = xid_start + ''.join(xid_continue) + n = unicodedata.normalize('NFKC', n) - n = xid_start + ''.join(xid_continue) + # Handle keywords by prefixing with underscore + if n in keyword.kwlist: + return '_' + n - normalised = unicodedata.normalize('NFKC', n) - assume(normalised not in keyword.kwlist) - assume(' ' not in normalised) - try: - ast.parse(normalised, mode='eval') - except Exception: + # Validate it's a proper identifier + if not n.isidentifier(): + # Shouldn't happen with our generation, but just in case assume(False) - return normalised + + return n @composite @@ -131,7 +167,7 @@ def Name(draw, ctx=ast.Load) -> ast.Name: @composite def UnaryOp(draw, expression) -> ast.UnaryOp: - op = draw(sampled_from([ast.USub(), ast.UAdd(), ast.Not(), ast.Invert()])) + op = draw(sampled_from([ast.UAdd(), ast.USub(), ast.Not(), ast.Invert()])) l = draw(expression) return ast.UnaryOp(op, l) @@ -152,20 +188,19 @@ def BinOp(draw, expression) -> ast.BinOp: op = draw( sampled_from( [ - ast.Add(), + ast.Add(), # Most common arithmetic ast.Sub(), ast.Mult(), ast.Div(), + ast.Mod(), # Common operations ast.FloorDiv(), - ast.Mod(), - ast.Pow(), - ast.LShift(), - ast.RShift(), + ast.Pow(), # Less common + ast.BitAnd(), # Bitwise operations ast.BitOr(), ast.BitXor(), - ast.BitOr(), - ast.BitAnd(), - ast.MatMult() + ast.LShift(), + ast.RShift(), + ast.MatMult() # Least common (matrix mult) ] ) ) @@ -209,7 +244,8 @@ def IfExp(draw, expression) -> ast.IfExp: @composite def Attribute(draw, expression) -> ast.Attribute: value = draw(expression) - attr = draw(text(alphabet=string.ascii_letters, min_size=1, max_size=3).filter(lambda n: n not in keyword.kwlist)) + # Use our improved name strategy for attributes too + attr = draw(name()) return ast.Attribute(value, attr, ast.Load()) @composite @@ -229,7 +265,7 @@ def Await(draw, expression) -> ast.Await: @composite def Index(draw, expression) -> ast.Index: - return ast.Index(draw(Ellipsis() | expression)) + return ast.Index(draw(one_of(Ellipsis(), expression))) @composite @@ -237,13 +273,13 @@ def Slice(draw, expression) -> ast.Slice: return ast.Slice( lower=draw(expression), upper=draw(expression), - step=draw(none() | expression) + step=draw(one_of(none(), expression)) ) @composite -def Ellipsis(draw) -> ast.Ellipsis: - return ast.Ellipsis() +def Ellipsis(draw) -> ast.Constant: + return ast.Constant(value=...) @composite @@ -266,7 +302,7 @@ def ExtSlice(draw, expression) -> ast.ExtSlice: def Subscript(draw, expression, ctx=ast.Load) -> ast.Subscript: return ast.Subscript( value=draw(expression), - slice=draw(Index(expression) | Slice(expression) | ExtSlice(expression)), + slice=draw(one_of(Index(expression), Slice(expression), ExtSlice(expression))), ctx=ctx() ) @@ -275,7 +311,7 @@ def Subscript(draw, expression, ctx=ast.Load) -> ast.Subscript: def arg(draw, allow_annotation=True) -> ast.arg: if allow_annotation: - annotation = draw(none() | expression()) + annotation = draw(one_of(none(), expression())) else: annotation = None @@ -293,10 +329,10 @@ def arguments(draw, for_lambda=False) -> ast.arguments: args = draw(lists(arg(allow_annotation), max_size=2)) posonlyargs = draw(lists(arg(allow_annotation), max_size=2)) kwonlyargs = draw(lists(arg(allow_annotation), max_size=2)) - vararg = draw(none() | arg(allow_annotation)) - kwarg = draw(none() | arg(allow_annotation)) + vararg = draw(one_of(none(), arg(allow_annotation))) + kwarg = draw(one_of(none(), arg(allow_annotation))) defaults = [] - kw_defaults = draw(lists(none() | expression(), max_size=len(kwonlyargs), min_size=len(kwonlyargs))) + kw_defaults = draw(lists(one_of(none(), expression()), max_size=len(kwonlyargs), min_size=len(kwonlyargs))) return ast.arguments( posonlyargs=posonlyargs, args=args, @@ -359,68 +395,87 @@ def DictComp(draw, expression) -> ast.DictComp: ) -leaves = NameConstant() | \ - Name() | \ - Num() | \ - Str() | \ - Bytes() +leaves = one_of( + NameConstant(), + Name(), + Num(), + Str(), + Bytes() +) + + +# Group related operations for better recursive structure +def binary_operations(expr): + """Simple binary and comparison operations""" + return one_of( + BinOp(expr), + Compare(expr), + BoolOp(expr), + UnaryOp(expr) + ) + +def collections(expr): + """Collection types""" + return one_of( + List(expr), + Tuple(expr), + Set(expr), + Dict(expr) + ) + +def calls_and_access(expr): + """Function calls and member access""" + return one_of( + Call(expr), + Attribute(expr), + Subscript(expr) + ) + +def control_flow(expr): + """Control flow expressions""" + return one_of( + IfExp(expr), + Yield(expr), + YieldFrom(expr) + ) + +def comprehensions(expr): + """List/dict/generator comprehensions""" + return one_of( + ListComp(expr), + DictComp(expr), + GeneratorExp(expr) + ) def async_expression() -> SearchStrategy: return recursive( leaves, - lambda expression: - one_of( - Yield(expression), - YieldFrom(expression), - Await(expression), - IfExp(expression), - Call(expression), - BinOp(expression), - Set(expression), - List(expression), - Tuple(expression), - BoolOp(expression), - UnaryOp(expression), - Attribute(expression), - Dict(expression), - Compare(expression), - Lambda(expression), - ListComp(expression), - GeneratorExp(expression), - DictComp(expression), - Subscript(expression) + lambda expression: one_of( + binary_operations(expression), + collections(expression), + calls_and_access(expression), + control_flow(expression), + comprehensions(expression), + Await(expression), # Async-specific + Lambda(expression) # Complex case ), - max_leaves=150 + max_leaves=50 ) def expression() -> SearchStrategy: return recursive( leaves, - lambda expression: - one_of( - Yield(expression), - YieldFrom(expression), - # Await(expression), - IfExp(expression), - Call(expression), - BinOp(expression), - Set(expression), - List(expression), - Tuple(expression), - BoolOp(expression), - UnaryOp(expression), - Attribute(expression), - Dict(expression), - Compare(expression), - Lambda(expression), - ListComp(expression), - GeneratorExp(expression), - DictComp(expression), - Subscript(expression) + lambda expression: one_of( + binary_operations(expression), + collections(expression), + calls_and_access(expression), + control_flow(expression), + comprehensions(expression), + Lambda(expression) # Complex case ), - max_leaves=150 + max_leaves=50 ) diff --git a/hypo_test/folding.py b/hypo_test/folding.py index 9c43b6ff..94603546 100644 --- a/hypo_test/folding.py +++ b/hypo_test/folding.py @@ -1,10 +1,13 @@ -import ast +import python_minifier.ast_compat as ast -from hypothesis.strategies import SearchStrategy, composite, lists, recursive, sampled_from +from hypothesis.strategies import SearchStrategy, composite, lists, one_of, recursive, sampled_from from .expressions import NameConstant, Num -leaves = NameConstant() | Num() +leaves = one_of( + NameConstant(), + Num() +) @composite @@ -12,19 +15,19 @@ def BinOp(draw, expression) -> ast.BinOp: op = draw( sampled_from( [ - ast.Add(), + ast.Add(), # Most common arithmetic ast.Sub(), ast.Mult(), ast.Div(), + ast.Mod(), # Common operations ast.FloorDiv(), - ast.Mod(), - ast.Pow(), - ast.LShift(), - ast.RShift(), + ast.Pow(), # Less common + ast.BitAnd(), # Bitwise operations ast.BitOr(), ast.BitXor(), - ast.BitAnd(), - ast.MatMult() + ast.LShift(), + ast.RShift(), + ast.MatMult() # Least common (matrix mult) ] ) ) diff --git a/hypo_test/module.py b/hypo_test/module.py index 9d066a38..14160c46 100644 --- a/hypo_test/module.py +++ b/hypo_test/module.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast from hypothesis import assume from hypothesis.strategies import SearchStrategy, booleans, composite, integers, lists, none, one_of, recursive, sampled_from @@ -23,20 +23,19 @@ def AugAssign(draw): op = draw( sampled_from( [ - ast.Add(), + ast.Add(), # Most common arithmetic ast.Sub(), ast.Mult(), ast.Div(), + ast.Mod(), # Common operations ast.FloorDiv(), - ast.Mod(), - ast.Pow(), - ast.LShift(), - ast.RShift(), + ast.Pow(), # Less common + ast.BitAnd(), # Bitwise operations ast.BitOr(), ast.BitXor(), - ast.BitOr(), - ast.BitAnd(), - ast.MatMult() + ast.LShift(), + ast.RShift(), + ast.MatMult() # Least common (matrix mult) ] ) ) @@ -51,7 +50,7 @@ def Print(draw): @composite def Raise(draw): - return ast.Raise(draw(none() | expression()), cause=None) + return ast.Raise(draw(one_of(none(), expression())), cause=None) @composite @@ -81,14 +80,16 @@ def Continue(draw) -> ast.Continue: @composite def With(draw, statements) -> ast.With: - items = draw(lists(expression(), min_size=1, max_size=3)) + # Tuples cannot be context expressions - they parse as multiple withitems + items = draw(lists(expression().filter(lambda e: not isinstance(e, ast.Tuple)), min_size=1, max_size=3)) body = draw(lists(statements, min_size=1, max_size=3)) return ast.With([ast.withitem(context_expr=i, optional_vars=None) for i in items], body) @composite def AsyncWith(draw, statements) -> ast.AsyncWith: - items = draw(lists(expression(), min_size=1, max_size=3)) + # Tuples cannot be context expressions - they parse as multiple withitems + items = draw(lists(expression().filter(lambda e: not isinstance(e, ast.Tuple)), min_size=1, max_size=3)) body = draw(lists(statements, min_size=1, max_size=3)) return ast.AsyncWith([ast.withitem(context_expr=i, optional_vars=None) for i in items], body) @@ -102,7 +103,7 @@ def If(draw, statements) -> ast.If: @composite def ExceptHandler(draw, statements) -> ast.ExceptHandler: - t = draw(none() | Name()) + t = draw(one_of(none(), Name())) n = None if t is not None: @@ -181,7 +182,7 @@ def Nonlocal(draw) -> ast.Nonlocal: @composite def alias(draw) -> ast.alias: - return ast.alias(name=draw(name()), asname=draw(none() | name())) + return ast.alias(name=draw(name()), asname=draw(one_of(none(), name()))) @composite @@ -202,7 +203,7 @@ def ImportFrom(draw) -> ast.ImportFrom: def TypeVar(draw) -> ast.TypeVar: return ast.TypeVar( name=draw(name()), - bound=draw(none() | expression()) + bound=draw(one_of(none(), expression())) ) @@ -232,7 +233,7 @@ def FunctionDef(draw, statements) -> ast.FunctionDef: body = draw(lists(statements, min_size=1, max_size=3)) decorator_list = draw(lists(Name(), min_size=0, max_size=2)) type_params = draw(lists(one_of(TypeVar(), TypeVarTuple(), ParamSpec()), min_size=0, max_size=3)) - returns = draw(none() | expression()) + returns = draw(one_of(none(), expression())) return ast.FunctionDef(n, args, body, decorator_list, returns, type_params=type_params) @@ -243,7 +244,7 @@ def AsyncFunctionDef(draw, statements) -> ast.AsyncFunctionDef: body = draw(lists(statements, min_size=1, max_size=3)) decorator_list = draw(lists(Name(), min_size=0, max_size=2)) type_params = draw(lists(one_of(TypeVar(), TypeVarTuple(), ParamSpec()), min_size=0, max_size=3)) - returns = draw(none() | expression()) + returns = draw(one_of(none(), expression())) return ast.AsyncFunctionDef(n, args, body, decorator_list, returns, type_params=type_params) @@ -261,7 +262,14 @@ def ClassDef(draw, statements) -> ast.ClassDef: bases = draw(lists(expression(), min_size=0, max_size=2)) keywords = draw(lists(keyword(), min_size=0, max_size=2)) - assume(len({kw.arg for kw in keywords}) == len(keywords)) + # Remove duplicate keyword names + seen_args = set() + unique_keywords = [] + for kw in keywords: + if kw.arg not in seen_args: + seen_args.add(kw.arg) + unique_keywords.append(kw) + keywords = unique_keywords body = draw(lists(statements, min_size=1, max_size=3)) decorator_list = draw(lists(Name(), min_size=0, max_size=2)) @@ -277,39 +285,38 @@ def ClassDef(draw, statements) -> ast.ClassDef: if hasattr(ast, 'Print'): simple_statements = one_of( - Pass(), - Break(), + Pass(), # Simplest - no operation + Break(), # Simple control flow Continue(), - Global(), + Global(), # Simple declarations Nonlocal(), - Expr(), - Assert(), - Print(), - Raise(), - # Delete() | - Assign(), - AnnAssign(), + Expr(), # Expression statement + Assign(), # Simple assignments AugAssign(), - Import(), + AnnAssign(), # Type annotations + Print(), # Python 2 print statement + Assert(), # More complex statements + Raise(), + Import(), # Import statements ImportFrom() + # Delete() - commented out ) else: simple_statements = one_of( - Pass(), - Break(), + Pass(), # Simplest - no operation + Break(), # Simple control flow Continue(), - Global(), + Global(), # Simple declarations Nonlocal(), - Expr(), - Assert(), - Raise(), - # Delete() | - Assign(), - AnnAssign(), + Expr(), # Expression statement + Assign(), # Simple assignments AugAssign(), - Import(), + AnnAssign(), # Type annotations + Assert(), # More complex statements + Raise(), + Import(), # Import statements ImportFrom(), - TypeAlias() + TypeAlias() # Most complex ) @@ -318,16 +325,16 @@ def suite() -> SearchStrategy: simple_statements, lambda statements: one_of( - With(statements), + If(statements), # Simple conditional + While(statements), # Simple loop + For(statements), # Loop with iteration + With(statements), # Context manager + FunctionDef(statements), # Function definition + AsyncFor(statements), # Async variants AsyncWith(statements), - If(statements), - For(statements), - AsyncFor(statements), - While(statements), - FunctionDef(statements), AsyncFunctionDef(statements), - ClassDef(statements), - Try(statements) + Try(statements), # Complex exception handling + ClassDef(statements) # Most complex ), max_leaves=100 ) @@ -335,5 +342,5 @@ def suite() -> SearchStrategy: @composite def Module(draw) -> ast.Module: - b = draw(lists(suite(), min_size=1, max_size=10)) + b = draw(lists(suite(), min_size=1, max_size=3)) return ast.Module(body=b, type_ignores=[]) diff --git a/hypo_test/patterns.py b/hypo_test/patterns.py index c4cf4270..7fef56ab 100644 --- a/hypo_test/patterns.py +++ b/hypo_test/patterns.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast import keyword import string @@ -8,9 +8,12 @@ @composite def name(draw): + # Generate simple ASCII names that avoid keywords n = draw(text(alphabet=string.ascii_letters, min_size=1, max_size=3)) - assume(n not in keyword.kwlist) + # Handle keywords by prefixing with underscore instead of filtering + if n in keyword.kwlist: + return '_' + n return n @@ -47,7 +50,7 @@ def MatchSequence(draw, pattern) -> ast.MatchSequence: def MatchMapping(draw, pattern) -> ast.MatchMapping: l = draw(lists(pattern, min_size=1, max_size=3)) - match_mapping = ast.MatchMapping(keys=[ast.Num(0) for i in range(len(l))], patterns=l) + match_mapping = ast.MatchMapping(keys=[ast.Constant(value=0) for i in range(len(l))], patterns=l) has_star = draw(booleans()) if has_star: @@ -73,7 +76,7 @@ def MatchClass(draw, pattern) -> ast.MatchClass: @composite def MatchAs(draw, pattern) -> ast.MatchAs: - n = draw(none() | name()) + n = draw(one_of(none(), name())) if n is None: p = None @@ -89,7 +92,10 @@ def MatchOr(draw, pattern) -> ast.MatchOr: return ast.MatchOr(patterns=l) -leaves = MatchValue() | MatchSingleton() +leaves = one_of( + MatchValue(), + MatchSingleton() +) def pattern(): @@ -97,13 +103,13 @@ def pattern(): leaves, lambda pattern: one_of( - MatchSequence(pattern), - MatchMapping(pattern), - MatchClass(pattern), - MatchAs(pattern), - MatchOr(pattern) + MatchAs(pattern), # Simplest - just name binding + MatchSequence(pattern), # Simple sequence patterns + MatchOr(pattern), # Alternative patterns + MatchMapping(pattern), # Dictionary-like patterns + MatchClass(pattern) # Most complex - class patterns ), - max_leaves=150 + max_leaves=50 ) diff --git a/hypo_test/strings.py b/hypo_test/strings.py new file mode 100644 index 00000000..59d688c2 --- /dev/null +++ b/hypo_test/strings.py @@ -0,0 +1,467 @@ +import ast + +from hypothesis import assume +from hypothesis.strategies import ( + SearchStrategy, + booleans, + composite, + integers, + one_of, + recursive, + sampled_from +) + +from .expressions import Name, Str, Bytes + +simple_strings = ['x', 'ab', 'test', 'hello'] +simple_strings_with_empty = ['', 'x', 'ab', 'test', 'hello'] # For parts that can be empty + + +@composite +def format_spec_string(draw) -> str: + """Generate valid format specification strings""" + format_specs = [ + '', # no format spec + 'd', # integer + 'f', # float + '.2f', # float with precision + 's', # string + 'x', # hex + 'o', # octal + 'b', # binary + '010d', # zero-padded integer + '.3s', # truncated string + '>10', # right-aligned + '<10', # left-aligned + '^10', # centered + ] + return draw(sampled_from(format_specs)) + + +# region: f-string + +@composite +def FormattedValue(draw, expression) -> ast.FormattedValue: + """Generate FormattedValue nodes for f-strings""" + value = draw(expression) + + # Conversion: -1 (no conversion), 115 ('s'), 114 ('r'), 97 ('a') + conversion = draw(sampled_from([-1, 115, 114, 97])) + + format_spec_choice = draw(sampled_from(['none', 'empty_spec', 'string_spec', 'nested'])) + + if format_spec_choice == 'none': + format_spec = None + elif format_spec_choice == 'empty_spec': + # Empty format spec: f"{x:}" + format_spec = ast.JoinedStr(values=[]) + elif format_spec_choice == 'string_spec': + # Simple string format spec: f"{x:d}", f"{x:.2f}" + spec_string = draw(format_spec_string()) + if spec_string: # Only create if non-empty + format_spec = ast.JoinedStr(values=[ast.Constant(value=spec_string)]) + else: + format_spec = ast.JoinedStr(values=[]) + else: + # Nested format spec - but constrain it to realistic patterns + # Valid nested format specs have patterns like: + # - f"{x:{width}}" -> format_spec=JoinedStr(values=[FormattedValue]) + # - f"{x:.{prec}f}" -> format_spec=JoinedStr(values=[Constant('.'), FormattedValue, Constant('f')]) + # - f"{x:>{width}}" -> format_spec=JoinedStr(values=[Constant('>'), FormattedValue]) + + pattern_choice = draw(sampled_from(['simple_var', 'alignment_var', 'precision_var'])) + + if pattern_choice == 'simple_var': + # Just a variable: {width} + format_spec = ast.JoinedStr(values=[ + ast.FormattedValue( + value=draw(one_of(string_leaves, simple_joined_str(expression), simple_template_str(expression))), + conversion=-1, + format_spec=None + ) + ]) + elif pattern_choice == 'alignment_var': + # Alignment + variable: >{width} or <{width} or ^{width} + align_char = draw(sampled_from(['>', '<', '^'])) + format_spec = ast.JoinedStr(values=[ + ast.Constant(value=align_char), + ast.FormattedValue( + value=draw(one_of(string_leaves, simple_joined_str(expression), simple_template_str(expression))), + conversion=-1, + format_spec=None + ) + ]) + else: # precision_var + # Precision pattern: .{prec}f or .{prec}d + type_char = draw(sampled_from(['f', 'd', 's', 'x'])) + format_spec = ast.JoinedStr(values=[ + ast.Constant(value='.'), + ast.FormattedValue( + value=draw(one_of(string_leaves, simple_joined_str(expression), simple_template_str(expression))), + conversion=-1, + format_spec=None + ), + ast.Constant(value=type_char) + ]) + + return ast.FormattedValue( + value=value, + conversion=conversion, + format_spec=format_spec + ) + + +@composite +def simple_joined_str(draw, expression) -> ast.JoinedStr: + """Generate simple JoinedStr nodes to avoid infinite recursion""" + + pattern_type = draw(sampled_from([ + 'constant_only', # f"text" + 'formatted_only', # f"{expr}" or f"{expr1}{expr2}" + 'simple_mixed' # f"text{expr}" or f"{expr}text" + ])) + + if pattern_type == 'constant_only': + return ast.JoinedStr(values=[ + ast.Constant(value=draw(sampled_from(simple_strings))) + ]) + + elif pattern_type == 'formatted_only': + num_formatted = draw(integers(min_value=1, max_value=2)) + values = [] + for _ in range(num_formatted): + expr = draw(expression) + values.append(ast.FormattedValue( + value=expr, + conversion=-1, + format_spec=None + )) + return ast.JoinedStr(values=values) + + else: # simple_mixed + # Either "text{expr}" or "{expr}text" + values = [] + if draw(booleans()): + # "text{expr}" + const_val = draw(sampled_from(simple_strings_with_empty)) + if const_val: # Python omits empty string constants + values.append(ast.Constant(value=const_val)) + values.append(ast.FormattedValue( + value=draw(expression), + conversion=-1, + format_spec=None + )) + else: + # "{expr}text" + values.append(ast.FormattedValue( + value=draw(expression), + conversion=-1, + format_spec=None + )) + const_val = draw(sampled_from(simple_strings_with_empty)) + if const_val: # Python omits empty string constants + values.append(ast.Constant(value=const_val)) + return ast.JoinedStr(values=values) + + +@composite +def JoinedStr(draw, expression) -> ast.JoinedStr: + """ + Valid patterns: + - f"" → JoinedStr(values=[]) + - f"text" → JoinedStr(values=[Constant]) + - f"{expr}" → JoinedStr(values=[FormattedValue]) + - f"text{expr}" → JoinedStr(values=[Constant, FormattedValue]) + - f"{expr}text" → JoinedStr(values=[FormattedValue, Constant]) + - f"a{expr}b{expr2}c" → JoinedStr(values=[Constant, FormattedValue, Constant, FormattedValue, Constant]) + """ + + pattern_type = draw(sampled_from([ + 'empty', # f"" + 'constant_only', # f"text" + 'formatted_only', # f"{expr}" + 'mixed' # f"text{expr}..." + ])) + + if pattern_type == 'empty': + return ast.JoinedStr(values=[]) + + elif pattern_type == 'constant_only': + return ast.JoinedStr(values=[ + ast.Constant(value=draw(sampled_from(simple_strings))) + ]) + + elif pattern_type == 'formatted_only': + num_formatted = draw(integers(min_value=1, max_value=3)) + values = [] + for _ in range(num_formatted): + values.append(draw(FormattedValue(expression))) + return ast.JoinedStr(values=values) + + else: # mixed + values = [] + + starts_with_constant = draw(booleans()) + num_formatted = draw(integers(min_value=1, max_value=2)) + + if starts_with_constant: + const_val = draw(sampled_from(simple_strings_with_empty)) + if const_val: # Python omits empty string constants + values.append(ast.Constant(value=const_val)) + + for i in range(num_formatted): + values.append(draw(FormattedValue(expression))) + # Optionally add a constant after each formatted value (except maybe the last) + if i < num_formatted - 1 or draw(booleans()): + const_val = draw(sampled_from(simple_strings_with_empty)) + if const_val: # Python omits empty string constants + values.append(ast.Constant(value=const_val)) + + return ast.JoinedStr(values=values) + + +# endregion + + +# region: t-string + +@composite +def Interpolation(draw, expression) -> 'ast.Interpolation': + """Generate Interpolation nodes for t-strings""" + value = draw(expression) + + # Conversion: -1 (no conversion), 115 ('s'), 114 ('r'), 97 ('a') + conversion = draw(sampled_from([-1, 115, 114, 97])) + + format_spec_choice = draw(sampled_from(['none', 'empty_spec', 'string_spec', 'nested'])) + + if format_spec_choice == 'none': + format_spec = None + elif format_spec_choice == 'empty_spec': + # Empty format spec: t"{x:}" + format_spec = ast.JoinedStr(values=[]) + elif format_spec_choice == 'string_spec': + # Simple string format spec: t"{x:d}", t"{x:.2f}" + spec_string = draw(format_spec_string()) + if spec_string: # Only create if non-empty + format_spec = ast.JoinedStr(values=[ast.Constant(value=spec_string)]) + else: + format_spec = ast.JoinedStr(values=[]) + else: + # Nested format spec - but constrain it to realistic patterns + # Valid nested format specs have patterns like: + # - f"{x:{width}}" -> format_spec=JoinedStr(values=[FormattedValue]) + # - f"{x:.{prec}f}" -> format_spec=JoinedStr(values=[Constant('.'), FormattedValue, Constant('f')]) + # - f"{x:>{width}}" -> format_spec=JoinedStr(values=[Constant('>'), FormattedValue]) + + # Generate a realistic format spec pattern + # Use simple_joined_str/simple_template_str to avoid deep nesting + pattern_choice = draw(sampled_from(['simple_var', 'alignment_var', 'precision_var'])) + + if pattern_choice == 'simple_var': + # Just a variable: {width} + format_spec = ast.JoinedStr(values=[ + ast.FormattedValue( + value=draw(one_of(string_leaves, simple_joined_str(expression), simple_template_str(expression))), + conversion=-1, + format_spec=None + ) + ]) + elif pattern_choice == 'alignment_var': + # Alignment + variable: >{width} or <{width} or ^{width} + align_char = draw(sampled_from(['>', '<', '^'])) + format_spec = ast.JoinedStr(values=[ + ast.Constant(value=align_char), + ast.FormattedValue( + value=draw(one_of(string_leaves, simple_joined_str(expression), simple_template_str(expression))), + conversion=-1, + format_spec=None + ) + ]) + else: # precision_var + # Precision pattern: .{prec}f or .{prec}d + type_char = draw(sampled_from(['f', 'd', 's', 'x'])) + format_spec = ast.JoinedStr(values=[ + ast.Constant(value='.'), + ast.FormattedValue( + value=draw(one_of(string_leaves, simple_joined_str(expression), simple_template_str(expression))), + conversion=-1, + format_spec=None + ), + ast.Constant(value=type_char) + ]) + + return ast.Interpolation( + value=value, + str='', # Empty string is sufficient for our testing purposes + conversion=conversion, + format_spec=format_spec + ) + + +@composite +def simple_template_str(draw, expression) -> 'ast.TemplateStr': + """Generate simple TemplateStr nodes to avoid infinite recursion""" + + # Simple patterns that avoid consecutive constants + pattern_type = draw(sampled_from([ + 'constant_only', # t"text" + 'interpolation_only', # t"{expr}" or t"{expr1}{expr2}" + 'simple_mixed' # t"text{expr}" or t"{expr}text" + ])) + + if pattern_type == 'constant_only': + return ast.TemplateStr(values=[ + ast.Constant(value=draw(sampled_from(simple_strings))) + ]) + + elif pattern_type == 'interpolation_only': + # 1 or 2 interpolations, no constants + num_interpolations = draw(integers(min_value=1, max_value=2)) + values = [] + for _ in range(num_interpolations): + expr = draw(expression) + values.append(ast.Interpolation( + value=expr, + str='', + conversion=-1, + format_spec=None + )) + return ast.TemplateStr(values=values) + + else: # simple_mixed + # Either "text{expr}" or "{expr}text" + values = [] + if draw(booleans()): + # "text{expr}" + const_val = draw(sampled_from(simple_strings_with_empty)) + if const_val: # Python omits empty string constants + values.append(ast.Constant(value=const_val)) + values.append(ast.Interpolation( + value=draw(expression), + str='', + conversion=-1, + format_spec=None + )) + else: + # "{expr}text" + values.append(ast.Interpolation( + value=draw(expression), + str='', + conversion=-1, + format_spec=None + )) + const_val = draw(sampled_from(simple_strings_with_empty)) + if const_val: # Python omits empty string constants + values.append(ast.Constant(value=const_val)) + return ast.TemplateStr(values=values) + + +@composite +def TemplateStr(draw, expression) -> 'ast.TemplateStr': + """Generate TemplateStr nodes (t-strings) that mirror Python parser output + + Valid patterns follow same rules as f-strings but with Interpolation instead of FormattedValue: + - t"" → TemplateStr(values=[]) + - t"text" → TemplateStr(values=[Constant]) + - t"{expr}" → TemplateStr(values=[Interpolation]) + - t"text{expr}" → TemplateStr(values=[Constant, Interpolation]) + - t"{expr}text" → TemplateStr(values=[Interpolation, Constant]) + + Key insight: Never consecutive Constants (Python parser merges them) + """ + # Choose pattern type (same as JoinedStr) + pattern_type = draw(sampled_from([ + 'empty', # t"" + 'constant_only', # t"text" + 'interpolation_only', # t"{expr}" + 'mixed' # t"text{expr}..." + ])) + + if pattern_type == 'empty': + return ast.TemplateStr(values=[]) + + elif pattern_type == 'constant_only': + # Just a single string constant + return ast.TemplateStr(values=[ + ast.Constant(value=draw(sampled_from(simple_strings))) + ]) + + elif pattern_type == 'interpolation_only': + # One or more interpolations, no constants + num_interpolations = draw(integers(min_value=1, max_value=3)) + values = [] + for _ in range(num_interpolations): + values.append(draw(Interpolation(expression))) + return ast.TemplateStr(values=values) + + else: # mixed + # Generate realistic mixed pattern: alternating constants and interpolations + # Never adjacent constants + values = [] + + # Start with constant or interpolation + starts_with_constant = draw(booleans()) + + # Number of interpolations (at least 1) + num_interpolations = draw(integers(min_value=1, max_value=2)) + + if starts_with_constant: + const_val = draw(sampled_from(simple_strings_with_empty)) + if const_val: # Python omits empty string constants + values.append(ast.Constant(value=const_val)) + + # Add alternating interpolations and constants + for i in range(num_interpolations): + values.append(draw(Interpolation(expression))) + # Optionally add a constant after each interpolation (except maybe the last) + if i < num_interpolations - 1 or draw(booleans()): + const_val = draw(sampled_from(simple_strings_with_empty)) + if const_val: # Python omits empty string constants + values.append(ast.Constant(value=const_val)) + + return ast.TemplateStr(values=values) + + +# endregion + + +@composite +def mixed_string_expression(draw, expression) -> ast.AST: + """Generate expressions that can include f-strings, t-strings, regular strings, and bytes""" + return draw(one_of(Str(), Bytes(), JoinedStr(expression), TemplateStr(expression))) + + +string_leaves = one_of( + sampled_from([ + ast.Constant(value=''), + ast.Constant(value='hello'), + ast.Constant(value=42), + ast.Constant(value=3.14), + ast.Constant(value=True), + ast.Constant(value=None), + ]), + Str(), + Bytes(), + Name(), +) + + +def string_expression() -> SearchStrategy: + """Expression strategy focused on string operations and literals""" + return recursive( + string_leaves, + lambda expression: one_of( + mixed_string_expression(expression), + JoinedStr(expression), + TemplateStr(expression), + ), + max_leaves=30 + ) + + +@composite +def StringExpression(draw) -> ast.Expression: + """An eval expression focused on string formatting""" + e = draw(string_expression()) + return ast.Expression(e) diff --git a/hypo_test/test_it.py b/hypo_test/test_it.py index 3fe5d009..704a4efc 100644 --- a/hypo_test/test_it.py +++ b/hypo_test/test_it.py @@ -1,9 +1,10 @@ -import ast +import python_minifier.ast_compat as ast from datetime import timedelta -from hypothesis import HealthCheck, Verbosity, given, note, settings +from hypothesis import HealthCheck, Verbosity, example, given, note, settings +from python_minifier.ast_annotation import add_parent as add_parent_refs from python_minifier.ast_compare import compare_ast from python_minifier.ast_printer import print_ast from python_minifier.expression_printer import ExpressionPrinter @@ -15,10 +16,11 @@ from .folding import FoldableExpression from .module import Module, TypeAlias from .patterns import Pattern +from .strings import StringExpression @given(node=Expression()) -@settings(report_multiple_bugs=False, deadline=timedelta(seconds=1), max_examples=100, suppress_health_check=[HealthCheck.too_slow]) # verbosity=Verbosity.verbose +@settings(report_multiple_bugs=True, deadline=timedelta(seconds=1), max_examples=100, suppress_health_check=[HealthCheck.too_slow]) # verbosity=Verbosity.verbose def test_expression(node): assert isinstance(node, ast.AST) @@ -29,8 +31,9 @@ def test_expression(node): compare_ast(node, ast.parse(code, 'test_expression', 'eval')) +@example(node=ast.Module(body=[ast.Pass()], type_ignores=[])) # Simple passing example @given(node=Module()) -@settings(report_multiple_bugs=False, deadline=timedelta(seconds=1), max_examples=100, suppress_health_check=[HealthCheck.too_slow], verbosity=Verbosity.verbose) +@settings(report_multiple_bugs=True, deadline=timedelta(seconds=1), max_examples=100, suppress_health_check=[HealthCheck.too_slow, HealthCheck.data_too_large], verbosity=Verbosity.verbose) def test_module(node): assert isinstance(node, ast.Module) @@ -42,7 +45,7 @@ def test_module(node): @given(node=Pattern()) -@settings(report_multiple_bugs=False, deadline=timedelta(seconds=2), max_examples=100, verbosity=Verbosity.verbose) +@settings(report_multiple_bugs=True, deadline=timedelta(seconds=2), max_examples=100, verbosity=Verbosity.verbose) def test_pattern(node): module = ast.Module( @@ -66,11 +69,12 @@ def test_pattern(node): @given(node=FoldableExpression()) -@settings(report_multiple_bugs=False, deadline=timedelta(seconds=1), max_examples=1000, suppress_health_check=[HealthCheck.too_slow]) # verbosity=Verbosity.verbose +@settings(report_multiple_bugs=True, deadline=timedelta(seconds=1), max_examples=100, suppress_health_check=[HealthCheck.too_slow]) # verbosity=Verbosity.verbose def test_folding(node): assert isinstance(node, ast.AST) note(print_ast(node)) + add_parent_refs(node) add_parent(node) constant_folder = FoldConstants() @@ -80,7 +84,7 @@ def test_folding(node): @given(node=TypeAlias()) -@settings(report_multiple_bugs=False, deadline=timedelta(seconds=2), max_examples=100, verbosity=Verbosity.verbose) +@settings(report_multiple_bugs=True, deadline=timedelta(seconds=2), max_examples=100, verbosity=Verbosity.verbose) def test_type_alias(node): module = ast.Module( @@ -95,7 +99,7 @@ def test_type_alias(node): @given(node=TypeAlias()) -@settings(report_multiple_bugs=False, deadline=timedelta(seconds=2), max_examples=100, verbosity=Verbosity.verbose) +@settings(report_multiple_bugs=True, deadline=timedelta(seconds=2), max_examples=100, verbosity=Verbosity.verbose) def test_function_type_param(node): module = ast.Module( @@ -122,3 +126,15 @@ def test_function_type_param(node): code = printer(module) note(code) compare_ast(module, ast.parse(code, 'test_function_type_param')) + + +@given(node=StringExpression()) +@settings(report_multiple_bugs=True, deadline=None, max_examples=100, suppress_health_check=[HealthCheck.too_slow]) # verbosity=Verbosity.verbose +def test_string_expression(node): + assert isinstance(node, ast.Expression) + + note(ast.dump(node)) + printer = ExpressionPrinter() + code = printer(node) + note(code) + compare_ast(node, ast.parse(code, 'test_string_expression', 'eval')) diff --git a/setup.py b/setup.py index 53cb2e64..53e0699e 100644 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ long_description=long_desc, long_description_content_type='text/markdown', - python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, <3.14', + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, <3.15', setup_requires=['setuptools_scm'], classifiers=[ @@ -46,6 +46,7 @@ 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: Implementation :: CPython', diff --git a/src/python_minifier/ast_compare.py b/src/python_minifier/ast_compare.py index 1b6c0219..470f689c 100644 --- a/src/python_minifier/ast_compare.py +++ b/src/python_minifier/ast_compare.py @@ -59,10 +59,13 @@ def counter(): if type(l_ast) != type(r_ast): raise CompareError(l_ast, r_ast, msg='Nodes do not match! %r != %r' % (l_ast, r_ast)) - for field in set(l_ast._fields + r_ast._fields): + for field in sorted(set(l_ast._fields + r_ast._fields)): if field == 'kind' and isinstance(l_ast, ast.Constant): continue + + if field == 'str' and hasattr(ast, 'Interpolation') and isinstance(l_ast, ast.Interpolation): + continue if isinstance(getattr(l_ast, field, None), list): diff --git a/src/python_minifier/ast_compat.py b/src/python_minifier/ast_compat.py index 29cf6af5..c9c31c7c 100644 --- a/src/python_minifier/ast_compat.py +++ b/src/python_minifier/ast_compat.py @@ -70,6 +70,8 @@ def __new__(cls, *args, **kwargs): 'TryStar', 'TypeVar', 'TypeVarTuple', + 'TemplateStr', + 'Interpolation', 'YieldFrom', 'arg', 'withitem', diff --git a/src/python_minifier/expression_printer.py b/src/python_minifier/expression_printer.py index b5292953..bfdb45b0 100644 --- a/src/python_minifier/expression_printer.py +++ b/src/python_minifier/expression_printer.py @@ -743,6 +743,13 @@ def visit_JoinedStr(self, node): self.printer.fstring(str(python_minifier.f_string.OuterFString(node, pep701=pep701))) + def visit_TemplateStr(self, node): + assert isinstance(node, ast.TemplateStr) + + import python_minifier.t_string + + self.printer.tstring(str(python_minifier.t_string.TString(node))) + def visit_NamedExpr(self, node): self._expression(node.target) self.printer.operator(':=') diff --git a/src/python_minifier/f_string.py b/src/python_minifier/f_string.py index e51a8c25..45c970bd 100644 --- a/src/python_minifier/f_string.py +++ b/src/python_minifier/f_string.py @@ -8,6 +8,7 @@ import copy import re +import sys import python_minifier.ast_compat as ast @@ -58,11 +59,12 @@ def complete_debug_specifier(self, partial_specifier_candidates, value_node): return [x + '}' for x in conversion_candidates] - def candidates(self): - actual_candidates = [] + def _generate_candidates_with_processor(self, prefix, str_processor): + """Generate f-string candidates using the given prefix and string processor function.""" + candidates = [] for quote in self.allowed_quotes: - candidates = [''] + quote_candidates = [''] debug_specifier_candidates = [] nested_allowed = copy.copy(self.allowed_quotes) @@ -71,26 +73,24 @@ def candidates(self): for v in self.node.values: if is_constant_node(v, ast.Str): - # Could this be used as a debug specifier? - if len(candidates) < 10: + if len(quote_candidates) < 10: debug_specifier = re.match(r'.*=\s*$', v.s) if debug_specifier: - # Maybe! try: - debug_specifier_candidates = [x + '{' + v.s for x in candidates] + debug_specifier_candidates = [x + '{' + v.s for x in quote_candidates] except Exception: continue try: - candidates = [x + self.str_for(v.s, quote) for x in candidates] + quote_candidates = [x + str_processor(v.s, quote) for x in quote_candidates] except Exception: continue elif isinstance(v, ast.FormattedValue): try: completed = self.complete_debug_specifier(debug_specifier_candidates, v) - candidates = [ - x + y for x in candidates for y in FormattedValue(v, nested_allowed, self.pep701).get_candidates() + quote_candidates = [ + x + y for x in quote_candidates for y in FormattedValue(v, nested_allowed, self.pep701).get_candidates() ] + completed debug_specifier_candidates = [] except Exception: @@ -98,13 +98,70 @@ def candidates(self): else: raise RuntimeError('Unexpected JoinedStr value') - actual_candidates += ['f' + quote + x + quote for x in candidates] + candidates += [prefix + quote + x + quote for x in quote_candidates] + + return candidates + + def candidates(self): + actual_candidates = [] + + # Normal f-string candidates + actual_candidates += self._generate_candidates_with_processor('f', self.str_for) + + # Raw f-string candidates (if we detect backslashes) + if self._contains_literal_backslashes(): + actual_candidates += self._generate_candidates_with_processor('rf', lambda s, quote: self.raw_str_for(s)) return filter(self.is_correct_ast, actual_candidates) - def str_for(self, s, quote): + def raw_str_for(self, s): + """ + Generate string representation for raw f-strings. + Don't escape backslashes like MiniString does. + """ return s.replace('{', '{{').replace('}', '}}') + def _contains_literal_backslashes(self): + """ + Check if this f-string contains literal backslashes in constant values. + This indicates it may need to be a raw f-string. + """ + for node in ast.walk(self.node): + if is_constant_node(node, ast.Str): + if '\\' in node.s: + return True + return False + + + def str_for(self, s, quote): + # Escape null bytes and other characters that can't appear in Python source + escaped = '' + is_multiline = len(quote) == 3 # Triple-quoted strings + + for c in s: + if c == '\0': + escaped += '\\x00' + elif c == '\n' and not is_multiline: + # Only escape newlines in single-quoted strings + escaped += '\\n' + elif c == '\r': + # Always escape carriage returns because Python normalizes them during parsing + # This prevents semantic changes (\\r -> \\n) in multiline strings + escaped += '\\r' + elif c == '\t': + # Always escape tabs for consistency (though not strictly necessary in multiline) + escaped += '\\t' + elif c == '{': + escaped += '{{' + elif c == '}': + escaped += '}}' + elif ord(c) < 32 and c not in '\n\r\t': + # Escape other control characters + escaped += '\\x{:02x}'.format(ord(c)) + else: + escaped += c + return escaped + class OuterFString(FString): """ @@ -285,7 +342,9 @@ def _literals(self): if literal == '': literal += self.current_quote - if c == '\n': + if c == '\0': + literal += '\\x00' + elif c == '\n': literal += '\\n' elif c == '\r': literal += '\\r' @@ -302,7 +361,7 @@ def __str__(self): if self._s == '': return str(min(self.allowed_quotes, key=len)) * 2 - if '\0' in self._s or ('\\' in self._s and not self.pep701): + if '\\' in self._s and not self.pep701: raise ValueError('Impossible to represent a character in f-string expression part') if not self.pep701 and ('\n' in self._s or '\r' in self._s): @@ -360,7 +419,35 @@ def candidates(self): return candidates def str_for(self, s): - return s.replace('{', '{{').replace('}', '}}') + # Special handling for problematic format spec characters that can cause parsing issues + # If the format spec contains only braces, it's likely an invalid test case + + # Escape null bytes and other unprintable characters + escaped = '' + for c in s: + if c == '\0': + escaped += '\\x00' + elif c == '{': + escaped += '{{' + elif c == '}': + escaped += '}}' + elif c == '\\': + # For Python 3.12+ raw f-string regression (fixed in 3.14rc2), we need to escape backslashes + # in format specs so they round-trip correctly + if (3, 12) <= sys.version_info < (3, 14): + escaped += '\\\\' + else: + escaped += c + elif c == '\r': + # Always escape carriage returns because Python normalizes them to newlines during parsing + # This prevents AST mismatches (\r -> \n normalization) + escaped += '\\r' + elif ord(c) < 32 and c not in '\t\n': + # Escape other control characters except tab, newline + escaped += '\\x{:02x}'.format(ord(c)) + else: + escaped += c + return escaped class Bytes(object): @@ -411,7 +498,24 @@ def _literals(self): if literal == '': literal = 'b' + self.current_quote - literal += chr(b) + + # Handle special characters that need escaping + if b == 0: # null byte + literal += '\\x00' + elif b == ord('\\'): # backslash + literal += '\\\\' + elif b == ord('\n'): # newline + literal += '\\n' + elif b == ord('\r'): # carriage return + literal += '\\r' + elif b == ord('\t'): # tab + literal += '\\t' + elif len(self.current_quote) == 1 and b == ord(self.current_quote): # single quote character + literal += '\\' + self.current_quote + elif 32 <= b <= 126: # printable ASCII + literal += chr(b) + else: # other non-printable characters + literal += '\\x{:02x}'.format(b) if literal: literal += self.current_quote @@ -421,8 +525,6 @@ def __str__(self): if self._b == b'': return 'b' + str(min(self.allowed_quotes, key=len)) * 2 - if b'\0' in self._b or b'\\' in self._b: - raise ValueError('Impossible to represent a %r character in f-string expression part') if b'\n' in self._b or b'\r' in self._b: if '"""' not in self.allowed_quotes and "'''" not in self.allowed_quotes: diff --git a/src/python_minifier/rename/rename_literals.py b/src/python_minifier/rename/rename_literals.py index c69abd95..e707cf9c 100644 --- a/src/python_minifier/rename/rename_literals.py +++ b/src/python_minifier/rename/rename_literals.py @@ -220,6 +220,13 @@ def visit_JoinedStr(self, node): continue self.visit(v) + def visit_TemplateStr(self, node): + for v in node.values: + if is_constant_node(v, ast.Str): + # Can't hoist string literals that are part of the template + continue + self.visit(v) + def visit_NameConstant(self, node): self.get_binding(node.value, node).add_reference(node) diff --git a/src/python_minifier/t_string.py b/src/python_minifier/t_string.py new file mode 100644 index 00000000..00d1c17b --- /dev/null +++ b/src/python_minifier/t_string.py @@ -0,0 +1,330 @@ +""" +Template String (T-String) unparsing + +T-strings in Python 3.14 follow PEP 750 and are based on PEP 701, +which means they don't have the quote restrictions of older f-strings. + +This implementation is much simpler than f_string.py because: +- No quote tracking needed (PEP 701 benefits) +- No pep701 parameter needed (always true for t-strings) +- No Outer vs Inner distinction needed +- Always use all quote types +""" + +import python_minifier.ast_compat as ast + +from python_minifier import UnstableMinification +from python_minifier.ast_compare import CompareError, compare_ast +from python_minifier.expression_printer import ExpressionPrinter +from python_minifier.ministring import MiniString +from python_minifier.token_printer import TokenTypes +from python_minifier.util import is_constant_node + + +class TString(object): + """ + A Template String (t-string) + + Much simpler than f-strings because PEP 701 eliminates quote restrictions + """ + + def __init__(self, node): + assert isinstance(node, ast.TemplateStr) + self.node = node + # Always use all quotes - no restrictions due to PEP 701 + self.allowed_quotes = ['"', "'", '"""', "'''"] + + def is_correct_ast(self, code): + """Check if the generated code produces the same AST""" + try: + c = ast.parse(code, 'TString candidate', mode='eval') + compare_ast(self.node, c.body) + return True + except Exception: + return False + + def complete_debug_specifier(self, partial_specifier_candidates, value_node): + """Complete debug specifier candidates for an Interpolation node""" + assert isinstance(value_node, ast.Interpolation) + + conversion = '' + if value_node.conversion == 115: # 's' + conversion = '!s' + elif value_node.conversion == 114 and value_node.format_spec is not None: + # This is the default for debug specifiers, unless there's a format_spec + conversion = '!r' + elif value_node.conversion == 97: # 'a' + conversion = '!a' + + conversion_candidates = [x + conversion for x in partial_specifier_candidates] + + if value_node.format_spec is not None: + # Handle format specifications in debug specifiers + if isinstance(value_node.format_spec, ast.JoinedStr): + import python_minifier.f_string + format_specs = python_minifier.f_string.FormatSpec(value_node.format_spec, self.allowed_quotes, pep701=True).candidates() + conversion_candidates = [c + ':' + fs for c in conversion_candidates for fs in format_specs] + + return [x + '}' for x in conversion_candidates] + + def candidates(self): + """Generate all possible representations""" + actual_candidates = [] + + # Normal t-string candidates + actual_candidates.extend(self._generate_candidates_with_processor('t', self.str_for)) + + # Raw t-string candidates (if we detect backslashes) + if self._contains_literal_backslashes(): + actual_candidates.extend(self._generate_candidates_with_processor('rt', self.raw_str_for)) + + return filter(self.is_correct_ast, actual_candidates) + + def _generate_candidates_with_processor(self, prefix, str_processor): + """Generate t-string candidates using the given prefix and string processor function.""" + candidates = [] + + for quote in self.allowed_quotes: + quote_candidates = [''] + debug_specifier_candidates = [] + + for v in self.node.values: + if is_constant_node(v, ast.Constant) and isinstance(v.value, str): + # String literal part - check for debug specifiers + + # Could this be used as a debug specifier? + if len(quote_candidates) < 10: + import re + debug_specifier = re.match(r'.*=\s*$', v.value) + if debug_specifier: + # Maybe! Save for potential debug specifier completion + try: + debug_specifier_candidates = [x + '{' + v.value for x in quote_candidates] + except Exception: + continue + + try: + quote_candidates = [x + str_processor(v.value, quote) for x in quote_candidates] + except Exception: + continue + + elif isinstance(v, ast.Interpolation): + # Interpolated expression part - check for debug completion + try: + # Try debug specifier completion + completed = self.complete_debug_specifier(debug_specifier_candidates, v) + + # Regular interpolation processing + interpolation_candidates = InterpolationValue(v).get_candidates() + quote_candidates = [x + y for x in quote_candidates for y in interpolation_candidates] + completed + + debug_specifier_candidates = [] + except Exception: + continue + else: + raise RuntimeError('Unexpected TemplateStr value: %r' % v) + + candidates.extend([prefix + quote + x + quote for x in quote_candidates]) + + return candidates + + def str_for(self, s, quote): + """Convert string literal to properly escaped form""" + # Use MiniString for optimal string representation + # Always allowed due to PEP 701 - no backslash restrictions + mini_s = str(MiniString(s, quote)).replace('{', '{{').replace('}', '}}') + + if mini_s == '': + return '\\\n' + return mini_s + + def raw_str_for(self, s): + """ + Generate string representation for raw t-strings. + Don't escape backslashes like MiniString does. + """ + return s.replace('{', '{{').replace('}', '}}') + + def _contains_literal_backslashes(self): + """ + Check if this t-string contains literal backslashes in constant values. + This indicates it may need to be a raw t-string. + """ + for node in ast.walk(self.node): + if is_constant_node(node, ast.Str): + if '\\' in node.s: + return True + return False + + def __str__(self): + """Generate the shortest valid t-string representation""" + if len(self.node.values) == 0: + return 't' + min(self.allowed_quotes, key=len) * 2 + + candidates = list(self.candidates()) + + # Validate all candidates + for candidate in candidates: + try: + minified_t_string = ast.parse(candidate, 'python_minifier.t_string output', mode='eval').body + except SyntaxError as syntax_error: + raise UnstableMinification(syntax_error, '', candidate) + + try: + compare_ast(self.node, minified_t_string) + except CompareError as compare_error: + raise UnstableMinification(compare_error, '', candidate) + + if not candidates: + raise ValueError('Unable to create representation for t-string') + + return min(candidates, key=len) + + +class InterpolationValue(ExpressionPrinter): + """ + A Template String Interpolation Part + + Handles ast.Interpolation nodes (equivalent to FormattedValue for f-strings) + """ + + def __init__(self, node): + super(InterpolationValue, self).__init__() + + assert isinstance(node, ast.Interpolation) + self.node = node + # Always use all quotes - no restrictions due to PEP 701 + self.allowed_quotes = ['"', "'", '"""', "'''"] + self.candidates = [''] + + def get_candidates(self): + """Generate all possible representations of this interpolation""" + + self.printer.delimiter('{') + + if self.is_curly(self.node.value): + self.printer.delimiter(' ') + + self._expression(self.node.value) + + # Handle conversion specifiers + if self.node.conversion == 115: # 's' + self.printer.append('!s', TokenTypes.Delimiter) + elif self.node.conversion == 114: # 'r' + self.printer.append('!r', TokenTypes.Delimiter) + elif self.node.conversion == 97: # 'a' + self.printer.append('!a', TokenTypes.Delimiter) + + # Handle format specifications + if self.node.format_spec is not None: + self.printer.delimiter(':') + + # Format spec is a JoinedStr (f-string) in the AST + if isinstance(self.node.format_spec, ast.JoinedStr): + import python_minifier.f_string + # Use f-string processing for format specs + format_candidates = python_minifier.f_string.OuterFString( + self.node.format_spec, pep701=True + ).candidates() + # Remove the f/rf prefix and quotes to get just the format part + format_parts = [] + for fmt in format_candidates: + # Handle both f"..." and rf"..." patterns + if fmt.startswith('rf'): + # Remove rf prefix and outer quotes + inner = fmt[2:] + elif fmt.startswith('f'): + # Remove f prefix and outer quotes + inner = fmt[1:] + else: + continue + + if (inner.startswith('"') and inner.endswith('"')) or \ + (inner.startswith("'") and inner.endswith("'")): + format_parts.append(inner[1:-1]) + elif (inner.startswith('"""') and inner.endswith('"""')) or \ + (inner.startswith("'''") and inner.endswith("'''")): + format_parts.append(inner[3:-3]) + else: + format_parts.append(inner) + + if format_parts: + self._append(format_parts) + else: + # Simple constant format spec + self.printer.append(str(self.node.format_spec), TokenTypes.Delimiter) + + self.printer.delimiter('}') + + self._finalize() + return self.candidates + + def is_curly(self, node): + """Check if expression starts with curly braces (needs space)""" + if isinstance(node, (ast.SetComp, ast.DictComp, ast.Set, ast.Dict)): + return True + + if isinstance(node, (ast.Expr, ast.Attribute, ast.Subscript)): + return self.is_curly(node.value) + + if isinstance(node, (ast.Compare, ast.BinOp)): + return self.is_curly(node.left) + + if isinstance(node, ast.Call): + return self.is_curly(node.func) + + if isinstance(node, ast.BoolOp): + return self.is_curly(node.values[0]) + + if isinstance(node, ast.IfExp): + return self.is_curly(node.body) + + return False + + def visit_Constant(self, node): + """Handle constant values in interpolations""" + if isinstance(node.value, str): + # Use Str class from f_string module for string handling + from python_minifier.f_string import Str + self.printer.append(str(Str(node.value, self.allowed_quotes, pep701=True)), TokenTypes.NonNumberLiteral) + elif isinstance(node.value, bytes): + # Use Bytes class from f_string module for bytes handling + from python_minifier.f_string import Bytes + self.printer.append(str(Bytes(node.value, self.allowed_quotes)), TokenTypes.NonNumberLiteral) + else: + # Other constants (numbers, None, etc.) + super().visit_Constant(node) + + def visit_TemplateStr(self, node): + """Handle nested t-strings""" + assert isinstance(node, ast.TemplateStr) + if self.printer.previous_token in [TokenTypes.Identifier, TokenTypes.Keyword, TokenTypes.SoftKeyword]: + self.printer.delimiter(' ') + # Nested t-string - no quote restrictions due to PEP 701 + self._append(TString(node).candidates()) + + def visit_JoinedStr(self, node): + """Handle nested f-strings in t-strings""" + assert isinstance(node, ast.JoinedStr) + if self.printer.previous_token in [TokenTypes.Identifier, TokenTypes.Keyword, TokenTypes.SoftKeyword]: + self.printer.delimiter(' ') + + import python_minifier.f_string + # F-strings nested in t-strings also benefit from PEP 701 + self._append(python_minifier.f_string.OuterFString(node, pep701=True).candidates()) + + def visit_Lambda(self, node): + """Handle lambda expressions in interpolations""" + self.printer.delimiter('(') + super().visit_Lambda(node) + self.printer.delimiter(')') + + def _finalize(self): + """Finalize the current printer state""" + self.candidates = [x + str(self.printer) for x in self.candidates] + self.printer._code = '' + + def _append(self, candidates): + """Append multiple candidate strings""" + self._finalize() + self.candidates = [x + y for x in self.candidates for y in candidates] diff --git a/src/python_minifier/token_printer.py b/src/python_minifier/token_printer.py index 52a03c66..8e4588e0 100644 --- a/src/python_minifier/token_printer.py +++ b/src/python_minifier/token_printer.py @@ -181,6 +181,16 @@ def fstring(self, s): self._code += s self.previous_token = TokenTypes.NonNumberLiteral + def tstring(self, s): + """Add a template string (t-string) to the output code.""" + assert isinstance(s, str) + + if self.previous_token in [TokenTypes.Identifier, TokenTypes.Keyword, TokenTypes.SoftKeyword]: + self.delimiter(' ') + + self._code += s + self.previous_token = TokenTypes.NonNumberLiteral + def delimiter(self, d): """Add a delimiter to the output code.""" assert d in [ diff --git a/test/requirements.txt b/test/requirements.txt new file mode 100644 index 00000000..55b033e9 --- /dev/null +++ b/test/requirements.txt @@ -0,0 +1 @@ +pytest \ No newline at end of file diff --git a/test/test_hoist_literals.py b/test/test_hoist_literals.py index 3a75e2ac..861218e1 100644 --- a/test/test_hoist_literals.py +++ b/test/test_hoist_literals.py @@ -198,7 +198,7 @@ def test_hoist_after_multiple_future(): source = ''' "Hello this is a docstring" from __future__ import print_function -from __future__ import sausages +from __future__ import unicode_literals import collections A = b'Hello' B = b'Hello' @@ -207,7 +207,7 @@ def test_hoist_after_multiple_future(): expected = ''' "Hello this is a docstring" from __future__ import print_function -from __future__ import sausages +from __future__ import unicode_literals C = b'Hello' import collections A = C diff --git a/test/test_is_constant_node.py b/test/test_is_constant_node.py index 1be7950d..f32a9908 100644 --- a/test/test_is_constant_node.py +++ b/test/test_is_constant_node.py @@ -13,6 +13,8 @@ @pytest.mark.filterwarnings("ignore:ast.NameConstant is deprecated:DeprecationWarning") @pytest.mark.filterwarnings("ignore:ast.Ellipsis is deprecated:DeprecationWarning") def test_type_nodes(): + if sys.version_info >= (3, 14): + pytest.skip('Deprecated AST types removed in Python 3.14') assert is_constant_node(ast.Str('a'), ast.Str) if hasattr(ast, 'Bytes'): @@ -42,6 +44,8 @@ def test_constant_nodes(): # only test on python 3.8+ if sys.version_info < (3, 8): pytest.skip('Constant not available') + if sys.version_info >= (3, 14): + pytest.skip('Deprecated AST types removed in Python 3.14') assert is_constant_node(ast.Constant('a'), ast.Str) assert is_constant_node(ast.Constant(b'a'), ast.Bytes) @@ -51,3 +55,39 @@ def test_constant_nodes(): assert is_constant_node(ast.Constant(False), ast.NameConstant) assert is_constant_node(ast.Constant(None), ast.NameConstant) assert is_constant_node(ast.Constant(ast.literal_eval('...')), ast.Ellipsis) + + +def test_ast_compat_types_python314(): + """Test that ast_compat provides the removed AST types in Python 3.14+""" + if sys.version_info < (3, 14): + pytest.skip('ast_compat types test only for Python 3.14+') + + import python_minifier.ast_compat as ast_compat + + # Test that ast_compat provides the removed types + assert is_constant_node(ast_compat.Str('a'), ast_compat.Str) + assert is_constant_node(ast_compat.Bytes(b'a'), ast_compat.Bytes) + assert is_constant_node(ast_compat.Num(1), ast_compat.Num) + assert is_constant_node(ast_compat.Num(0), ast_compat.Num) + assert is_constant_node(ast_compat.NameConstant(True), ast_compat.NameConstant) + assert is_constant_node(ast_compat.NameConstant(False), ast_compat.NameConstant) + assert is_constant_node(ast_compat.NameConstant(None), ast_compat.NameConstant) + assert is_constant_node(ast_compat.Ellipsis(), ast_compat.Ellipsis) + + +def test_ast_compat_constant_nodes_python314(): + """Test that ast_compat works with Constant nodes in Python 3.14+""" + if sys.version_info < (3, 14): + pytest.skip('ast_compat constant test only for Python 3.14+') + + import python_minifier.ast_compat as ast_compat + + # Test that Constant nodes work with ast_compat types + assert is_constant_node(ast.Constant('a'), ast_compat.Str) + assert is_constant_node(ast.Constant(b'a'), ast_compat.Bytes) + assert is_constant_node(ast.Constant(1), ast_compat.Num) + assert is_constant_node(ast.Constant(0), ast_compat.Num) + assert is_constant_node(ast.Constant(True), ast_compat.NameConstant) + assert is_constant_node(ast.Constant(False), ast_compat.NameConstant) + assert is_constant_node(ast.Constant(None), ast_compat.NameConstant) + assert is_constant_node(ast.Constant(ast.literal_eval('...')), ast_compat.Ellipsis) diff --git a/test/test_raw_fstring_backslash.py b/test/test_raw_fstring_backslash.py new file mode 100644 index 00000000..1057c566 --- /dev/null +++ b/test/test_raw_fstring_backslash.py @@ -0,0 +1,80 @@ +""" +Test for raw f-string with backslash escape sequences. +""" + +import ast +import sys + +import pytest + +from python_minifier import unparse +from python_minifier.ast_compare import compare_ast + + +@pytest.mark.parametrize('source,description', [ + # Raw f-string backslash tests - core regression fix + pytest.param(r'rf"{x:\\xFF}"', 'Single backslash in format spec (minimal failing case)', id='raw-fstring-backslash-format-spec'), + pytest.param(r'rf"\\n{x}\\t"', 'Backslashes in literal parts', id='raw-fstring-backslash-outer-str'), + pytest.param(r'rf"\\n{x:\\xFF}\\t"', 'Backslashes in both literal and format spec', id='raw-fstring-mixed-backslashes'), + pytest.param(r'rf"\n"', 'Single backslash in literal only', id='raw-fstring-literal-single-backslash'), + pytest.param(r'rf"\\n"', 'Double backslash in literal only', id='raw-fstring-literal-double-backslash'), + pytest.param(r'rf"{x:\xFF}"', 'Single backslash in format spec only', id='raw-fstring-formatspec-single-backslash'), + pytest.param(r'rf"{x:\\xFF}"', 'Double backslash in format spec only', id='raw-fstring-formatspec-double-backslash'), + pytest.param(r'rf"\n{x:\xFF}\t"', 'Single backslashes in both parts', id='raw-fstring-mixed-single-backslashes'), + + # Special characters discovered during fuzzing + pytest.param('f"test\\x00end"', 'Null byte in literal part', id='null-byte-literal'), + pytest.param('f"{x:\\x00}"', 'Null byte in format spec', id='null-byte-format-spec'), + pytest.param('f"test\\rend"', 'Carriage return in literal (must be escaped to prevent semantic changes)', id='carriage-return-literal'), + pytest.param('f"test\\tend"', 'Tab in literal part', id='tab-literal'), + pytest.param('f"{x:\\t}"', 'Tab in format spec', id='tab-format-spec'), + pytest.param('f"test\\x01end"', 'Control character (ASCII 1)', id='control-character'), + pytest.param('f"test\\nend"', 'Newline in single-quoted string', id='newline-single-quote'), + pytest.param('f"""test\nend"""', 'Actual newline in triple-quoted string', id='newline-triple-quote'), + pytest.param('f"\\x00\\r\\t{x}"', 'Mix of null bytes, carriage returns, and tabs', id='mixed-special-chars'), + + # Conversion specifiers with special characters + pytest.param(r'rf"{x!r:\\xFF}"', 'Conversion specifier !r with format spec', id='conversion-r-with-backslash'), + pytest.param(r'rf"{x!s:\\xFF}"', 'Conversion specifier !s with format spec', id='conversion-s-with-backslash'), + pytest.param(r'rf"{x!a:\\xFF}"', 'Conversion specifier !a with format spec', id='conversion-a-with-backslash'), + pytest.param('f"{x!r:\\x00}"', 'Conversion specifier with null byte in format spec', id='conversion-with-null-byte'), + + # Other edge cases + pytest.param(r'rf"""{x:\\xFF}"""', 'Triple-quoted raw f-string with backslashes', id='raw-fstring-triple-quoted'), + pytest.param(r'rf"{x:\\xFF}{y:\\xFF}"', 'Multiple interpolations with backslashes', id='raw-fstring-multiple-interpolations'), + pytest.param('f"\\\\n{x}\\\\t"', 'Regular (non-raw) f-string with backslashes', id='regular-fstring-with-backslash'), +]) +@pytest.mark.skipif(sys.version_info < (3, 6), reason='F-strings not supported in Python < 3.6') +def test_fstring_edge_cases(source, description): + """Test f-strings with various edge cases including backslashes and special characters.""" + expected_ast = ast.parse(source) + actual_code = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(actual_code)) + + +@pytest.mark.parametrize('source,description', [ + pytest.param(r'f"{f"\\n{x}\\t"}"', 'Nested f-strings with backslashes in inner string parts', id='nested-fstring-backslashes'), + pytest.param(r'f"{rf"\\xFF{y}\\n"}"', 'Nested raw f-strings with backslashes', id='nested-raw-fstring-backslashes'), + pytest.param(r'f"{f"{x:\\xFF}"}"', 'Nested f-strings with backslashes in format specs', id='nested-fstring-format-spec-backslashes'), +]) +@pytest.mark.skipif(sys.version_info < (3, 12), reason='Nested f-strings not supported in Python < 3.12') +def test_nested_fstring_edge_cases(source, description): + """Test nested f-strings with backslashes (Python 3.12+ only).""" + expected_ast = ast.parse(source) + actual_code = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(actual_code)) + + +@pytest.mark.skipif(sys.version_info < (3, 6), reason='F-strings not supported in Python < 3.6') +def test_fstring_carriage_return_format_spec(): + r"""Test f-string with carriage return in format spec. + + Note: This is syntactically valid but will fail at runtime with + ValueError: Unknown format code '\xd' for object of type 'int' + However, the minifier correctly escapes the carriage return to prevent + Python from normalizing it to a newline during parsing. + """ + source = 'f"{x:\\r}"' + expected_ast = ast.parse(source) + actual_code = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(actual_code)) diff --git a/test/test_raw_tstring_backslash.py b/test/test_raw_tstring_backslash.py new file mode 100644 index 00000000..525faceb --- /dev/null +++ b/test/test_raw_tstring_backslash.py @@ -0,0 +1,98 @@ +""" +Test for raw t-string with backslash escape sequences. + +This test covers the same scenarios as test_raw_fstring_backslash.py but for t-strings. +Since t-strings were introduced in Python 3.14 and the raw f-string regression was fixed +in Python 3.14rc2, these tests verify that raw t-strings handle backslashes correctly +from the start, especially in format specs. +""" + +import ast +import sys + +import pytest + +from python_minifier import unparse +from python_minifier.ast_compare import compare_ast + + +@pytest.mark.parametrize('source,description', [ + # Raw t-string backslash tests - core regression testing + pytest.param(r'rt"{x:\\xFF}"', 'Single backslash in format spec (minimal case)', id='raw-tstring-backslash-format-spec'), + pytest.param(r'rt"\\n{x}\\t"', 'Backslashes in literal parts', id='raw-tstring-backslash-outer-str'), + pytest.param(r'rt"\\n{x:\\xFF}\\t"', 'Backslashes in both literal and format spec', id='raw-tstring-mixed-backslashes'), + pytest.param(r'rt"\n"', 'Single backslash in literal only', id='raw-tstring-literal-single-backslash'), + pytest.param(r'rt"\\n"', 'Double backslash in literal only', id='raw-tstring-literal-double-backslash'), + pytest.param(r'rt"{x:\xFF}"', 'Single backslash in format spec only', id='raw-tstring-formatspec-single-backslash'), + pytest.param(r'rt"{x:\\xFF}"', 'Double backslash in format spec only', id='raw-tstring-formatspec-double-backslash'), + pytest.param(r'rt"\n{x:\xFF}\t"', 'Single backslashes in both parts', id='raw-tstring-mixed-single-backslashes'), + + # Special characters discovered during fuzzing + pytest.param('t"test\\x00end"', 'Null byte in literal part', id='null-byte-literal'), + pytest.param('t"{x:\\x00}"', 'Null byte in format spec', id='null-byte-format-spec'), + pytest.param('t"test\\rend"', 'Carriage return in literal (must be escaped to prevent semantic changes)', id='carriage-return-literal'), + pytest.param('t"test\\tend"', 'Tab in literal part', id='tab-literal'), + pytest.param('t"{x:\\t}"', 'Tab in format spec', id='tab-format-spec'), + pytest.param('t"test\\x01end"', 'Control character (ASCII 1)', id='control-character'), + pytest.param('t"test\\nend"', 'Newline in single-quoted string', id='newline-single-quote'), + pytest.param('t"""test\nend"""', 'Actual newline in triple-quoted string', id='newline-triple-quote'), + pytest.param('t"\\x00\\r\\t{x}"', 'Mix of null bytes, carriage returns, and tabs', id='mixed-special-chars'), + + # Conversion specifiers with special characters + pytest.param(r'rt"{x!r:\\xFF}"', 'Conversion specifier !r with format spec', id='conversion-r-with-backslash'), + pytest.param(r'rt"{x!s:\\xFF}"', 'Conversion specifier !s with format spec', id='conversion-s-with-backslash'), + pytest.param(r'rt"{x!a:\\xFF}"', 'Conversion specifier !a with format spec', id='conversion-a-with-backslash'), + pytest.param('t"{x!r:\\x00}"', 'Conversion specifier with null byte in format spec', id='conversion-with-null-byte'), + + # Other edge cases + pytest.param(r'rt"""{x:\\xFF}"""', 'Triple-quoted raw t-string with backslashes', id='raw-tstring-triple-quoted'), + pytest.param(r'rt"{x:\\xFF}{y:\\xFF}"', 'Multiple interpolations with backslashes', id='raw-tstring-multiple-interpolations'), + pytest.param('t"\\\\n{x}\\\\t"', 'Regular (non-raw) t-string with backslashes', id='regular-tstring-with-backslash'), + + # Complex format specs - originally in test_raw_tstring_complex_format_specs + pytest.param(r'rt"{x:\\xFF\\n}"', 'Multiple backslashes in single format spec', id='complex-multiple-backslashes'), + pytest.param(r'rt"{x:\\xFF}{y:\\n}"', 'Multiple format specs with backslashes', id='complex-multiple-format-specs'), + pytest.param(r'rt"\\start{x:\\xFF}\\end"', 'Backslashes in both literal and format spec parts', id='complex-mixed-locations'), + pytest.param(r'rt"{x:{fmt:\\n}}"', 'Nested format spec with backslashes', id='complex-nested-format-spec'), + + # Unicode escapes - originally in test_raw_tstring_unicode_escapes + pytest.param(r'rt"{x:\u0041}"', 'Unicode escape in format spec', id='unicode-short-escape'), + pytest.param(r'rt"{x:\U00000041}"', 'Long Unicode escape in format spec', id='unicode-long-escape'), + pytest.param(r'rt"\\u0041{x:\xFF}"', 'Unicode in literal, hex in format spec', id='unicode-mixed'), + + # Mixed t-string and f-string + pytest.param(r'rt"t-string \\n {f"f-string {x:\\xFF}"} \\t"', 'Nested combination of raw t-strings and f-strings', id='mixed-tstring-fstring'), +]) +@pytest.mark.skipif(sys.version_info < (3, 14), reason='T-strings not supported in Python < 3.14') +def test_tstring_edge_cases(source, description): + """Test t-strings with various edge cases including backslashes and special characters.""" + expected_ast = ast.parse(source) + actual_code = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(actual_code)) + + +@pytest.mark.parametrize('source,description', [ + pytest.param(r't"{t"\\n{x}\\t"}"', 'Nested t-strings with backslashes in inner string parts', id='nested-tstring-backslashes'), + pytest.param(r't"{rt"\\xFF{y}\\n"}"', 'Nested raw t-strings with backslashes', id='nested-raw-tstring-backslashes'), + pytest.param(r't"{t"{x:\\xFF}"}"', 'Nested t-strings with backslashes in format specs', id='nested-tstring-format-spec-backslashes'), +]) +@pytest.mark.skipif(sys.version_info < (3, 14), reason='T-strings not supported in Python < 3.14') +def test_nested_tstring_edge_cases(source, description): + """Test nested t-strings with backslashes.""" + expected_ast = ast.parse(source) + actual_code = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(actual_code)) + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason='T-strings not supported in Python < 3.14') +def test_tstring_carriage_return_format_spec(): + r"""Test t-string with carriage return in format spec. + + Note: This is syntactically valid but will fail at runtime with + ValueError: Unknown format code '\xd' for object of type 'int' + However, unlike f-strings, t-strings can successfully unparse this case. + """ + source = 't"{x:\\r}"' + expected_ast = ast.parse(source) + actual_code = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(actual_code)) \ No newline at end of file diff --git a/test/test_template_strings.py b/test/test_template_strings.py new file mode 100644 index 00000000..117d7c4c --- /dev/null +++ b/test/test_template_strings.py @@ -0,0 +1,254 @@ +import ast +import sys + +import pytest + +from python_minifier import unparse +from python_minifier.ast_compare import compare_ast + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +@pytest.mark.parametrize( + 'statement', [ + 't"hello"', + 't"Hello {name}"', + 't"Hello {name!r}"', + 't"Hello {name!s}"', + 't"Hello {name!a}"', + 't"Value: {value:.2f}"', + 't"{1}"', + 't"{1=}"', + 't"{1=!r:.4}"', + 't"{1=:.4}"', + 't"{1=!s:.4}"', + 't"{1=!a}"', + ] +) +def test_tstring_basic(statement): + """Test basic t-string parsing and unparsing""" + assert unparse(ast.parse(statement)) == statement + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +@pytest.mark.parametrize( + 'statement', [ + 't"Hello {name} and {other}"', + 't"User {action}: {amount:.2f} {item}"', + 't"{value:.{precision}f}"', + 't"Complex {a} and {b!r} with {c:.3f}"', + ] +) +def test_tstring_multiple_interpolations(statement): + """Test t-strings with multiple interpolations""" + assert unparse(ast.parse(statement)) == statement + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +@pytest.mark.parametrize( + 'statement', [ + 't"nested {t"inner {x}"}"', + 't"outer {t"middle {t"inner {y}"}"} end"', + 't"complex {t"nested {value:.2f}"} result"', + 't"{t"prefix {name}"} suffix"', + ] +) +def test_tstring_nesting(statement): + """Test nested t-strings (should work with PEP 701 benefits)""" + assert unparse(ast.parse(statement)) == statement + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +def test_tstring_quote_variations(): + """Test different quote styles for t-strings - just ensure they parse and unparse correctly""" + statements = [ + "t'single quotes {name}'", + 't"""triple double quotes {name}"""', + "t'''triple single quotes {name}'''", + 't"mixed {name} with \\"escaped\\" quotes"', + "t'mixed {name} with \\'escaped\\' quotes'", + ] + + for statement in statements: + # Just test that it parses and round-trips correctly, don't care about exact quote style + parsed = ast.parse(statement) + unparsed = unparse(parsed) + reparsed = ast.parse(unparsed) + compare_ast(parsed, reparsed) + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +def test_tstring_multiline(): + """Test multiline t-strings""" + statement = '''t""" +Multiline template +with {name} interpolation +and {value:.2f} formatting +"""''' + expected = 't"\\nMultiline template\\nwith {name} interpolation\\nand {value:.2f} formatting\\n"' + assert unparse(ast.parse(statement)) == expected + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +def test_tstring_with_complex_expressions(): + """Test t-strings with complex expressions in interpolations""" + test_cases = [ + ('t"Result: {func(a, b, c)}"', 't"Result: {func(a,b,c)}"'), + ('t"List: {[x for x in items]}"', 't"List: {[x for x in items]}"'), + ('t"Dict: {key: value for key, value in pairs}"', 't"Dict: {key: value for key, value in pairs}"'), + ('t"Set: {{item for item in collection}}"', 't"Set: {{item for item in collection}}"'), + ('t"Lambda: {(lambda x: x * 2)(value)}"', 't"Lambda: {((lambda x:x*2))(value)}"'), + ('t"Attribute: {obj.attr.method()}"', 't"Attribute: {obj.attr.method()}"'), + ('t"Subscription: {data[key][0]}"', 't"Subscription: {data[key][0]}"'), + ('t"Ternary: {x if condition else y}"', 't"Ternary: {x if condition else y}"'), + ] + + for input_statement, expected_output in test_cases: + assert unparse(ast.parse(input_statement)) == expected_output + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +def test_tstring_with_binary_operations(): + """Test t-strings with binary operations in interpolations""" + test_cases = [ + ('t"Sum: {a + b}"', 't"Sum: {a+b}"'), + ('t"Product: {x * y}"', 't"Product: {x*y}"'), + ('t"Division: {total / count}"', 't"Division: {total/count}"'), + ('t"Complex: {(a + b) * (c - d)}"', 't"Complex: {(a+b)*(c-d)}"'), + ('t"String concat: {first + last}"', 't"String concat: {first+last}"'), + ('t"Comparison: {x > y}"', 't"Comparison: {x>y}"'), + ('t"Boolean: {a and b}"', 't"Boolean: {a and b}"'), + ('t"Bitwise: {x | y}"', 't"Bitwise: {x|y}"'), + ] + + for input_statement, expected_output in test_cases: + assert unparse(ast.parse(input_statement)) == expected_output + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +def test_tstring_empty(): + """Test empty t-string""" + statement = 't""' + assert unparse(ast.parse(statement)) == statement + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +def test_tstring_only_interpolation(): + """Test t-string with only interpolation, no literal parts""" + statement = 't"{value}"' + assert unparse(ast.parse(statement)) == statement + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +def test_tstring_special_characters(): + """Test t-strings with special characters that need escaping""" + statements = [ + 't"Braces: {{literal}} and {variable}"', + 't"Newline: \\n and {value}"', + 't"Tab: \\t and {value}"', + 't"Quote: \\" and {value}"', + "t'Quote: \\' and {value}'", + 't"Backslash: \\\\ and {value}"', + ] + + for statement in statements: + # Test that it parses and round-trips correctly + parsed = ast.parse(statement) + unparsed = unparse(parsed) + reparsed = ast.parse(unparsed) + compare_ast(parsed, reparsed) + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +def test_tstring_ast_structure(): + """Test that t-string AST structure is correctly preserved""" + source = 't"Hello {name} world {value:.2f}!"' + expected_ast = ast.parse(source) # Parse as module, not expression + actual_ast = ast.parse(unparse(expected_ast)) + compare_ast(expected_ast, actual_ast) + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +def test_tstring_vs_fstring_syntax(): + """Test that t-strings and f-strings have similar but distinct syntax""" + # These should both parse successfully but produce different ASTs + tstring = 't"Hello {name}"' + fstring = 'f"Hello {name}"' + + t_ast = ast.parse(tstring) + f_ast = ast.parse(fstring) + + # Should be different node types in the expression + assert type(t_ast.body[0].value).__name__ == 'TemplateStr' + assert type(f_ast.body[0].value).__name__ == 'JoinedStr' + + # But should unparse correctly + assert unparse(t_ast) == tstring + assert unparse(f_ast) == fstring + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +def test_raw_template_strings(): + """Test raw template strings (rt prefix) - they parse but unparser loses the raw prefix""" + if sys.version_info >= (3, 14): # Raw t-strings are supported in Python 3.14 + # Test that raw t-strings parse correctly + raw_statements = [ + 'rt"raw template {name}"', + 'rt"backslash \\\\ preserved {name}"', + ] + + for statement in raw_statements: + # Raw t-strings should parse successfully + ast.parse(statement) + + # Test that raw behavior is preserved in the AST even if prefix is lost + raw_backslash = 'rt"backslash \\\\n and {name}"' + regular_backslash = 't"backslash \\n and {name}"' # Only two backslashes for regular + + raw_ast = ast.parse(raw_backslash) + regular_ast = ast.parse(regular_backslash) + + # The AST should show different string content + raw_content = raw_ast.body[0].value.values[0].value + regular_content = regular_ast.body[0].value.values[0].value + + # Raw should have literal backslash-n, regular should have actual newline + assert '\\\\n' in raw_content # literal backslash-n (two chars: \ and n) + assert '\n' in regular_content # actual newline character + assert raw_content != regular_content + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +def test_tstring_debug_specifier_limitations(): + """Test debug specifier limitations (same as f-strings)""" + # Debug specifiers work when at the start of the string + assert unparse(ast.parse('t"{name=}"')) == 't"{name=}"' + assert unparse(ast.parse('t"{value=:.2f}"')) == 't"{value=:.2f}"' + + # But are lost when there's a preceding literal (same limitation as f-strings) + assert unparse(ast.parse('t"Hello {name=}"')) == 't"Hello name={name!r}"' + assert unparse(ast.parse('t"Hello {name=!s}"')) == 't"Hello name={name!s}"' + assert unparse(ast.parse('t"Hello {name=:.2f}"')) == 't"Hello name={name:.2f}"' + + # This matches f-string behavior exactly + assert unparse(ast.parse('f"Hello {name=}"')) == 'f"Hello name={name!r}"' + + +@pytest.mark.skipif(sys.version_info < (3, 14), reason="Template strings require Python 3.14+") +def test_tstring_error_conditions(): + """Test that our implementation handles edge cases properly""" + # Test round-trip parsing for complex cases + complex_cases = [ + 't"Deep {t"nesting {t"level {x}"}"} works"', + 't"Format {value:{width}.{precision}f} complex"', + 't"Mixed {a!r} and {b=:.2f} specifiers"', + ] + + for case in complex_cases: + try: + # Parse as module, not expression + expected_ast = ast.parse(case) + unparsed = unparse(expected_ast) + actual_ast = ast.parse(unparsed) + compare_ast(expected_ast, actual_ast) + except Exception as e: + pytest.fail("Failed to handle complex case {}: {}".format(case, e)) \ No newline at end of file diff --git a/test/test_tuple_with_bug.py b/test/test_tuple_with_bug.py new file mode 100644 index 00000000..5d4eb6de --- /dev/null +++ b/test/test_tuple_with_bug.py @@ -0,0 +1,34 @@ +import ast + +from python_minifier import unparse +from python_minifier.ast_compare import compare_ast + + +def test_single_element_tuple_in_with(): + """Test that single-element tuples in with statements are preserved during minification.""" + + source = 'with(None,):pass' + + expected_ast = ast.parse(source) + minified = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(minified)) + + +def test_tuple_with_multiple_elements(): + """Test that multi-element tuples in with statements work correctly.""" + + source = 'with(a,b):pass' + + expected_ast = ast.parse(source) + minified = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(minified)) + + +def test_nested_tuple_with(): + """Test nested tuple structures in with statements.""" + + source = 'with((a,),b):pass' + + expected_ast = ast.parse(source) + minified = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(minified)) \ No newline at end of file diff --git a/test/test_unicode_cli.py b/test/test_unicode_cli.py index 6835aeb0..727ee4a2 100644 --- a/test/test_unicode_cli.py +++ b/test/test_unicode_cli.py @@ -30,8 +30,12 @@ def test_cli_output_flag_with_unicode(): assert result.returncode == 0, "CLI failed with encoding error: {}".format(safe_decode(result.stderr)) # Verify the output file was created and contains Unicode characters - with codecs.open(output_path, 'r', encoding='utf-8') as f: - minified_content = f.read() + if sys.version_info[0] >= 3: + with open(output_path, 'r', encoding='utf-8') as f: + minified_content = f.read() + else: + with codecs.open(output_path, 'r', encoding='utf-8') as f: + minified_content = f.read() # Verify problematic Unicode characters are preserved if hasattr(sys, 'pypy_version_info') and sys.version_info[0] >= 3: @@ -88,8 +92,12 @@ def test_cli_in_place_with_unicode(): assert result.returncode == 0, "CLI failed with encoding error: {}".format(safe_decode(result.stderr)) - with codecs.open(temp_file.name, 'r', encoding='utf-8') as f: - content = f.read() + if sys.version_info[0] >= 3: + with open(temp_file.name, 'r', encoding='utf-8') as f: + content = f.read() + else: + with codecs.open(temp_file.name, 'r', encoding='utf-8') as f: + content = f.read() if hasattr(sys, 'pypy_version_info') and sys.version_info[0] >= 3: # PyPy3: Unicode characters may be escaped as \\u escapes diff --git a/test/test_utf8_encoding.py b/test/test_utf8_encoding.py index f018e60a..5403690a 100644 --- a/test/test_utf8_encoding.py +++ b/test/test_utf8_encoding.py @@ -1,10 +1,9 @@ # -*- coding: utf-8 -*- -import pytest import python_minifier import tempfile import os import codecs - +import sys def test_minify_utf8_file(): """Test minifying a Python file with UTF-8 characters not in Windows default encoding.""" @@ -52,8 +51,12 @@ def arrow_symbols(): try: # Read the file and minify it # Python 2.7 doesn't support encoding parameter in open() - with codecs.open(temp_file, 'r', encoding='utf-8') as f: - original_content = f.read() + if sys.version_info[0] >= 3: + with open(temp_file, 'r', encoding='utf-8') as f: + original_content = f.read() + else: + with codecs.open(temp_file, 'r', encoding='utf-8') as f: + original_content = f.read() # This should work - minify the UTF-8 content minified = python_minifier.minify(original_content) @@ -63,12 +66,12 @@ def arrow_symbols(): # Test by executing the minified code and checking the actual values minified_globals = {} exec(minified, minified_globals) - + # The minified code should contain the same functions that return Unicode assert 'greet_in_greek' in minified_globals assert u"Γεια σας κόσμος" == minified_globals['greet_in_greek']() - - # Test that mathematical symbols are also preserved + + # Test that mathematical symbols are also preserved assert 'mathematical_formula' in minified_globals assert u"∑ from i=1 to ∞" in minified_globals['mathematical_formula']() @@ -101,11 +104,11 @@ def get_symbols(self): # Verify UTF-8 characters are preserved by executing the minified code minified_globals = {} exec(minified, minified_globals) - + # Test that the functions return the correct Unicode strings assert u"🐍" in minified_globals['emoji_function']() assert u"∆" in minified_globals['emoji_function']() - + # Test the class unicode_obj = minified_globals['UnicodeClass']() assert u"Héllö" in unicode_obj.message diff --git a/tox-windows.ini b/tox-windows.ini index 1a2be052..8db14a1d 100644 --- a/tox-windows.ini +++ b/tox-windows.ini @@ -1,5 +1,5 @@ [tox] -envlist = 3.8,3.9,3.10,3.11,3.12,3.13 +envlist = 3.8,3.9,3.10,3.11,3.12,3.13,3.14 [testenv] commands = @@ -140,3 +140,15 @@ deps = pyperf==2.7.0 pytest==8.3.3 PyYAML==6.0.2 + +[testenv:3.14] +basepython = python3.14 +deps = + colorama==0.4.6 + iniconfig==2.1.0 + packaging==25.0 + pip==25.2 + pluggy==1.6.0 + Pygments==2.19.2 + pytest==8.4.1 + PyYAML==6.0.2 diff --git a/tox.ini b/tox.ini index b89b21e4..25ef8ea0 100644 --- a/tox.ini +++ b/tox.ini @@ -1,9 +1,11 @@ [tox] -envlist = python27,python33,python34,python35,python36,python37,python38,python39,pypy,pypy3 +envlist = python27,python33,python34,python35,python36,python37,python38,python39,python310,python311,python312,python313,python314,pypy,pypy3 [testenv] +setenv = + PYTHONHASHSEED = 0 commands = - pytest {posargs:test} --junitxml=junit-{envname}.xml --maxfail=1 --verbose + pytest {posargs:test} --junitxml=junit-{envname}.xml --verbose [testenv:python27] basepython = /usr/bin/python2.7 @@ -74,7 +76,7 @@ deps = [testenv:python36] basepython = /usr/bin/python3.6 -deps = +deps = atomicwrites==1.4.1 attrs==20.3.0 importlib-metadata==4.8.3 @@ -91,7 +93,7 @@ deps = [testenv:python37] basepython = /usr/bin/python3.7 -deps = +deps = atomicwrites==1.4.1 attrs==20.3.0 importlib-metadata==6.7.0 @@ -108,7 +110,7 @@ deps = [testenv:python38] basepython = /usr/bin/python3.8 -deps = +deps = atomicwrites==1.4.1 attrs==20.3.0 more-itertools==10.5.0 @@ -188,9 +190,21 @@ deps = PyYAML==6.0.2 sh==2.0.7 +[testenv:python314] +basepython = /usr/local/bin/python3.14 +deps = + iniconfig==2.1.0 + packaging==25.0 + pip==25.2 + pluggy==1.6.0 + Pygments==2.19.2 + pytest==8.4.1 + PyYAML==6.0.2 + sh==2.2.2 + [testenv:pypy] basepython = /usr/bin/pypy -deps = +deps = atomicwrites==1.4.1 attrs==20.3.0 backports.functools-lru-cache==1.6.6 @@ -216,7 +230,7 @@ deps = [testenv:pypy3] basepython = /usr/bin/pypy3 -deps = +deps = atomicwrites==1.4.1 attrs==20.3.0 cffi==1.12.0 diff --git a/xtest/manifests/python3.14_test_manifest.yaml b/xtest/manifests/python3.14_test_manifest.yaml new file mode 100644 index 00000000..6c75d8d2 --- /dev/null +++ b/xtest/manifests/python3.14_test_manifest.yaml @@ -0,0 +1,9852 @@ +/usr/local/lib/python3.14/test/_test_atexit.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/_test_eintr.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/_test_embed_structseq.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/_test_gc_fast_cycles.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/_test_multiprocessing.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/_test_venv_multiprocessing.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/archiver_tests.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/audiotests.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/fork_wait.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/leakers/test_ctypes.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/leakers/test_selftype.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/list_tests.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/lock_tests.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/mapping_tests.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/multibytecodec_support.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/pickletester.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/regrtestdata/import_from_tests/test_regrtest_a.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/regrtestdata/import_from_tests/test_regrtest_b/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/regrtestdata/import_from_tests/test_regrtest_b/util.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/regrtestdata/import_from_tests/test_regrtest_c.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/seq_tests.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/signalinterproctester.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/string_tests.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test___all__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test__colorize.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test__interpchannels.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test__interpreters.py: +- options: + hoist_literals: false + preserve_globals: [w, obj, print, open] + status: passing +- options: + remove_literal_statements: true + hoist_literals: false + preserve_globals: [w, obj, print, open] + status: passing +- options: + rename_globals: true + hoist_literals: false + preserve_globals: [w, obj, print, open] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + hoist_literals: false + preserve_globals: [w, obj, print, open] + status: passing +/usr/local/lib/python3.14/test/test__locale.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test__opcode.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test__osx_support.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_abc.py: +- options: + preserve_locals: + - A + - B + - C + - D + status: passing +/usr/local/lib/python3.14/test/test_abstract_numbers.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_annotationlib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_argparse.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_array.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ast/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ast/snippets.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ast/test_ast.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ast/utils.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncgen.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/echo.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/echo2.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/echo3.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/functional.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_base_events.py: +- options: + preserve_locals: [zero_error, stop_loop_cb, stop_loop_coro] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [zero_error, stop_loop_cb, stop_loop_coro] + status: passing +- options: + rename_globals: true + preserve_locals: [zero_error, stop_loop_cb, stop_loop_coro] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [zero_error, stop_loop_cb, stop_loop_coro] + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_buffered_proto.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_context.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_eager_task_factory.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_free_threading.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_futures2.py: +- options: + preserve_locals: + - future + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_graph.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_locks.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_proactor_events.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_protocols.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_queues.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_runners.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_selector_events.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_sendfile.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_server.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_sock_lowlevel.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_ssl.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_sslproto.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_staggered.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_streams.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_subprocess.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_taskgroups.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_threads.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_timeouts.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_tools.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_transports.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_unix_events.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/test_waitfor.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_asyncio/utils.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_atexit.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_audit.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_augassign.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_base64.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_baseexception.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_bigaddrspace.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_bigmem.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_binascii.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_binop.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_bisect.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_bool.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_buffer.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_bufio.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_builtin.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_bytes.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_bz2.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_c_locale_coercion.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_calendar.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/check_config.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_abstract.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_bytearray.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_bytes.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_codecs.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_complex.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_config.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_dict.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_eval_code_ex.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_file.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_float.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_frame.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_function.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_getargs.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_hash.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_immortal.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_import.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_list.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_long.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_mem.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_number.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_object.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_opt.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_pyatomic.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_run.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_set.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_structmembers.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_sys.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_time.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_tuple.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_type.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_capi/test_watchers.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_cext/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_charmapcodec.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_class.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_cmath.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_cmd.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_cmd_line_script.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + preserve_globals: [example_args] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_globals: [example_args] + status: passing +/usr/local/lib/python3.14/test/test_code_module.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codeccallbacks.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codecencodings_cn.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codecencodings_hk.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codecencodings_iso2022.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codecencodings_jp.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codecencodings_kr.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codecencodings_tw.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codecmaps_cn.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codecmaps_hk.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codecmaps_jp.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codecmaps_kr.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codecmaps_tw.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codecs.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_codeop.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_collections.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_colorsys.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_compare.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_compileall.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_compiler_assemble.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_compiler_codegen.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_complex.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_concurrent_futures/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_concurrent_futures/executor.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_concurrent_futures/util.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_configparser.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_contains.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_context.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_copy.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_copyreg.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_cprofile.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_csv.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/__main__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/_support.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_array_in_pointer.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_as_parameter.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_buffers.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_callbacks.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_cast.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_cfuncs.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_checkretval.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_delattr.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_dlerror.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_dllist.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_errno.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_find.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_frombuffer.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_generated_structs.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_incomplete.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_init.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_internals.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_keeprefs.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_libc.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_loading.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_macholib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_memfunctions.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_numbers.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_parameters.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_pep3118.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_pickling.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_prototypes.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_python_api.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_random_things.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_refcounts.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_repr.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_returnfuncptrs.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_sizes.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_slicing.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_stringptr.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_strings.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_unaligned_structures.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_unicode.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_values.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_varsize_struct.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ctypes/test_wintypes.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_curses.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dataclasses/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dataclasses/dataclass_module_1.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dataclasses/dataclass_module_1_str.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dataclasses/dataclass_module_2.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dataclasses/dataclass_module_2_str.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dataclasses/dataclass_textanno.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_datetime.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_dbm.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dbm_dumb.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dbm_gnu.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dbm_ndbm.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dbm_sqlite3.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_decimal.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_decorators.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_defaultdict.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_deque.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_descrtut.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_dict.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dictviews.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_difflib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_doctest/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_doctest/decorator_mod.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_doctest/doctest_aliases.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_doctest/doctest_lineno.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_doctest/sample_doctest.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_doctest/sample_doctest_errors.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_doctest/sample_doctest_no_docstrings.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_doctest/sample_doctest_no_doctests.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_doctest/sample_doctest_skip.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_doctest/test_doctest2.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dtrace.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dynamic.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_dynamicclassattribute.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_eintr.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/__main__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test__encoded_words.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test__header_value_parser.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test_asian_codecs.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test_contentmanager.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_email/test_defect_handling.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test_email.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test_generator.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test_headerregistry.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test_inversion.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test_message.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test_parser.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test_pickleable.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test_policy.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/test_utils.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_email/torture_test.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_embed.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ensurepip.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_enumerate.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_eof.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_epoll.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_errno.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_except_star.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_exception_hierarchy.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_exception_variations.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_faulthandler.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_fcntl.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_file.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_file_eintr.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_filecmp.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_fileinput.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_fileio.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_fileutils.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_finalization.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_float.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_flufl.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_fnmatch.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_fork1.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_format.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_fractions.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_code.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_dict.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_enumerate.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_func_annotations.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_functools.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_gc.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_grp.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_heapq.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_iteration.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_itertools_batched.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_list.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_methodcaller.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_monitoring.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_races.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_reversed.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_set.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_slots.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_str.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_tokenize.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_type.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_free_threading/test_zip.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_frozen.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_fstring.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ftplib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_funcattrs.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_future_stmt/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_future_stmt/badsyntax_future.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_future_stmt/import_nested_scope_twice.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_future_stmt/nested_scope.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_future_stmt/test_future.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_future_stmt/test_future_flags.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_future_stmt/test_future_multiple_features.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_future_stmt/test_future_multiple_imports.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_future_stmt/test_future_single_import.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_gc.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_gdb/gdb_sample.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_generator_stop.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_generators.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_genericalias.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_genericpath.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_genexps.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_getopt.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_getpass.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_getpath.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_glob.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_global.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_graphlib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_grp.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_gzip.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_hash.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_hashlib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_heapq.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_hmac.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_html.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_htmlparser.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_http_cookiejar.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_http_cookies.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_httplib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_httpservers.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_idle.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_imaplib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/__main__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/circular_imports/binding.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/circular_imports/binding2.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/circular_imports/singlephase.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/circular_imports/subpkg/util.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/circular_imports/subpkg2/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/circular_imports/util.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/double_const.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/package/submodule.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/package2/submodule2.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/package3/submodule.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/package4/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/package4/submodule.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_import/data/unwritable/x.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/abc.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/builtin/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/builtin/test_finder.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/builtin/test_loader.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/extension/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/extension/_test_nonmodule_cases.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/extension/test_case_sensitivity.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/extension/test_finder.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/extension/test_loader.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + preserve_globals: [MultiPhaseExtensionModuleTests] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_globals: [MultiPhaseExtensionModuleTests] + status: passing +/usr/local/lib/python3.14/test/test_importlib/extension/test_path_hook.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/frozen/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/frozen/test_finder.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/frozen/test_loader.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/import_/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/import_/test___loader__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/import_/test___package__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/import_/test_api.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/import_/test_caching.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/import_/test_fromlist.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/import_/test_meta_path.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/import_/test_packages.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/import_/test_relative_imports.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/metadata/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/metadata/_context.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/metadata/data/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/metadata/data/sources/example/example/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/metadata/data/sources/example2/example2/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/metadata/stubs.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/namespace_pkgs/both_portions/foo/one.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/namespace_pkgs/both_portions/foo/two.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/namespace_pkgs/module_and_namespace_package/a_test.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/namespace_pkgs/not_a_namespace_pkg/foo/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/namespace_pkgs/not_a_namespace_pkg/foo/one.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/namespace_pkgs/portion1/foo/one.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/namespace_pkgs/portion2/foo/two.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/namespace_pkgs/project1/parent/child/one.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/namespace_pkgs/project2/parent/child/two.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/namespace_pkgs/project3/parent/child/three.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/partial/cfimport.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/partial/pool_in_threads.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/resources/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/resources/zip.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/source/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/source/test_case_sensitivity.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/source/test_finder.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/source/test_path_hook.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/source/test_source_encoding.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/test_abc.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/test_api.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/test_lazy.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/test_locks.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/test_pkg_import.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/test_spec.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/test_threaded_import.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/test_util.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/threaded_import_hangers.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_importlib/util.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_index.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_inspect/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_inspect/inspect_deferred_annotations.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_inspect/inspect_fodder.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_inspect/inspect_fodder2.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_inspect/inspect_stock_annotations.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_inspect/inspect_stringized_annotations.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_inspect/inspect_stringized_annotations_2.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_inspect/inspect_stringized_annotations_pep695.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_int.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_int_literal.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_interpreters/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_interpreters/utils.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_io.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ioctl.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ipaddress.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_isinstance.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_iterlen.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_itertools.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/__main__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_decode.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_default.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_dump.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_encode_basestring_ascii.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_enum.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_fail.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_float.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_indent.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_pass1.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_pass2.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_pass3.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_recursion.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_scanstring.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_separators.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_speedups.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_tool.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_json/test_unicode.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_keyword.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_keywordonlyarg.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_largefile.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_linecache.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_list.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_lltrace.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_locale.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_long.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_longexp.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_lzma.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_mailbox.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_marshal.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_math.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_math_property.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_memoryview.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_metaclass.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_mimetypes.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_minidom.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_mmap.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_module/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_module/bad_getattr.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_module/bad_getattr2.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_module/bad_getattr3.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_module/final_a.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_module/final_b.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_module/good_getattr.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_modulefinder.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_monitoring.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multibytecodec.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_fork/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_fork/test_manager.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_fork/test_misc.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_fork/test_processes.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_fork/test_threads.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_forkserver/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_forkserver/test_manager.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_forkserver/test_misc.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_forkserver/test_processes.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_forkserver/test_threads.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_main_handling.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_spawn/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_spawn/test_manager.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_spawn/test_misc.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_spawn/test_processes.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_multiprocessing_spawn/test_threads.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_named_expressions.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_netrc.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ntpath.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_nturl2path.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_numeric_tower.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_opcache.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_opcodes.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_openpty.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_operator.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_optimizer.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_optparse.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ordered_dict.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_os.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_osx_env.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pathlib/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pathlib/support/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_peg_generator/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pep646_syntax.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_perf_profiler.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_perfmaps.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pickle.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_picklebuffer.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pickletools.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_pkg.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pkgutil.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_platform.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_plistlib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_poll.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_popen.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_poplib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_posix.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_posixpath.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pow.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pprint.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_print.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_profile.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pty.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pulldom.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pwd.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_py_compile.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pyclbr.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pydoc/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pydoc/module_none.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pydoc/pydoc_mod.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pydoc/pydocfodder.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pyexpat.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pyrepl/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pyrepl/__main__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pyrepl/support.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pyrepl/test_eventqueue.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pyrepl/test_input.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pyrepl/test_interact.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pyrepl/test_keymap.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pyrepl/test_terminfo.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_pyrepl/test_utils.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_queue.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_quopri.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_raise.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_random.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_range.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_re.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_readline.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_regrtest.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_remote_pdb.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_repl.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_resource.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_rlcompleter.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_robotparser.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_sax.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_sched.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_scope.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_script_helper.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_secrets.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_select.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_selectors.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_set.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_shelve.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_shlex.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_shutil.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_signal.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_site.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_slice.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_smtplib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_smtpnet.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_socket.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_socketserver.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_sort.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_source_encoding.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_sqlite3/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_sqlite3/__main__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_sqlite3/test_cli.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_sqlite3/test_types.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_sqlite3/util.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ssl.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_stable_abi_ctypes.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_stat.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_statistics.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_str.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_strftime.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_string/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_string/_support.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_string/test_string.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_string_literals.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_stringprep.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_strptime.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_strtod.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_struct.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_structseq.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_subclassinit.py: +- options: + preserve_locals: + - MyClass + - NotGoingToWork + - Descriptor + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_subprocess.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_sundry.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_super.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_support.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_symtable.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_syntax.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_sys_setprofile.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_sysconfig.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_syslog.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tabnanny.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tarfile.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_tcl.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tempfile.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_termios.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_textwrap.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_thread.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_thread_local_bytecode.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_threadedtempfile.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_threadsignals.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_time.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_timeit.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_timeout.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tkinter/support.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tokenize.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tomllib/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tomllib/burntsushi.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tools/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tools/__main__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tools/i18n_data/comments.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tools/i18n_data/docstrings.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tools/i18n_data/fileloc.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tools/test_makefile.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ttk_textonly.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tty.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_tuple.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_turtle.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_type_aliases.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_type_annotations.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_type_cache.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_type_comments.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_type_params.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_typechecks.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_ucn.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unary.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unicode_file.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unicode_file_functions.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unicodedata.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/_test_warnings.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/dummy.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/namespace_test_pkg/bar/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/namespace_test_pkg/bar/test_bar.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/namespace_test_pkg/noop/no2/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/namespace_test_pkg/noop/no2/test_no2.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/namespace_test_pkg/noop/test_noop.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/namespace_test_pkg/test_foo.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/support.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_assertions.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_async_case.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_break.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_discovery.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_functiontestcase.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_program.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_result.py: +- options: {} + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_setups.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_skipping.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_suite.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_util.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/testmock/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/testmock/__main__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/testmock/support.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/testmock/testasync.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/testmock/testcallable.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/testmock/testhelpers.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/testmock/testmagicmethods.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/testmock/testmock.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/testmock/testsealable.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/testmock/testsentinel.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/testmock/testthreadingmock.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_unittest/testmock/testwith.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_univnewlines.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_unparse.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_urllib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_urllib2.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_urllib2_localnet.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_urllib2net.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_urllib_response.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_urllibnet.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_urlparse.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_userdict.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_userlist.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_userstring.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_utf8_mode.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_utf8source.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_uuid.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_venv.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_wait3.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_wait4.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_warnings/__main__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_warnings/data/import_warning.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_warnings/data/package_helper.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_warnings/data/stacklevel.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_wave.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_weakset.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_webbrowser.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_xml_dom_minicompat.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_xml_dom_xmlbuilder.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_xml_etree.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_xml_etree_c.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_xxlimited.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_xxtestfuzz.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zipapp.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zipfile/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zipfile/_path/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zipfile/_path/_functools.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zipfile/_path/_itertools.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zipfile/_path/_support.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zipfile/test_core.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zipimport.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zipimport_support.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zlib.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zoneinfo/__init__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zoneinfo/__main__.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zoneinfo/_support.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zoneinfo/test_zoneinfo_property.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_zstd.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + preserve_globals: [setUpModule] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_globals: [setUpModule] + status: passing +/usr/local/lib/python3.14/test/test_zipfile64.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing + +/usr/local/lib/python3.14/test/test_asyncio/test_pep492.py: +- options: + preserve_locals: [foo] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [foo] + status: passing +- options: + rename_globals: true + preserve_locals: [foo] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [foo] + status: passing + +/usr/local/lib/python3.14/test/test_call.py: +- options: + convert_posargs_to_args: false + status: passing +- options: + remove_literal_statements: true + convert_posargs_to_args: false + status: passing +- options: + rename_globals: true + convert_posargs_to_args: false + status: passing +- options: + remove_literal_statements: true + rename_globals: true + convert_posargs_to_args: false + status: passing + +/usr/local/lib/python3.14/test/test_cmd_line.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing + +/usr/local/lib/python3.14/test/test_ctypes/test_functions.py: +- options: + remove_object_base: false + status: passing +- options: + remove_literal_statements: true + remove_object_base: false + status: passing +- options: + rename_globals: true + remove_object_base: false + status: passing +- options: + remove_literal_statements: true + rename_globals: true + remove_object_base: false + status: passing +/usr/local/lib/python3.14/test/test_docxmlrpc.py: +- options: + preserve_locals: [add, annotation] + remove_annotations: false + status: passing +- options: + preserve_locals: [add, annotation] + remove_annotations: false + rename_globals: true + status: passing +/usr/local/lib/python3.14/test/test_functools.py: +- options: + preserve_locals: [arg, a] + remove_annotations: false + convert_posargs_to_args: false + status: passing +- options: + remove_literal_statements: true + preserve_locals: [arg, a] + remove_annotations: false + convert_posargs_to_args: false + status: passing +- options: + rename_globals: true + preserve_locals: [arg, a] + remove_annotations: false + convert_posargs_to_args: false + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [arg, a] + remove_annotations: false + convert_posargs_to_args: false + status: passing +/usr/local/lib/python3.14/test/test_genericclass.py: +- options: + preserve_locals: [A, B, C, D, Meta, C_is_none] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [A, B, C, D, Meta, C_is_none] + status: passing +- options: + rename_globals: true + preserve_locals: [A, B, C, D, Meta, C_is_none] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [A, B, C, D, Meta, C_is_none] + status: passing +/usr/local/lib/python3.14/test/test_grammar.py: +- options: + remove_annotations: false + status: passing +- options: + remove_annotations: false + remove_literal_statements: true + status: passing +- options: + remove_annotations: false + rename_globals: true + status: passing +- options: + remove_annotations: false + rename_globals: true + remove_literal_statements: true + status: passing +/usr/local/lib/python3.14/test/test_inspect/test_inspect.py: +- options: + remove_annotations: false + convert_posargs_to_args: false + hoist_literals: false + preserve_locals: [arg1, arg2, arg3, a, b, c, d, self, x, y, z, foo, bar, baz, test, a_po, b_po, c_po, pk, kw, args, kwargs] + status: passing +- options: + remove_annotations: false + convert_posargs_to_args: false + hoist_literals: false + remove_literal_statements: true + preserve_locals: [arg1, arg2, arg3, a, b, c, d, self, x, y, z, foo, bar, baz, test, a_po, b_po, c_po, pk, kw, args, kwargs] + status: passing +- options: + remove_annotations: false + convert_posargs_to_args: false + hoist_literals: false + rename_globals: true + preserve_locals: [arg1, arg2, arg3, a, b, c, d, self, x, y, z, foo, bar, baz, test, a_po, b_po, c_po, pk, kw, args, kwargs] + status: passing +- options: + remove_annotations: false + convert_posargs_to_args: false + hoist_literals: false + remove_literal_statements: true + rename_globals: true + preserve_locals: [arg1, arg2, arg3, a, b, c, d, self, x, y, z, foo, bar, baz, test, a_po, b_po, c_po, pk, kw, args, kwargs] + status: passing +/usr/local/lib/python3.14/test/test_memoryio.py: +- options: + preserve_locals: [PickleTestMemIO] + status: passing +- options: + preserve_locals: [PickleTestMemIO] + remove_literal_statements: true + status: passing +- options: + preserve_locals: [PickleTestMemIO] + rename_globals: true + status: passing +- options: + preserve_locals: [PickleTestMemIO] + remove_literal_statements: true + rename_globals: true + status: passing + +/usr/local/lib/python3.14/test/test_positional_only_arg.py: +- options: + remove_annotations: false + convert_posargs_to_args: false + preserve_locals: [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, something, x1, x2, x3, y1, y2] + status: passing +- options: + remove_literal_statements: true + remove_annotations: false + convert_posargs_to_args: false + preserve_locals: [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, something, x1, x2, x3, y1, y2] + status: passing +- options: + rename_globals: true + remove_annotations: false + convert_posargs_to_args: false + preserve_locals: [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, something, x1, x2, x3, y1, y2] + preserve_globals: [global_pos_only_f, global_pos_only_and_normal, global_pos_only_defaults] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + remove_annotations: false + convert_posargs_to_args: false + preserve_locals: [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, something, x1, x2, x3, y1, y2] + preserve_globals: [global_pos_only_f, global_pos_only_and_normal, global_pos_only_defaults] + status: passing + +/usr/local/lib/python3.14/test/test_property.py: +- options: + preserve_locals: [getter] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [getter] + status: passing +- options: + rename_globals: true + preserve_locals: [getter] + preserve_globals: [PropertyUnreachableAttributeWithName, PropertyUnreachableAttributeNoName] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [getter] + preserve_globals: [PropertyUnreachableAttributeWithName, PropertyUnreachableAttributeNoName] + status: passing + +/usr/local/lib/python3.14/test/test_pstats.py: +- options: + preserve_locals: [pass1, pass2, pass3] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [pass1, pass2, pass3] + status: passing +- options: + rename_globals: true + preserve_locals: [pass1, pass2, pass3] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [pass1, pass2, pass3] + status: passing + +/usr/local/lib/python3.14/test/test_reprlib.py: +- options: + remove_annotations: false + status: passing +- options: + remove_literal_statements: true + remove_annotations: false + status: passing +- options: + rename_globals: true + remove_annotations: false + preserve_globals: [ClassWithFailingRepr, ReprTests] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + remove_annotations: false + preserve_globals: [ClassWithFailingRepr, ReprTests] + status: passing + +/usr/local/lib/python3.14/test/test_richcmp.py: +- options: + preserve_locals: [Spam] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [Spam] + status: passing +- options: + rename_globals: true + preserve_locals: [Spam] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [Spam] + status: passing +/usr/local/lib/python3.14/test/test_threading_local.py: +- options: + preserve_locals: [Loop] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [Loop] + status: passing +- options: + rename_globals: true + preserve_locals: [Loop] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [Loop] + status: passing +/usr/local/lib/python3.14/test/test_types.py: +- options: + preserve_locals: [x] + remove_annotations: false + status: passing +- options: + remove_literal_statements: true + preserve_locals: [x] + remove_annotations: false + status: passing +- options: + rename_globals: true + preserve_locals: [x] + remove_annotations: false + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [x] + remove_annotations: false + status: passing +/usr/local/lib/python3.14/test/test_typing.py: +- options: + preserve_locals: [x, a, left, args, kwargs, return, other, self] + remove_annotations: false + hoist_literals: false + status: passing +- options: + remove_literal_statements: true + preserve_locals: [x, a, left, args, kwargs, return, other, self] + remove_annotations: false + hoist_literals: false + status: passing +- options: + rename_globals: true + preserve_locals: [x, a, left, args, kwargs, return, other, self] + remove_annotations: false + hoist_literals: false + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [x, a, left, args, kwargs, return, other, self] + remove_annotations: false + hoist_literals: false + status: passing +/usr/local/lib/python3.14/test/test_unicode_identifiers.py: +- options: + preserve_locals: [Unicode] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [Unicode] + status: passing +- options: + rename_globals: true + preserve_locals: [Unicode] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [Unicode] + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_loader.py: +- options: + preserve_locals: [MyTestCase, MyTest] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [MyTestCase, MyTest] + status: passing +- options: + rename_globals: true + preserve_locals: [MyTestCase, MyTest] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [MyTestCase, MyTest] + status: passing +/usr/local/lib/python3.14/test/test_unittest/test_runner.py: +- options: + preserve_locals: [cleanup1, cleanup2, CleanUpExc, exc2] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [cleanup1, cleanup2, CleanUpExc, exc2] + status: passing +- options: + rename_globals: true + preserve_locals: [cleanup1, cleanup2, CleanUpExc, exc2] + preserve_globals: [CustomError] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [cleanup1, cleanup2, CleanUpExc, exc2] + preserve_globals: [CustomError] + status: passing +/usr/local/lib/python3.14/test/test_weakref.py: +- options: + preserve_locals: [MyConfig] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [MyConfig] + status: passing +- options: + rename_globals: true + preserve_locals: [MyConfig] + preserve_globals: [FinalizeTestCase] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [MyConfig] + preserve_globals: [FinalizeTestCase] + status: passing +/usr/local/lib/python3.14/test/test_wsgiref.py: +- options: + preserve_locals: [CustomException] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [CustomException] + status: passing +- options: + rename_globals: true + preserve_locals: [CustomException] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [CustomException] + status: passing +/usr/local/lib/python3.14/test/test_xmlrpc.py: +- options: + preserve_locals: [my_function, dispatched_func, foobar] + status: passing +- options: + rename_globals: true + preserve_locals: [my_function, dispatched_func, foobar] + status: passing +/usr/local/lib/python3.14/test/test_yield_from.py: +- options: + preserve_locals: [spam, eggs] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [spam, eggs] + status: passing +- options: + rename_globals: true + preserve_locals: [spam, eggs] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [spam, eggs] + status: passing +/usr/local/lib/python3.14/test/test_zoneinfo/test_zoneinfo.py: +- options: + preserve_locals: [ZISubclass, dt, fold, offset] + status: passing +- options: + remove_literal_statements: true + preserve_locals: [ZISubclass, dt, fold, offset] + status: passing +- options: + rename_globals: true + preserve_locals: [ZISubclass, dt, fold, offset] + preserve_globals: [ZONEINFO_DATA, ZONEINFO_DATA_V1, setUpModule, tearDownModule] + status: passing +- options: + remove_literal_statements: true + rename_globals: true + preserve_locals: [ZISubclass, dt, fold, offset] + preserve_globals: [ZONEINFO_DATA, ZONEINFO_DATA_V1, setUpModule, tearDownModule] + status: passing +/usr/local/lib/python3.14/test/test_string/test_templatelib.py: +- options: + preserve_locals: [x, name, user, a, age, country] + status: passing +- options: + preserve_locals: [x, name, user, a, age, country] + remove_literal_statements: true + status: passing +- options: + preserve_locals: [x, name, user, a, age, country] + rename_globals: true + status: passing +- options: + preserve_locals: [x, name, user, a, age, country] + remove_literal_statements: true + rename_globals: true + status: passing