diff --git a/.github/github_sucks b/.github/github_sucks index e69de29b..8b137891 100644 --- a/.github/github_sucks +++ b/.github/github_sucks @@ -0,0 +1 @@ + diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index e5d39ea9..ea9c5b0c 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -8,12 +8,15 @@ concurrency: group: release cancel-in-progress: false +env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + jobs: release: runs-on: ubuntu-latest container: - image: danielflook/python-minifier-build:python3.11-2022-10-25 + image: danielflook/python-minifier-build:python3.12-2024-01-12 steps: - name: Checkout uses: actions/checkout@v3 @@ -25,8 +28,8 @@ jobs: - name: Build package run: | - pip3 install --upgrade setuptools wheel - python3 setup.py sdist bdist_wheel --universal + pip3 install --upgrade build + python3 -m build - uses: actions/upload-artifact@v3 with: @@ -51,7 +54,7 @@ jobs: id-token: write environment: name: pypi - url: https://pypi.org/project/python-minifier/ + url: https://pypi.org/project/python-minifier/${{ github.event.release.tag_name }} steps: - uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/release_test.yaml b/.github/workflows/release_test.yaml index 37a51c8e..b655747c 100644 --- a/.github/workflows/release_test.yaml +++ b/.github/workflows/release_test.yaml @@ -2,28 +2,40 @@ name: Release Test on: [push] +env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + jobs: - package: - name: Create Package + package_python3: + name: Create sdist and Python 3 Wheel runs-on: ubuntu-latest + outputs: + sdist: ${{ steps.package.outputs.sdist }} + wheel: ${{ steps.package.outputs.wheel }} container: - image: danielflook/python-minifier-build:python3.11-2022-10-25 + image: danielflook/python-minifier-build:python3.12-2024-01-12 steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 + show-progress: false - name: Set version statically run: | - VERSION="$(python3 setup.py --version)" + pip3 install setuptools_scm + VERSION="$(python3 -m setuptools_scm)" sed -i "s/setup_requires=.*/version='$VERSION',/; s/use_scm_version=.*//" setup.py - name: Create Packages + id: package run: | - pip3 install --upgrade setuptools wheel twine - python3 setup.py sdist bdist_wheel --universal + 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" - uses: actions/upload-artifact@v3 with: @@ -31,12 +43,40 @@ jobs: path: dist/ if-no-files-found: error - test_docs: + package_python2: + name: Create Python 2 Wheel + runs-on: ubuntu-latest + needs: [package_python3] + outputs: + wheel: ${{ steps.package.outputs.wheel }} + container: + image: danielflook/python-minifier-build:python2.7-2024-01-12 + steps: + - uses: actions/download-artifact@v3 + with: + name: dist + path: dist/ + + - name: Build wheel + id: package + run: | + dnf install -y findutils + pip install --upgrade wheel + pip wheel dist/${{ needs.package_python3.outputs.sdist }} -w dist + echo "wheel=$(find dist -name '*-py2-*.whl' -printf "%f\n")" >> "$GITHUB_OUTPUT" + + - uses: actions/upload-artifact@v3 + with: + name: dist + path: dist/ + if-no-files-found: error + + documentation: name: Test Documentation runs-on: ubuntu-latest - needs: [package] + needs: [package_python3] container: - image: danielflook/python-minifier-build:python3.11-2022-10-25 + image: danielflook/python-minifier-build:python3.12-2024-01-12 steps: - uses: actions/download-artifact@v3 with: @@ -45,11 +85,14 @@ jobs: - name: Install package run: | - pip3 install dist/*.tar.gz + pip3 install dist/${{needs.package_python3.outputs.sdist}} pyminify --version - name: Checkout uses: actions/checkout@v3 + with: + fetch-depth: 0 + show-progress: false - name: Build documentation run: | @@ -59,13 +102,14 @@ jobs: test_package: name: Test Package runs-on: ubuntu-latest - needs: [package] + 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"] - package_type: [.tar.gz, .whl] + python: ["2.7", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] + package_type: [sdist, wheel] container: - image: danielflook/python-minifier-build:python${{ matrix.python }}-2022-10-25 + image: danielflook/python-minifier-build:python${{ matrix.python }}-2024-01-12 steps: - uses: actions/download-artifact@v3 with: @@ -74,11 +118,21 @@ jobs: - name: Install package run: | - pip${{ matrix.python }} install dist/*${{ matrix.package_type }} + 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 - name: Checkout uses: actions/checkout@v3 + with: + fetch-depth: 0 + show-progress: false - name: Test pyminify run: | @@ -90,12 +144,12 @@ jobs: test_typing: runs-on: ubuntu-latest - needs: [package] + needs: [package_python3] strategy: matrix: - package_type: [.tar.gz, .whl] + package_type: [sdist, wheel] container: - image: danielflook/python-minifier-build:python3.11-2022-10-25 + image: danielflook/python-minifier-build:python3.12-2024-01-12 steps: - uses: actions/download-artifact@v3 with: @@ -104,14 +158,21 @@ jobs: - name: Install package run: | - pip3.11 install dist/*${{ matrix.package_type }} + if [[ "${{ matrix.package_type }}" == "sdist" ]]; then + pip3.12 install dist/${{needs.package_python3.outputs.sdist}} + else + pip3.12 install dist/${{needs.package_python3.outputs.wheel}} + fi - name: Checkout uses: actions/checkout@v3 + with: + fetch-depth: 0 + show-progress: false - name: Test typing run: | - pip3.11 install mypy types-setuptools + pip3.12 install mypy types-setuptools mypy --strict typing_test/test_typing.py if mypy --strict typing_test/test_badtyping.py; then @@ -119,4 +180,4 @@ jobs: exit 1 fi - stubtest python_minifier + stubtest python_minifier --allowlist typing_test/stubtest-allowlist.txt diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index f9596298..df3f0951 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -2,6 +2,9 @@ name: Unit Test on: [push] +env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + jobs: test: @@ -10,9 +13,9 @@ 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", "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", "pypy", "pypy3"] container: - image: danielflook/python-minifier-build:${{ matrix.python }}-2022-10-25 + image: danielflook/python-minifier-build:${{ matrix.python }}-2024-01-12 steps: - name: Checkout uses: actions/checkout@v3 diff --git a/.github/workflows/test_corpus.yaml b/.github/workflows/test_corpus.yaml index d8368dd9..99da2e12 100644 --- a/.github/workflows/test_corpus.yaml +++ b/.github/workflows/test_corpus.yaml @@ -34,6 +34,9 @@ on: required: false default: false +env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + jobs: generate_results: name: Minify Corpus @@ -41,10 +44,10 @@ 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"] + python: ["2.7", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] ref: ["${{ inputs.ref }}", "${{ inputs.base-ref }}"] container: - image: danielflook/python-minifier-build:${{ matrix.python }}-2022-10-25 + image: danielflook/python-minifier-build:python${{ matrix.python }}-2024-01-12 volumes: - /corpus:/corpus - /corpus-results:/corpus-results @@ -64,31 +67,43 @@ jobs: path: python-minifier - name: Install ref + id: install run: | set -ex (cd python-minifier && git log --pretty=format:'%H' -n 1) > sha.txt cat sha.txt VERSION=0.0.0 sed -i "s/setup_requires=.*/version='$VERSION',/; s/use_scm_version=.*//" python-minifier/setup.py - (cd python-minifier && ${{matrix.python}} setup.py install) + + if ! pip${{ matrix.python }} install python-minifier/ 2>stderr.log; then + echo stderr.log + + if grep -q -E 'require a different python version|requires a different Python' stderr.log; then + echo "${{ matrix.ref }} doesn't support Python ${{ matrix.python }}. Skipping." + echo "skip=true" >> "$GITHUB_OUTPUT" + else + exit 1 + fi + fi - name: Run tests + if: steps.install.outputs.skip != 'true' run: | - if [[ "${{ matrix.python }}" == "python3.3" || "${{ matrix.python }}" == "python3.4" || "${{ matrix.python }}" == "python3.5" ]]; then + if [[ "${{ matrix.python }}" == "3.3" || "${{ matrix.python }}" == "3.4" || "${{ matrix.python }}" == "3.5" ]]; then # These versions randomise the hash seed, but don't preserve dict order # This affects how names are assigned. Disable the hash randomisation for # deterministic results. export PYTHONHASHSEED=0 fi - ${{matrix.python}} workflow/corpus_test/generate_results.py /corpus /corpus-results $(> $GITHUB_STEP_SUMMARY + python3.12 workflow/corpus_test/generate_report.py /corpus-results ${{ inputs.ref }} $(> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/verify_release.yaml b/.github/workflows/verify_release.yaml index 54db516d..f8ecfcca 100644 --- a/.github/workflows/verify_release.yaml +++ b/.github/workflows/verify_release.yaml @@ -8,14 +8,17 @@ on: required: true type: string +env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + jobs: test_package: runs-on: ubuntu-latest strategy: matrix: - python: ["2.7", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11"] + python: ["2.7", "3.3", "3.4", "3.5", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"] container: - image: danielflook/python-minifier-build:python${{ matrix.python }}-2022-10-25 + image: danielflook/python-minifier-build:python${{ matrix.python }}-2024-01-12 steps: - name: Test run: | diff --git a/.github/workflows/xtest.yaml b/.github/workflows/xtest.yaml index 245114de..bebbab5f 100644 --- a/.github/workflows/xtest.yaml +++ b/.github/workflows/xtest.yaml @@ -2,6 +2,9 @@ name: Regression Test on: [pull_request] +env: + ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true + jobs: test: @@ -10,9 +13,9 @@ 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", "pypy3"] + python: ["python2.7", "python3.3", "python3.4", "python3.5", "python3.6", "python3.7", "python3.8", "python3.9", "python3.10", "python3.11", "python3.12", "pypy3"] container: - image: danielflook/python-minifier-build:${{ matrix.python }}-2022-10-25 + image: danielflook/python-minifier-build:${{ matrix.python }}-2024-01-12 steps: - name: Checkout uses: actions/checkout@v3 @@ -35,7 +38,7 @@ jobs: (cd /usr/lib64/pypy3-7.0/lib-python/3/test && pypy3 make_ssl_certs.py) fi - tox -r -e $(echo "${{ matrix.python }}" | tr -d .) xtest + tox -r -e $(echo "${{ matrix.python }}" | tr -d .) -- xtest test-corpus: needs: test diff --git a/README.md b/README.md index 31c7d8bd..40863605 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.11. Previous releases supported Python 2.6. +python-minifier currently supports Python 2.7 and Python 3.3 to 3.12. Previous releases supported Python 2.6. * [PyPI](https://pypi.org/project/python-minifier/) * [Documentation](https://dflook.github.io/python-minifier/) @@ -107,7 +107,7 @@ $ pip install python-minifier Note that python-minifier depends on the python interpreter for parsing source code, so install using a version of python appropriate for your source. -python-minifier runs with and can minify code written for Python 2.7 and Python 3.3 to 3.11. +python-minifier runs with and can minify code written for Python 2.7 and Python 3.3 to 3.12. ## Usage diff --git a/corpus_test/generate_report.py b/corpus_test/generate_report.py index fccf9beb..b0ee2d04 100644 --- a/corpus_test/generate_report.py +++ b/corpus_test/generate_report.py @@ -54,12 +54,12 @@ def add(self, result: Result): @property def mean_time(self) -> float: """Return the mean time to minify a file""" - return self.total_time / self.valid_count + return self.total_time / self.valid_count if self.valid_count else 0 @property def mean_percent_of_original(self) -> float: """Return the mean minified size as a percent of the original size""" - return self.total_percent_of_original / self.valid_count + return self.total_percent_of_original / self.valid_count if self.valid_count else 0 def larger_than_original(self) -> Iterable[Result]: """Return those entries that have a larger minified size than the original size""" @@ -257,7 +257,11 @@ def report_larger_than_base(results_dir: str, python_versions: str, minifier_sha except FileNotFoundError: continue - base_summary = result_summary(results_dir, python_version, base_sha) + try: + base_summary = result_summary(results_dir, python_version, base_sha) + except FileNotFoundError: + continue + larger_than_original = sorted(summary.compare_size_increase(base_summary), key=lambda result: result.original_size)[:10] for entry in larger_than_original: @@ -275,7 +279,10 @@ def report_slowest(results_dir: str, python_versions: str, minifier_sha: str) -> |--------------|--------------:|--------------:|-----:|''' for python_version in python_versions: - summary = result_summary(results_dir, python_version, minifier_sha) + try: + summary = result_summary(results_dir, python_version, minifier_sha) + except FileNotFoundError: + continue for entry in sorted(summary.entries.values(), key=lambda entry: entry.time, reverse=True)[:10]: yield f'| {entry.corpus_entry} | {entry.original_size} | {entry.minified_size} | {entry.time:.3f} |' @@ -308,7 +315,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']: + 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']: try: summary = result_summary(results_dir, python_version, minifier_sha) except FileNotFoundError: @@ -331,9 +338,9 @@ def format_size_change_detail() -> str: got_smaller_count = len(list(summary.compare_size_decrease(base_summary))) if got_bigger_count > 0: - s += f', {got_bigger_count}:chart_with_upwards_trend:' + s += f', {got_bigger_count} :chart_with_upwards_trend:' if got_smaller_count > 0: - s += f', {got_smaller_count}:chart_with_downwards_trend:' + s += f', {got_smaller_count} :chart_with_downwards_trend:' s += ')' @@ -351,11 +358,11 @@ def format_size_change_detail() -> str: ) if ENHANCED_REPORT: - yield from report_larger_than_original(results_dir, ['3.11'], minifier_sha) - yield from report_larger_than_base(results_dir, ['3.11'], minifier_sha, base_sha) - yield from report_slowest(results_dir, ['3.11'], 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'], minifier_sha) - yield from report_exceptions(results_dir, ['3.6', '3.7', '3.8', '3.9', '3.10', '3.11'], minifier_sha) + yield from report_larger_than_original(results_dir, ['3.12'], minifier_sha) + yield from report_larger_than_base(results_dir, ['3.12'], minifier_sha, base_sha) + yield from report_slowest(results_dir, ['3.12'], 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'], minifier_sha) + yield from report_exceptions(results_dir, ['3.6', '3.7', '3.8', '3.9', '3.10', '3.11', '3.12'], minifier_sha) def main(): diff --git a/docker/Dockerfile-fedora30 b/docker/Dockerfile-fedora30 index 37912b4e..525270cd 100644 --- a/docker/Dockerfile-fedora30 +++ b/docker/Dockerfile-fedora30 @@ -27,6 +27,7 @@ RUN dnf install -y \ python27 \ python2-test \ python2-pip \ + findutils \ && dnf clean all && rm -rf /var/cache/dnf/* ## diff --git a/docker/Dockerfile-fedora38 b/docker/Dockerfile-fedora38 new file mode 100644 index 00000000..a6a0bbc9 --- /dev/null +++ b/docker/Dockerfile-fedora38 @@ -0,0 +1,47 @@ +FROM fedora:38 AS python3.12 + +# CircleCI required tools +RUN dnf install -y \ + git \ + tar \ + gzip \ + gpg \ + ca-certificates \ + && dnf clean all && rm -rf /var/cache/dnf/* + +# Development tools +RUN dnf install -y \ + @development-tools \ + findutils \ + zlib-devel \ + bzip2-devel \ + ncurses-devel \ + gdbm-devel \ + openssl-devel \ + sqlite-devel \ + tk-devel \ + libuuid-devel \ + readline-devel \ + libnsl2-devel \ + xz-devel \ + libffi-devel \ + wget \ + && git clone https://github.com/python/cpython.git \ + && cd cpython \ + && git checkout v3.12.1 \ + && ./configure \ + && make \ + && make install \ + && cd .. \ + && rm -rf cpython \ + && dnf clean all && rm -rf /var/cache/dnf/* + +# Other packages required for tests +RUN dnf install -y \ + bzip2 \ + && dnf clean all && rm -rf /var/cache/dnf/* + +RUN pip3 install tox==4.11.3 + +WORKDIR /tmp/work +ENTRYPOINT ["/bin/bash"] diff --git a/docker/build-images.sh b/docker/build-images.sh index f4867f59..ee13d71f 100755 --- a/docker/build-images.sh +++ b/docker/build-images.sh @@ -27,6 +27,7 @@ docker pull fedora:36 docker build --tag danielflook/python-minifier-build:python3.11-$DATE -f Dockerfile-fedora36 --target python3.11 . docker pull fedora:38 +docker build --tag danielflook/python-minifier-build:python3.12-$DATE -f Dockerfile-fedora38 --target python3.12 . docker build --tag danielflook/python-minifier-build:fuzz-$DATE -f Dockerfile-fuzz --target fuzz . docker push danielflook/python-minifier-build:python3.3-$DATE @@ -39,6 +40,7 @@ docker push danielflook/python-minifier-build:python3.8-$DATE docker push danielflook/python-minifier-build:python3.9-$DATE docker push danielflook/python-minifier-build:python3.10-$DATE docker push danielflook/python-minifier-build:python3.11-$DATE +docker push danielflook/python-minifier-build:python3.12-$DATE docker push danielflook/python-minifier-build:pypy-$DATE docker push danielflook/python-minifier-build:pypy3-$DATE docker push danielflook/python-minifier-build:fuzz-$DATE diff --git a/docs/source/conf.py b/docs/source/conf.py index 9fda54f1..d9f9d9bf 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -23,11 +23,11 @@ copyright = '2020, Daniel Flook' author = 'Daniel Flook' -from pkg_resources import get_distribution, DistributionNotFound +from importlib import metadata try: - release = get_distribution('python_minifier').version + release = metadata.version('python-minifier') version = '.'.join(release.split('.')[:3]) -except DistributionNotFound: +except metadata.PackageNotFoundError: release = '0.0.0' version = '0.0.0' diff --git a/docs/source/installation.rst b/docs/source/installation.rst index b1909d4f..1b36892a 100644 --- a/docs/source/installation.rst +++ b/docs/source/installation.rst @@ -9,4 +9,4 @@ To install python-minifier use pip: Note that python-minifier depends on the python interpreter for parsing source code, so install using a version of python appropriate for your source. -python-minifier runs with and can minify code written for Python 2.7 and Python 3.3 to 3.11. +python-minifier runs with and can minify code written for Python 2.7 and Python 3.3 to 3.12. diff --git a/hypo_test/module.py b/hypo_test/module.py index 5c871dfe..50eabfae 100644 --- a/hypo_test/module.py +++ b/hypo_test/module.py @@ -168,14 +168,34 @@ def ImportFrom(draw) -> ast.ImportFrom: names=draw(lists(alias(), min_size=1, max_size=3)), level=draw(integers(min_value=0, max_value=2))) +@composite +def TypeVar(draw) -> ast.TypeVar: + return ast.TypeVar(name=draw(name()), + bound=draw(none() | expression())) + +@composite +def TypeVarTuple(draw) -> ast.TypeVarTuple: + return ast.TypeVarTuple(name=draw(name())) + +@composite +def ParamSpec(draw) -> ast.ParamSpec: + return ast.ParamSpec(name=draw(name())) + +@composite +def TypeAlias(draw) -> ast.TypeAlias: + return ast.TypeAlias(name=draw(Name(ast.Store)), + value=draw(expression()), + type_params=draw(lists(one_of(TypeVar(), TypeVarTuple(), ParamSpec()), min_size=0, max_size=3))) + @composite def FunctionDef(draw, statements) -> ast.FunctionDef: n = draw(name()) args = draw(arguments()) body = draw(lists(statements, min_size=1, max_size=3)) decorator_list = draw(lists(Name(), min_size=0, max_size=2)) + type_params = draw(none() | lists(one_of(TypeVar(), TypeVarTuple(), ParamSpec()), min_size=0, max_size=3)) returns = draw(none() | expression()) - return ast.FunctionDef(n, args, body, decorator_list, returns) + return ast.FunctionDef(n, args, body, decorator_list, returns, type_params=type_params) @composite def AsyncFunctionDef(draw, statements) -> ast.AsyncFunctionDef: @@ -183,8 +203,9 @@ def AsyncFunctionDef(draw, statements) -> ast.AsyncFunctionDef: args = draw(arguments()) body = draw(lists(statements, min_size=1, max_size=3)) decorator_list = draw(lists(Name(), min_size=0, max_size=2)) + type_params = draw(none() | lists(one_of(TypeVar(), TypeVarTuple(), ParamSpec()), min_size=0, max_size=3)) returns = draw(none() | expression()) - return ast.AsyncFunctionDef(n, args, body, decorator_list, returns) + return ast.AsyncFunctionDef(n, args, body, decorator_list, returns, type_params=type_params) @composite def keyword(draw) -> ast.keyword: @@ -208,7 +229,8 @@ def ClassDef(draw, statements) -> ast.ClassDef: bases=bases, keywords=keywords, body=body, - decorator_list=decorator_list + decorator_list=decorator_list, + type_params=draw(none() | lists(one_of(TypeVar(), TypeVarTuple(), ParamSpec()), min_size=0, max_size=3)) ) if hasattr(ast, 'Print'): @@ -244,7 +266,8 @@ def ClassDef(draw, statements) -> ast.ClassDef: AnnAssign(), AugAssign(), Import(), - ImportFrom() + ImportFrom(), + TypeAlias() ) def suite() -> SearchStrategy: diff --git a/hypo_test/test_it.py b/hypo_test/test_it.py index 608dd002..9327f4b9 100644 --- a/hypo_test/test_it.py +++ b/hypo_test/test_it.py @@ -10,7 +10,7 @@ from python_minifier.ast_printer import print_ast from python_minifier.expression_printer import ExpressionPrinter from expressions import Expression -from module import Module +from module import Module, TypeAlias from python_minifier.rename.mapper import add_parent from python_minifier.transforms.constant_folding import FoldConstants @@ -72,3 +72,46 @@ def test_folding(node): # The constant folder asserts the value is correct constant_folder(node) + +@given(node=TypeAlias()) +@settings(report_multiple_bugs=False, deadline=timedelta(seconds=2), max_examples=1000, verbosity=Verbosity.verbose) +def test_type_alias(node): + + module = ast.Module( + body=[node], + type_ignores=[] + ) + + printer = ModulePrinter() + code = printer(module) + note(code) + compare_ast(module, ast.parse(code, 'test_type_alias')) + +@given(node=TypeAlias()) +@settings(report_multiple_bugs=False, deadline=timedelta(seconds=2), max_examples=1000, verbosity=Verbosity.verbose) +def test_function_type_param(node): + + module = ast.Module( + body=[ast.FunctionDef( + name='test', + args=ast.arguments( + posonlyargs=[], + args=[], + vararg=None, + kwonlyargs=[], + kw_defaults=[], + kwarg=None, + defaults=[], + ), + body=[ast.Pass()], + type_params=node.type_params, + decorator_list=[], + returns=None + )], + type_ignores=[] + ) + + printer = ModulePrinter() + code = printer(module) + note(code) + compare_ast(module, ast.parse(code, 'test_function_type_param')) diff --git a/setup.py b/setup.py index 6133edf4..c0846376 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,4 @@ import os.path -import sys from setuptools import setup, find_packages @@ -27,7 +26,7 @@ long_description=long_desc, long_description_content_type='text/markdown', - python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, <3.12', + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, <3.13', setup_requires=['setuptools_scm'], classifiers=[ @@ -44,6 +43,7 @@ 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: Implementation :: CPython', diff --git a/src/python_minifier/__init__.py b/src/python_minifier/__init__.py index bbeeeb62..9863b791 100644 --- a/src/python_minifier/__init__.py +++ b/src/python_minifier/__init__.py @@ -4,11 +4,10 @@ """ -import ast +import python_minifier.ast_compat as ast import re from python_minifier.ast_compare import CompareError, compare_ast -from python_minifier.ast_printer import print_ast from python_minifier.module_printer import ModulePrinter from python_minifier.rename import ( rename_literals, diff --git a/src/python_minifier/__main__.py b/src/python_minifier/__main__.py index 6c81b4aa..056fe5ca 100644 --- a/src/python_minifier/__main__.py +++ b/src/python_minifier/__main__.py @@ -1,18 +1,24 @@ from __future__ import print_function -import sys -import os - import argparse -from pkg_resources import get_distribution, DistributionNotFound +import os +import sys from python_minifier import minify from python_minifier.transforms.remove_annotations_options import RemoveAnnotationsOptions -try: - version = get_distribution('python_minifier').version -except DistributionNotFound: - version = '0.0.0' +if sys.version_info >= (3, 8): + from importlib import metadata + try: + version = metadata.version('python-minifier') + except metadata.PackageNotFoundError: + version = '0.0.0' +else: + from pkg_resources import get_distribution, DistributionNotFound + try: + version = get_distribution('python_minifier').version + except DistributionNotFound: + version = '0.0.0' def main(): @@ -69,6 +75,7 @@ def main(): else: sys.stdout.write(minified) + def parse_args(): parser = argparse.ArgumentParser(prog='pyminify', description='Minify Python source code', formatter_class=argparse.RawDescriptionHelpFormatter, epilog=main.__doc__) @@ -253,6 +260,7 @@ def parse_args(): return args + def source_modules(args): def error(os_error): @@ -267,6 +275,7 @@ def error(os_error): else: yield path_arg + def do_minify(source, filename, minification_args): preserve_globals = [] diff --git a/src/python_minifier/ast_compare.py b/src/python_minifier/ast_compare.py index 7c658389..8d034b5b 100644 --- a/src/python_minifier/ast_compare.py +++ b/src/python_minifier/ast_compare.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast from python_minifier.util import is_ast_node diff --git a/src/python_minifier/ast_compat.py b/src/python_minifier/ast_compat.py new file mode 100644 index 00000000..ba198d56 --- /dev/null +++ b/src/python_minifier/ast_compat.py @@ -0,0 +1,40 @@ +""" +The is a backwards compatible shim for the ast module. + +This is the best way to make the ast module work the same in both python 2 and 3. +This is essentially what the ast module was doing until 3.12, when it started throwing +deprecation warnings. +""" + +from ast import * + +# Ideally we don't import anything else + +if 'TypeAlias' in globals(): + + # Add n and s properties to Constant so it can stand in for Num, Str and Bytes + Constant.n = property(lambda self: self.value, lambda self, value: setattr(self, 'value', value)) # type: ignore[assignment] + Constant.s = property(lambda self: self.value, lambda self, value: setattr(self, 'value', value)) # type: ignore[assignment] + + # These classes are redefined from the ones in ast that complain about deprecation + # They will continue to work once they are removed from ast + + class Str(Constant): # type: ignore[no-redef] + def __new__(cls, s, *args, **kwargs): + return Constant(value=s, *args, **kwargs) + + class Bytes(Constant): # type: ignore[no-redef] + def __new__(cls, s, *args, **kwargs): + return Constant(value=s, *args, **kwargs) + + class Num(Constant): # type: ignore[no-redef] + def __new__(cls, n, *args, **kwargs): + return Constant(value=n, *args, **kwargs) + + class NameConstant(Constant): # type: ignore[no-redef] + def __new__(cls, *args, **kwargs): + return Constant(*args, **kwargs) + + class Ellipsis(Constant): # type: ignore[no-redef] + def __new__(cls, *args, **kwargs): + return Constant(value=literal_eval('...'), *args, **kwargs) diff --git a/src/python_minifier/ast_printer.py b/src/python_minifier/ast_printer.py index 60ec8698..5480f506 100644 --- a/src/python_minifier/ast_printer.py +++ b/src/python_minifier/ast_printer.py @@ -10,7 +10,7 @@ """ -import ast +import python_minifier.ast_compat as ast from python_minifier.util import is_ast_node @@ -67,10 +67,10 @@ def is_literal(node, field): if hasattr(ast, 'Constant') and isinstance(node, ast.Constant) and field == 'value': return True - if isinstance(node, ast.Num) and field == 'n': + if is_ast_node(node, ast.Num) and field == 'n': return True - if isinstance(node, ast.Str) and field == 's': + if is_ast_node(node, ast.Str) and field == 's': return True if is_ast_node(node, 'Bytes') and field == 's': diff --git a/src/python_minifier/expression_printer.py b/src/python_minifier/expression_printer.py index 4544db96..300f399c 100644 --- a/src/python_minifier/expression_printer.py +++ b/src/python_minifier/expression_printer.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast import sys from python_minifier.util import is_ast_node @@ -69,7 +69,7 @@ def precedence(self, node): # Python2 parses negative ints as an ast.Num with a negative value. # Make sure the Num get the precedence of the USub operator in this case. - if sys.version_info < (3, 0) and isinstance(node, ast.Num): + if sys.version_info < (3, 0) and is_ast_node(node, ast.Num): if str(node.n)[0] == '-': return self.precedences['USub'] @@ -208,7 +208,7 @@ def visit_Starred(self, node): def visit_UnaryOp(self, node): self.visit(node.op) - if sys.version_info < (3, 0) and isinstance(node.op, ast.USub) and isinstance(node.operand, ast.Num): + if sys.version_info < (3, 0) and isinstance(node.op, ast.USub) and is_ast_node(node.operand, ast.Num): # For: -(1), which is parsed as a UnaryOp(USub, Num(1)). # Without this special case it would be printed as -1 # This is fine, but python 2 will then parse it at Num(-1) so the AST wouldn't round-trip. @@ -428,7 +428,7 @@ def visit_Attribute(self, node): value_precedence = self.precedence(node.value) attr_precedence = self.precedence(node) - if (value_precedence != 0 and (attr_precedence > value_precedence)) or isinstance(node.value, ast.Num): + if (value_precedence != 0 and (attr_precedence > value_precedence)) or is_ast_node(node.value, ast.Num): self.printer.delimiter('(') self._expression(node.value) self.printer.delimiter(')') @@ -462,7 +462,7 @@ def visit_Subscript(self, node): self.visit_Slice(node.slice) elif isinstance(node.slice, ast.ExtSlice): self.visit_ExtSlice(node.slice) - elif isinstance(node.slice, ast.Ellipsis): + elif is_ast_node(node.slice, ast.Ellipsis): self.visit_Ellipsis(node) elif sys.version_info >= (3, 9) and isinstance(node.slice, ast.Tuple): self.visit_Tuple(node.slice) @@ -735,7 +735,12 @@ def visit_JoinedStr(self, node): import python_minifier.f_string - self.printer.fstring(str(python_minifier.f_string.OuterFString(node))) + if sys.version_info < (3, 12): + pep701 = False + else: + pep701 = True + + self.printer.fstring(str(python_minifier.f_string.OuterFString(node, pep701=pep701))) def visit_NamedExpr(self, node): self._expression(node.target) diff --git a/src/python_minifier/f_string.py b/src/python_minifier/f_string.py index 2dead030..332a2546 100644 --- a/src/python_minifier/f_string.py +++ b/src/python_minifier/f_string.py @@ -6,7 +6,7 @@ """ -import ast +import python_minifier.ast_compat as ast import copy import re @@ -24,11 +24,12 @@ class FString(object): An F-string in the expression part of another f-string """ - def __init__(self, node, allowed_quotes): + def __init__(self, node, allowed_quotes, pep701): assert isinstance(node, ast.JoinedStr) self.node = node self.allowed_quotes = allowed_quotes + self.pep701 = pep701 def is_correct_ast(self, code): try: @@ -53,7 +54,7 @@ def complete_debug_specifier(self, partial_specifier_candidates, value_node): conversion_candidates = [x + conversion for x in partial_specifier_candidates] if value_node.format_spec is not None: - conversion_candidates = [c + ':' + fs for c in conversion_candidates for fs in FormatSpec(value_node.format_spec, self.allowed_quotes).candidates()] + conversion_candidates = [c + ':' + fs for c in conversion_candidates for fs in FormatSpec(value_node.format_spec, self.allowed_quotes, self.pep701).candidates()] return [x + '}' for x in conversion_candidates] @@ -64,7 +65,10 @@ def candidates(self): candidates = [''] debug_specifier_candidates = [] nested_allowed = copy.copy(self.allowed_quotes) - nested_allowed.remove(quote) + + if not self.pep701: + nested_allowed.remove(quote) + for v in self.node.values: if is_ast_node(v, ast.Str): @@ -86,7 +90,7 @@ def candidates(self): try: completed = self.complete_debug_specifier(debug_specifier_candidates, v) candidates = [ - x + y for x in candidates for y in FormattedValue(v, nested_allowed).get_candidates() + x + y for x in candidates for y in FormattedValue(v, nested_allowed, self.pep701).get_candidates() ] + completed debug_specifier_candidates = [] except Exception as e: @@ -111,9 +115,9 @@ class OuterFString(FString): OuterFString is free to use backslashes in the Str parts """ - def __init__(self, node): + def __init__(self, node, pep701=False): assert isinstance(node, ast.JoinedStr) - super(OuterFString, self).__init__(node, ['"', "'", '"""', "'''"]) + super(OuterFString, self).__init__(node, ['"', "'", '"""', "'''"], pep701=pep701) def __str__(self): if len(self.node.values) == 0: @@ -151,12 +155,13 @@ class FormattedValue(ExpressionPrinter): An F-String Expression Part """ - def __init__(self, node, allowed_quotes): + def __init__(self, node, allowed_quotes, pep701): super(FormattedValue, self).__init__() assert isinstance(node, ast.FormattedValue) self.node = node self.allowed_quotes = allowed_quotes + self.pep701 = pep701 self.candidates = [''] def get_candidates(self): @@ -177,7 +182,7 @@ def get_candidates(self): if self.node.format_spec is not None: self.printer.delimiter(':') - self._append(FormatSpec(self.node.format_spec, self.allowed_quotes).candidates()) + self._append(FormatSpec(self.node.format_spec, self.allowed_quotes, pep701=self.pep701).candidates()) self.printer.delimiter('}') @@ -206,7 +211,7 @@ def is_curly(self, node): return False def visit_Str(self, node): - self.printer.append(str(Str(node.s, self.allowed_quotes)), TokenTypes.NonNumberLiteral) + self.printer.append(str(Str(node.s, self.allowed_quotes, self.pep701)), TokenTypes.NonNumberLiteral) def visit_Bytes(self, node): self.printer.append(str(Bytes(node.s, self.allowed_quotes)), TokenTypes.NonNumberLiteral) @@ -215,7 +220,12 @@ def visit_JoinedStr(self, node): assert isinstance(node, ast.JoinedStr) if self.printer.previous_token in [TokenTypes.Identifier, TokenTypes.Keyword, TokenTypes.SoftKeyword]: self.printer.delimiter(' ') - self._append(FString(node, allowed_quotes=self.allowed_quotes).candidates()) + self._append(FString(node, allowed_quotes=self.allowed_quotes, pep701=self.pep701).candidates()) + + def visit_Lambda(self, node): + self.printer.delimiter('(') + super().visit_Lambda(node) + self.printer.delimiter(')') def _finalize(self): self.candidates = [x + str(self.printer) for x in self.candidates] @@ -230,20 +240,21 @@ class Str(object): """ A Str node inside an f-string expression - May use any of the allowed quotes, no backslashes! + May use any of the allowed quotes. In Python <3.12, backslashes are not allowed. """ - def __init__(self, s, allowed_quotes): + def __init__(self, s, allowed_quotes, pep701=False): self._s = s self.allowed_quotes = allowed_quotes self.current_quote = None + self.pep701 = pep701 def _can_quote(self, c): if self.current_quote is None: return False - if (c == '\n' or c == '\r') and len(self.current_quote) == 1: + if (c == '\n' or c == '\r') and len(self.current_quote) == 1 and not self.pep701: return False if c == self.current_quote[0]: @@ -253,7 +264,7 @@ def _can_quote(self, c): def _get_quote(self, c): for quote in self.allowed_quotes: - if c == '\n' or c == '\r': + if not self.pep701 and (c == '\n' or c == '\r'): if len(quote) == 3: return quote elif c != quote: @@ -274,7 +285,15 @@ def _literals(self): if l == '': l += self.current_quote - l += c + + if c == '\n': + l += '\\n' + elif c == '\r': + l += '\\r' + elif c == '\\': + l += '\\\\' + else: + l += c if l: l += self.current_quote @@ -284,10 +303,10 @@ def __str__(self): if self._s == '': return str(min(self.allowed_quotes, key=len)) * 2 - if '\0' in self._s or '\\' in self._s: - raise ValueError('Impossible to represent a %r character in f-string expression part') + if '\0' in self._s or ('\\' in self._s and not self.pep701): + raise ValueError('Impossible to represent a character in f-string expression part') - if '\n' in self._s or '\r' in self._s: + if not self.pep701 and ('\n' in self._s or '\r' in self._s): if '"""' not in self.allowed_quotes and "'''" not in self.allowed_quotes: raise ValueError( 'Impossible to represent newline character in f-string expression part without a long quote' @@ -319,11 +338,12 @@ class FormatSpec(object): """ - def __init__(self, node, allowed_quotes): + def __init__(self, node, allowed_quotes, pep701): assert isinstance(node, ast.JoinedStr) self.node = node self.allowed_quotes = allowed_quotes + self.pep701 = pep701 def candidates(self): @@ -333,7 +353,7 @@ def candidates(self): candidates = [x + self.str_for(v.s) for x in candidates] elif isinstance(v, ast.FormattedValue): candidates = [ - x + y for x in candidates for y in FormattedValue(v, self.allowed_quotes).get_candidates() + x + y for x in candidates for y in FormattedValue(v, self.allowed_quotes, self.pep701).get_candidates() ] else: raise RuntimeError('Unexpected JoinedStr value') diff --git a/src/python_minifier/module_printer.py b/src/python_minifier/module_printer.py index cc2ec7d5..3d57178b 100644 --- a/src/python_minifier/module_printer.py +++ b/src/python_minifier/module_printer.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast import sys from .expression_printer import ExpressionPrinter @@ -440,7 +440,7 @@ def visit_ExceptHandler(self, node, star=False): self._suite(node.body) def visit_With(self, node, is_async=False): - assert isinstance(node, ast.With) or (hasattr(ast, 'AsyncWith') and isinstance(node, ast.AsyncWith)) + assert is_ast_node(node, (ast.With, 'AsyncWith')) self.printer.newline() @@ -469,7 +469,7 @@ def visit_With(self, node, is_async=False): self._suite(node.body) def visit_withitem(self, node): - assert (hasattr(ast, 'withitem') and isinstance(node, ast.withitem)) or isinstance(node, ast.With) + assert is_ast_node(node, ('withitem', ast.With)) self._expression(node.context_expr) @@ -478,9 +478,7 @@ def visit_withitem(self, node): self._expression(node.optional_vars) def visit_FunctionDef(self, node, is_async=False): - assert isinstance(node, ast.FunctionDef) or ( - hasattr(ast, 'AsyncFunctionDef') and isinstance(node, ast.AsyncFunctionDef) - ) + assert is_ast_node(node, (ast.FunctionDef, 'AsyncFunctionDef')) self.printer.newline() @@ -494,6 +492,15 @@ def visit_FunctionDef(self, node, is_async=False): self.printer.keyword('def') self.printer.identifier(node.name) + + if hasattr(node, 'type_params') and node.type_params: + self.printer.delimiter('[') + delimiter = Delimiter(self.printer) + for type_param in node.type_params: + delimiter.new_item() + self.visit(type_param) + self.printer.delimiter(']') + self.printer.delimiter('(') self.visit_arguments(node.args) self.printer.delimiter(')') @@ -523,6 +530,14 @@ def visit_ClassDef(self, node): self.printer.keyword('class') self.printer.identifier(node.name) + if hasattr(node, 'type_params') and node.type_params: + self.printer.delimiter('[') + delimiter = Delimiter(self.printer) + for type_param in node.type_params: + delimiter.new_item() + self.visit(type_param) + self.printer.delimiter(']') + with Delimiter(self.printer, add_parens=True) as delimiter: for b in node.bases: @@ -712,6 +727,46 @@ def visit_AsyncWith(self, node): # endregion + # region Generic Types + def visit_TypeAlias(self, node): + assert isinstance(node, ast.TypeAlias) + self.printer.keyword('type') + self.visit_Name(node.name) + + if hasattr(node, 'type_params') and node.type_params: + self.printer.delimiter('[') + delimiter = Delimiter(self.printer) + for param in node.type_params: + delimiter.new_item() + self.visit(param) + self.printer.delimiter(']') + + self.printer.delimiter('=') + self._expression(node.value) + self.printer.end_statement() + + def visit_TypeVar(self, node): + assert isinstance(node, ast.TypeVar) + assert isinstance(node.name, str) + self.printer.identifier(node.name) + + if node.bound: + self.printer.delimiter(':') + self._expression(node.bound) + + def visit_TypeVarTuple(self, node): + assert isinstance(node, ast.TypeVarTuple) + self.printer.operator('*') + self.printer.identifier(node.name) + + def visit_ParamSpec(self, node): + assert isinstance(node, ast.ParamSpec) + self.printer.operator('*') + self.printer.operator('*') + self.printer.identifier(node.name) + + # endregion + def visit_Module(self, node): if hasattr(node, 'docstring') and node.docstring is not None: # Python 3.6 added a docstring field! Really useful for every use case except this one... @@ -786,7 +841,8 @@ def _suite_body(self, node_list): 'Print': self.visit_Print, 'Exec': self.visit_Exec, 'Match': self.visit_Match, - 'match_case': self.visit_match_case + 'match_case': self.visit_match_case, + 'TypeAlias': self.visit_TypeAlias } for node in node_list: diff --git a/src/python_minifier/rename/bind_names.py b/src/python_minifier/rename/bind_names.py index 9a065c88..1a2f586a 100644 --- a/src/python_minifier/rename/bind_names.py +++ b/src/python_minifier/rename/bind_names.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast from python_minifier.rename.binding import NameBinding from python_minifier.rename.util import arg_rename_in_place, get_global_namespace, get_nonlocal_namespace, builtins @@ -24,11 +24,6 @@ def get_binding(self, name, namespace): # nonlocal names should not create a binding in any context assert name not in namespace.nonlocal_names - if isinstance(namespace, ast.ClassDef): - binding = self.get_binding(name, get_nonlocal_namespace(namespace)) - binding.disallow_rename() - return binding - for binding in namespace.bindings: if binding.name == name: break @@ -43,6 +38,10 @@ def get_binding(self, name, namespace): # This is actually a syntax error - but we want the same syntax error after minifying! binding.disallow_rename() + if isinstance(namespace, ast.ClassDef): + # This name will become an attribute of the class, so it can't be renamed + binding.disallow_rename() + return binding def visit_Name(self, node): diff --git a/src/python_minifier/rename/binding.py b/src/python_minifier/rename/binding.py index 26d44700..45ee4916 100644 --- a/src/python_minifier/rename/binding.py +++ b/src/python_minifier/rename/binding.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast from python_minifier.rename.util import arg_rename_in_place, insert from python_minifier.util import is_ast_node @@ -11,7 +11,6 @@ class Binding(object): :param name: A name for this binding :type name: str or None :param bool allow_rename: If this binding may be renamed - :param int rename_cost: The cost of renaming this binding in bytes, NOT including the difference in name lengths """ @@ -289,7 +288,7 @@ def __init__(self, name, *args, **kwargs): self.disallow_rename() def __repr__(self): - return self.__class__.__name__ + '(name=%r) ' % (self._name, len(self._references)) + return self.__class__.__name__ + '(name=%r, allow_rename=%r) ' % (self._name, self._allow_rename, len(self._references)) def should_rename(self, new_name): """ diff --git a/src/python_minifier/rename/mapper.py b/src/python_minifier/rename/mapper.py index 47817cd8..d21a1908 100644 --- a/src/python_minifier/rename/mapper.py +++ b/src/python_minifier/rename/mapper.py @@ -2,7 +2,7 @@ For each node in an AST set the namespace to use for name binding and resolution """ -import ast +import python_minifier.ast_compat as ast from python_minifier.rename.util import is_namespace from python_minifier.util import is_ast_node @@ -61,6 +61,10 @@ def add_parent_to_functiondef(functiondef): for node in functiondef.decorator_list: add_parent(node, parent=functiondef, namespace=functiondef.namespace) + if hasattr(functiondef, 'type_params') and functiondef.type_params is not None: + for node in functiondef.type_params: + add_parent(node, parent=functiondef, namespace=functiondef.namespace) + if hasattr(functiondef, 'returns') and functiondef.returns is not None: add_parent(functiondef.returns, parent=functiondef, namespace=functiondef.namespace) @@ -89,6 +93,10 @@ def add_parent_to_classdef(classdef): for node in classdef.decorator_list: add_parent(node, parent=classdef, namespace=classdef.namespace) + if hasattr(classdef, 'type_params') and classdef.type_params is not None: + for node in classdef.type_params: + add_parent(node, parent=classdef, namespace=classdef.namespace) + def add_parent_to_comprehension(node, namespace): assert is_ast_node(node, (ast.GeneratorExp, 'SetComp', 'DictComp', 'ListComp')) @@ -152,6 +160,13 @@ def add_parent(node, parent=None, namespace=None): if is_ast_node(node, 'Nonlocal'): namespace.nonlocal_names.update(node.names) + if isinstance(node, ast.Name): + if isinstance(namespace, ast.ClassDef): + if isinstance(node.ctx, ast.Load): + namespace.nonlocal_names.add(node.id) + elif isinstance(node.ctx, ast.Store) and isinstance(node.parent, ast.AugAssign): + namespace.nonlocal_names.add(node.id) + for child in ast.iter_child_nodes(node): add_parent(child, parent=node, namespace=namespace) diff --git a/src/python_minifier/rename/rename_literals.py b/src/python_minifier/rename/rename_literals.py index 4ed65999..b5e2cf5d 100644 --- a/src/python_minifier/rename/rename_literals.py +++ b/src/python_minifier/rename/rename_literals.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast from python_minifier.rename.binding import Binding from python_minifier.rename.util import insert @@ -113,8 +113,9 @@ class HoistLiterals(NodeVisitor): Hoist literal strings to module level variables """ - def __call__(self, module): + def __call__(self, module, ignore_slots=True): self.module = module + self._ignore_slots = ignore_slots self._hoisted = {} self.visit(module) self.place_bindings() @@ -230,5 +231,19 @@ def visit_match_case(self, node): for n in node.body: self.visit(n) + def visit_Assign(self, node): + if not self._ignore_slots: + return self.generic_visit(node) + + if not is_ast_node(node.namespace, ast.ClassDef): + return self.generic_visit(node) + + for target in node.targets: + if is_ast_node(target, ast.Name) and target.id == '__slots__': + # This is a __slots__ assignment, don't hoist the literals + return + + return self.generic_visit(node) + def rename_literals(module): HoistLiterals()(module) diff --git a/src/python_minifier/rename/renamer.py b/src/python_minifier/rename/renamer.py index a879207e..9e9e6b54 100644 --- a/src/python_minifier/rename/renamer.py +++ b/src/python_minifier/rename/renamer.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast from python_minifier.rename.binding import NameBinding from python_minifier.rename.name_generator import name_filter diff --git a/src/python_minifier/rename/resolve_names.py b/src/python_minifier/rename/resolve_names.py index 602cb5e0..25555fdc 100644 --- a/src/python_minifier/rename/resolve_names.py +++ b/src/python_minifier/rename/resolve_names.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast from python_minifier.rename.binding import BuiltinBinding, NameBinding from python_minifier.rename.util import get_global_namespace, get_nonlocal_namespace, builtins @@ -47,7 +47,11 @@ def resolve_names(node): if isinstance(node, ast.Name) and isinstance(node.ctx, ast.Load): get_binding(node.id, node.namespace).add_reference(node) elif isinstance(node, ast.Name) and node.id in node.namespace.nonlocal_names: - get_binding(node.id, node.namespace).add_reference(node) + binding = get_binding(node.id, node.namespace) + binding.add_reference(node) + + if isinstance(node.ctx, ast.Store) and isinstance(node.namespace, ast.ClassDef): + binding.disallow_rename() elif isinstance(node, ast.ClassDef) and node.name in node.namespace.nonlocal_names: get_binding(node.name, node.namespace).add_reference(node) diff --git a/src/python_minifier/rename/util.py b/src/python_minifier/rename/util.py index ed6f9fd0..098ec24a 100644 --- a/src/python_minifier/rename/util.py +++ b/src/python_minifier/rename/util.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast import sys from python_minifier.util import is_ast_node @@ -23,6 +23,15 @@ def create_is_namespace(): is_namespace = create_is_namespace() +def iter_child_namespaces(node): + + for child in ast.iter_child_nodes(node): + if is_namespace(child): + yield child + else: + for c in iter_child_namespaces(child): + yield c + def get_global_namespace(node): """ Return the global namespace for a node diff --git a/src/python_minifier/token_printer.py b/src/python_minifier/token_printer.py index 2a916434..e8813fd2 100644 --- a/src/python_minifier/token_printer.py +++ b/src/python_minifier/token_printer.py @@ -117,7 +117,9 @@ def keyword(self, kw): 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', - 'try', 'while', 'with', 'yield', '_', 'case', 'match', 'print', 'exec' + 'try', 'while', 'with', 'yield', '_', + 'case', 'match', 'print', 'exec', + 'type' ] if self.previous_token in [TokenTypes.Identifier, TokenTypes.Keyword, TokenTypes.SoftKeyword, TokenTypes.NumberLiteral]: @@ -125,7 +127,7 @@ def keyword(self, kw): self._code += kw - if kw in ['_', 'case', 'match']: + if kw in ['_', 'case', 'match', 'type']: self.previous_token = TokenTypes.SoftKeyword else: self.previous_token = TokenTypes.Keyword diff --git a/src/python_minifier/transforms/combine_imports.py b/src/python_minifier/transforms/combine_imports.py index 748064d9..5373b2ed 100644 --- a/src/python_minifier/transforms/combine_imports.py +++ b/src/python_minifier/transforms/combine_imports.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast from python_minifier.transforms.suite_transformer import SuiteTransformer diff --git a/src/python_minifier/transforms/constant_folding.py b/src/python_minifier/transforms/constant_folding.py index a7763d97..bc1a33b5 100644 --- a/src/python_minifier/transforms/constant_folding.py +++ b/src/python_minifier/transforms/constant_folding.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast import math import sys diff --git a/src/python_minifier/transforms/remove_annotations.py b/src/python_minifier/transforms/remove_annotations.py index eff0ca1f..114dbaaa 100644 --- a/src/python_minifier/transforms/remove_annotations.py +++ b/src/python_minifier/transforms/remove_annotations.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast import sys from python_minifier.transforms.remove_annotations_options import RemoveAnnotationsOptions @@ -25,6 +25,9 @@ def visit_FunctionDef(self, node): node.body = self.suite(node.body, parent=node) node.decorator_list = [self.visit(d) for d in node.decorator_list] + if hasattr(node, 'type_params') and node.type_params is not None: + node.type_params = [self.visit(t) for t in node.type_params] + if hasattr(node, 'returns') and self._options.remove_return_annotations: node.returns = None diff --git a/src/python_minifier/transforms/remove_asserts.py b/src/python_minifier/transforms/remove_asserts.py index 924d88a1..c71fa016 100644 --- a/src/python_minifier/transforms/remove_asserts.py +++ b/src/python_minifier/transforms/remove_asserts.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast from python_minifier.transforms.suite_transformer import SuiteTransformer from python_minifier.util import is_ast_node diff --git a/src/python_minifier/transforms/remove_debug.py b/src/python_minifier/transforms/remove_debug.py index 2d0afbd4..d744c3aa 100644 --- a/src/python_minifier/transforms/remove_debug.py +++ b/src/python_minifier/transforms/remove_debug.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast import sys from python_minifier.transforms.suite_transformer import SuiteTransformer diff --git a/src/python_minifier/transforms/remove_exception_brackets.py b/src/python_minifier/transforms/remove_exception_brackets.py index 05150bdc..aac64976 100644 --- a/src/python_minifier/transforms/remove_exception_brackets.py +++ b/src/python_minifier/transforms/remove_exception_brackets.py @@ -8,7 +8,7 @@ We can't generally know if a name refers to an exception, so we only do this for builtin exceptions """ -import ast +import python_minifier.ast_compat as ast import sys from python_minifier.rename.binding import BuiltinBinding diff --git a/src/python_minifier/transforms/remove_explicit_return_none.py b/src/python_minifier/transforms/remove_explicit_return_none.py index 2148dbcc..c152ea54 100644 --- a/src/python_minifier/transforms/remove_explicit_return_none.py +++ b/src/python_minifier/transforms/remove_explicit_return_none.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast import sys from python_minifier.transforms.suite_transformer import SuiteTransformer diff --git a/src/python_minifier/transforms/remove_literal_statements.py b/src/python_minifier/transforms/remove_literal_statements.py index 62910e86..89d28189 100644 --- a/src/python_minifier/transforms/remove_literal_statements.py +++ b/src/python_minifier/transforms/remove_literal_statements.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast from python_minifier.transforms.suite_transformer import SuiteTransformer from python_minifier.util import is_ast_node diff --git a/src/python_minifier/transforms/remove_object_base.py b/src/python_minifier/transforms/remove_object_base.py index d7234128..9a34b9c9 100644 --- a/src/python_minifier/transforms/remove_object_base.py +++ b/src/python_minifier/transforms/remove_object_base.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast import sys from python_minifier.transforms.suite_transformer import SuiteTransformer @@ -16,6 +16,9 @@ def visit_ClassDef(self, node): b for b in node.bases if not isinstance(b, ast.Name) or (isinstance(b, ast.Name) and b.id != 'object') ] + if hasattr(node, 'type_params') and node.type_params is not None: + node.type_params = [self.visit(t) for t in node.type_params] + node.body = [self.visit(n) for n in node.body] return node diff --git a/src/python_minifier/transforms/remove_pass.py b/src/python_minifier/transforms/remove_pass.py index 2f4e14ce..8183c8a9 100644 --- a/src/python_minifier/transforms/remove_pass.py +++ b/src/python_minifier/transforms/remove_pass.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast from python_minifier.transforms.suite_transformer import SuiteTransformer from python_minifier.util import is_ast_node diff --git a/src/python_minifier/transforms/remove_posargs.py b/src/python_minifier/transforms/remove_posargs.py index 7eabe629..a5e72d52 100644 --- a/src/python_minifier/transforms/remove_posargs.py +++ b/src/python_minifier/transforms/remove_posargs.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast def remove_posargs(node): diff --git a/src/python_minifier/transforms/suite_transformer.py b/src/python_minifier/transforms/suite_transformer.py index 2743d902..0b0982a7 100644 --- a/src/python_minifier/transforms/suite_transformer.py +++ b/src/python_minifier/transforms/suite_transformer.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast from python_minifier.rename.mapper import add_parent from python_minifier.util import is_ast_node @@ -50,6 +50,9 @@ def __call__(self, node): def visit_ClassDef(self, node): node.bases = [self.visit(b) for b in node.bases] + if hasattr(node, 'type_params') and node.type_params is not None: + node.type_params = [self.visit(t) for t in node.type_params] + node.body = self.suite(node.body, parent=node) node.decorator_list = [self.visit(d) for d in node.decorator_list] diff --git a/src/python_minifier/util.py b/src/python_minifier/util.py index c7d0cafe..9e80a73b 100644 --- a/src/python_minifier/util.py +++ b/src/python_minifier/util.py @@ -1,4 +1,4 @@ -import ast +import python_minifier.ast_compat as ast def is_ast_node(node, types): """ @@ -32,16 +32,16 @@ def is_ast_node(node, types): return True if hasattr(ast, 'Constant') and isinstance(node, ast.Constant): - if node.value in [None, True, False]: - return ast.NameConstant in types + if type(node.value) in [type(None), type(True), type(False)]: + return ast.NameConstant in actual_types elif isinstance(node.value, (int, float, complex)): - return ast.Num in types + return ast.Num in actual_types elif isinstance(node.value, str): - return ast.Str in types + return ast.Str in actual_types elif isinstance(node.value, bytes): - return ast.Bytes in types + return ast.Bytes in actual_types elif node.value == Ellipsis: - return ast.Ellipsis in types + return ast.Ellipsis in actual_types else: raise RuntimeError('Unknown Constant value %r' % type(node.value)) diff --git a/test/test_bind_names.py b/test/test_bind_names.py new file mode 100644 index 00000000..a3813eb7 --- /dev/null +++ b/test/test_bind_names.py @@ -0,0 +1,679 @@ +import ast +import sys + +import pytest + +from python_minifier.rename import add_namespace, resolve_names +from python_minifier.rename.bind_names import bind_names +from python_minifier.rename.util import iter_child_namespaces +from python_minifier.util import is_ast_node + + +def assert_namespace_tree(source, expected_tree): + tree = ast.parse(source) + + add_namespace(tree) + bind_names(tree) + resolve_names(tree) + + actual = print_namespace(tree) + + print(actual) + assert actual.strip() == expected_tree.strip() + + +def print_namespace(namespace, indent=''): + s = '' + + if not indent: + s += '\n' + + def namespace_name(node): + if is_ast_node(node, (ast.FunctionDef, 'AsyncFunctionDef')): + return 'Function ' + node.name + elif isinstance(node, ast.ClassDef): + return 'Class ' + node.name + else: + return namespace.__class__.__name__ + + s += indent + '+ ' + namespace_name(namespace) + '\n' + + for name in sorted(namespace.global_names): + s += indent + ' - global ' + name + '\n' + + for name in sorted(namespace.nonlocal_names): + s += indent + ' - nonlocal ' + name + '\n' + + for binding in namespace.bindings: + s += indent + ' - ' + repr(binding) + '\n' + + for child in iter_child_namespaces(namespace): + s += print_namespace(child, indent=indent + ' ') + + return s + +def test_module_namespace(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +name_in_module = True +name_in_module = True +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='name_in_module', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_lambda_namespace(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +name_in_module = True + +b = lambda arg, *args, **kwargs: arg + 1 +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='name_in_module', allow_rename=True) + - NameBinding(name='b', allow_rename=True) + + Lambda + - NameBinding(name='arg', allow_rename=False) + - NameBinding(name='args', allow_rename=True) + - NameBinding(name='kwargs', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_function_namespace(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +name_in_module = True + +def func(arg, *args, **kwargs): + name_in_func = True + print(name_in_module) + + def inner_func(): + print(name_in_module) + name_in_inner_func = True +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='name_in_module', allow_rename=True) + - NameBinding(name='func', allow_rename=True) + - BuiltinBinding(name='print', allow_rename=True) + + Function func + - NameBinding(name='arg', allow_rename=True) + - NameBinding(name='args', allow_rename=True) + - NameBinding(name='kwargs', allow_rename=True) + - NameBinding(name='name_in_func', allow_rename=True) + - NameBinding(name='inner_func', allow_rename=True) + + Function inner_func + - NameBinding(name='name_in_inner_func', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_async_function_namespace(): + if sys.version_info < (3, 5): + pytest.skip('No async functions in python < 3.5') + + source = ''' +name_in_module = True + +async def func(arg, *args, **kwargs): + name_in_func = True + print(name_in_module) + + async def inner_func(): + print(name_in_module) + name_in_inner_func = True +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='name_in_module', allow_rename=True) + - NameBinding(name='func', allow_rename=True) + - BuiltinBinding(name='print', allow_rename=True) + + Function func + - NameBinding(name='arg', allow_rename=True) + - NameBinding(name='args', allow_rename=True) + - NameBinding(name='kwargs', allow_rename=True) + - NameBinding(name='name_in_func', allow_rename=True) + - NameBinding(name='inner_func', allow_rename=True) + + Function inner_func + - NameBinding(name='name_in_inner_func', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +# region generator namespace + +def test_generator_namespace(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +a = (x for x in range(10)) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - BuiltinBinding(name='range', allow_rename=True) + + GeneratorExp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_multi_generator_namespace(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +x = [] +f = [] +a = (x for x in f for x in x) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='x', allow_rename=True) + - NameBinding(name='f', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + GeneratorExp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_multi_generator_namespace_2(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +c = '' +line = '' +file = [] +a = (c for line in file for c in line) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + GeneratorExp + - NameBinding(name='line', allow_rename=True) + - NameBinding(name='c', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_nested_generator(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +c = '' +line = '' +file = [] +a = (c for c in (line for line in file)) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + GeneratorExp + - NameBinding(name='c', allow_rename=True) + + GeneratorExp + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_nested_generator_2(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +x = '' +a = (x for x in (x for x in x)) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='x', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + GeneratorExp + - NameBinding(name='x', allow_rename=True) + + GeneratorExp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +# endregion + + +# region setcomp + +def test_setcomp_namespace(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +a = {x for x in range(10)} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - BuiltinBinding(name='range', allow_rename=True) + + SetComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_multi_setcomp_namespace(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +x = [] +f = [] +a = {x for x in f for x in x} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='x', allow_rename=True) + - NameBinding(name='f', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + SetComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_multi_setcomp_namespace_2(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +c = '' +line = '' +file = [] +a = {c for line in file for c in line} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + SetComp + - NameBinding(name='line', allow_rename=True) + - NameBinding(name='c', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_nested_setcomp(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +c = '' +line = '' +file = [] +a = {c for c in {line for line in file}} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + SetComp + - NameBinding(name='c', allow_rename=True) + + SetComp + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_nested_setcomp_2(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +x = '' +a = {x for x in {x for x in x}} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='x', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + SetComp + - NameBinding(name='x', allow_rename=True) + + SetComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +# endregion + +# region listcomp + +def test_listcomp_namespace(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +a = [x for x in range(10)] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - BuiltinBinding(name='range', allow_rename=True) + + ListComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_multi_listcomp_namespace(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +x = [] +f = [] +a = [x for x in f for x in x] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='x', allow_rename=True) + - NameBinding(name='f', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + ListComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_multi_listcomp_namespace_2(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +c = '' +line = '' +file = [] +a = [c for line in file for c in line] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + ListComp + - NameBinding(name='line', allow_rename=True) + - NameBinding(name='c', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_nested_listcomp(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +c = '' +line = '' +file = [] +a =[c for c in [line for line in file]] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + ListComp + - NameBinding(name='c', allow_rename=True) + + ListComp + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_nested_listcomp_2(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +x = '' +a =[x for x in [x for x in x]] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='x', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + ListComp + - NameBinding(name='x', allow_rename=True) + + ListComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +# endregion + +# region dictcomp + +def test_dictcomp_namespace(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +a = {x: x for x in range(10)} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - BuiltinBinding(name='range', allow_rename=True) + + DictComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_multi_dictcomp_namespace(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +x = [] +f = [] +a = {x: x for x, x in f for x, x in x} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='x', allow_rename=True) + - NameBinding(name='f', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + DictComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_multi_dictcomp_namespace_2(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +c = '' +line = '' +file = [] +a = {c: c for line, line in file for c, c in line} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + DictComp + - NameBinding(name='line', allow_rename=True) + - NameBinding(name='c', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_nested_dictcomp(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +c = '' +line = '' +file = [] +a = {c: c for c, c in {line: line for line in file}} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + DictComp + - NameBinding(name='c', allow_rename=True) + + DictComp + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +def test_nested_dictcomp_2(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +x = {} +a = {x:x for x, x in {x: x for x in x}} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='x', allow_rename=True) + - NameBinding(name='a', allow_rename=True) + + DictComp + - NameBinding(name='x', allow_rename=True) + + DictComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + +# endregion + +def test_class_namespace(): + if sys.version_info < (3, 6): + pytest.skip('Annotations are not available in python < 3.6') + + source = ''' +OhALongName = 'Hello' +OhALongName = 'Hello' +MyOtherName = 'World' + +def func(): + class C: + OhALongName = ' World' + MyOtherName = OhALongName + ClassName: int + +func() +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='OhALongName', allow_rename=False) + - NameBinding(name='MyOtherName', allow_rename=True) + - NameBinding(name='func', allow_rename=True) + - BuiltinBinding(name='int', allow_rename=True) + + Function func + - NameBinding(name='C', allow_rename=True) + + Class C + - nonlocal OhALongName + - nonlocal int + - NameBinding(name='MyOtherName', allow_rename=False) + - NameBinding(name='ClassName', allow_rename=False) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_class_name_rebinding(): + if sys.version_info < (3, 4): + pytest.skip('Test requires python 3.4 or later') + + source = ''' +OhALongName = 'Hello' +OhALongName = 'Hello' +MyOtherName = 'World' + +def func(): + class C: + OhALongName = OhALongName + ' World' + MyOtherName = OhALongName + + +func() +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='OhALongName', allow_rename=False) + - NameBinding(name='MyOtherName', allow_rename=True) + - NameBinding(name='func', allow_rename=True) + + Function func + - NameBinding(name='C', allow_rename=True) + + Class C + - nonlocal OhALongName + - NameBinding(name='MyOtherName', allow_rename=False) +''' + + assert_namespace_tree(source, expected_namespaces) + diff --git a/test/test_bind_names_python2.py b/test/test_bind_names_python2.py new file mode 100644 index 00000000..03f412d4 --- /dev/null +++ b/test/test_bind_names_python2.py @@ -0,0 +1,654 @@ +import ast +import sys + +import pytest + +from python_minifier.rename import add_namespace, resolve_names +from python_minifier.rename.bind_names import bind_names +from python_minifier.rename.util import iter_child_namespaces +from python_minifier.util import is_ast_node + + +def assert_namespace_tree(source, expected_tree): + tree = ast.parse(source) + + add_namespace(tree) + bind_names(tree) + resolve_names(tree) + + actual = print_namespace(tree) + + print(actual) + assert actual.strip() == expected_tree.strip() + + +def print_namespace(namespace, indent=''): + s = '' + + if not indent: + s += '\n' + + def namespace_name(node): + if is_ast_node(node, (ast.FunctionDef, 'AsyncFunctionDef')): + return 'Function ' + node.name + elif isinstance(node, ast.ClassDef): + return 'Class ' + node.name + else: + return namespace.__class__.__name__ + + s += indent + '+ ' + namespace_name(namespace) + '\n' + + for name in sorted(namespace.global_names): + s += indent + ' - global ' + name + '\n' + + for name in sorted(namespace.nonlocal_names): + s += indent + ' - nonlocal ' + name + '\n' + + for binding in sorted(namespace.bindings, key=lambda b: b.name): + s += indent + ' - ' + repr(binding) + '\n' + + for child in iter_child_namespaces(namespace): + s += print_namespace(child, indent=indent + ' ') + + return s + + +def test_module_namespace(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +name_in_module = True +name_in_module = True +''' + + expected_namespaces = ''' ++ Module + - BuiltinBinding(name='True', allow_rename=True) + - NameBinding(name='name_in_module', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_lambda_namespace(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +name_in_module = 0 + +b = lambda arg, *args, **kwargs: arg + 1 +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='b', allow_rename=True) + - NameBinding(name='name_in_module', allow_rename=True) + + Lambda + - NameBinding(name='arg', allow_rename=False) + - NameBinding(name='args', allow_rename=True) + - NameBinding(name='kwargs', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_function_namespace(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +name_in_module = True + +def func(arg, *args, **kwargs): + name_in_func = True + print(name_in_module) + + def inner_func(): + print(name_in_module) + name_in_inner_func = True +''' + + expected_namespaces = ''' ++ Module + - BuiltinBinding(name='True', allow_rename=True) + - NameBinding(name='func', allow_rename=True) + - NameBinding(name='name_in_module', allow_rename=True) + + Function func + - NameBinding(name='arg', allow_rename=True) + - NameBinding(name='args', allow_rename=True) + - NameBinding(name='inner_func', allow_rename=True) + - NameBinding(name='kwargs', allow_rename=True) + - NameBinding(name='name_in_func', allow_rename=True) + + Function inner_func + - NameBinding(name='name_in_inner_func', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +# region generator namespace + +def test_generator_namespace(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +a = (x for x in range(10)) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - BuiltinBinding(name='range', allow_rename=True) + + GeneratorExp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_generator_namespace(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +x = [] +f = [] +a = (x for x in f for x in x) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='f', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + GeneratorExp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_generator_namespace_2(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +c = '' +line = '' +file = [] +a = (c for line in file for c in line) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=False) + - NameBinding(name='line', allow_rename=True) + + GeneratorExp + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_generator(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +c = '' +line = '' +file = [] +a = (c for c in (line for line in file)) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=False) + - NameBinding(name='line', allow_rename=True) + + GeneratorExp + - NameBinding(name='c', allow_rename=True) + + GeneratorExp + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_generator_2(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +x = '' +a = (x for x in (x for x in x)) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + GeneratorExp + - NameBinding(name='x', allow_rename=True) + + GeneratorExp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +# endregion + + +# region setcomp + +def test_setcomp_namespace(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +a = {x for x in range(10)} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - BuiltinBinding(name='range', allow_rename=True) + + SetComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_setcomp_namespace(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +x = [] +f = [] +a = {x for x in f for x in x} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='f', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + SetComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_setcomp_namespace_2(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +c = '' +line = '' +file = [] +a = {c for line in file for c in line} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=False) + - NameBinding(name='line', allow_rename=True) + + SetComp + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_setcomp(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +c = '' +line = '' +file = [] +a = {c for c in {line for line in file}} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=False) + - NameBinding(name='line', allow_rename=True) + + SetComp + - NameBinding(name='c', allow_rename=True) + + SetComp + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_setcomp_2(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +x = '' +a = {x for x in {x for x in x}} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + SetComp + - NameBinding(name='x', allow_rename=True) + + SetComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +# endregion + +# region listcomp + +def test_listcomp_namespace(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +a = [x for x in range(10)] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - BuiltinBinding(name='range', allow_rename=True) + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_listcomp_namespace(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +x = [] +f = [] +a = [x for x in f for x in x] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='f', allow_rename=True) + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_listcomp_namespace_2(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +c = '' +line = '' +file = [] +a = [c for line in file for c in line] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=False) + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_listcomp(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +c = '' +line = '' +file = [] +a =[c for c in [line for line in file]] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=False) + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_listcomp_2(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +x = '' +a =[x for x in [x for x in x]] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +# endregion + +# region dictcomp + +def test_dictcomp_namespace(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +a = {x: x for x in range(10)} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - BuiltinBinding(name='range', allow_rename=True) + + DictComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_dictcomp_namespace(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +x = [] +f = [] +a = {x: x for x, x in f for x, x in x} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='f', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + DictComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_dictcomp_namespace_2(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +c = '' +line = '' +file = [] +a = {c: c for line, line in file for c, c in line} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=False) + - NameBinding(name='line', allow_rename=True) + + DictComp + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_dictcomp(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +c = '' +line = '' +file = [] +a = {c: c for c, c in {line: line for line in file}} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=False) + - NameBinding(name='line', allow_rename=True) + + DictComp + - NameBinding(name='c', allow_rename=True) + + DictComp + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_dictcomp_2(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +x = {} +a = {x:x for x, x in {x: x for x in x}} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + DictComp + - NameBinding(name='x', allow_rename=True) + + DictComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +# endregion + +def test_class_namespace(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +OhALongName = 'Hello' +OhALongName = 'Hello' +MyOtherName = 'World' + +def func(): + class C: + OhALongName = ' World' + MyOtherName = OhALongName + ClassName = 0 + +func() +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='MyOtherName', allow_rename=True) + - NameBinding(name='OhALongName', allow_rename=False) + - NameBinding(name='func', allow_rename=True) + + Function func + - NameBinding(name='C', allow_rename=True) + + Class C + - nonlocal OhALongName + - NameBinding(name='ClassName', allow_rename=False) + - NameBinding(name='MyOtherName', allow_rename=False) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_class_name_rebinding(): + if sys.version_info >= (3, 0): + pytest.skip('Test is for python 2 only') + + source = ''' +OhALongName = 'Hello' +OhALongName = 'Hello' +MyOtherName = 'World' + +def func(): + class C: + OhALongName = OhALongName + ' World' + MyOtherName = OhALongName + + +func() +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='MyOtherName', allow_rename=True) + - NameBinding(name='OhALongName', allow_rename=False) + - NameBinding(name='func', allow_rename=True) + + Function func + - NameBinding(name='C', allow_rename=True) + + Class C + - nonlocal OhALongName + - NameBinding(name='MyOtherName', allow_rename=False) +''' + + assert_namespace_tree(source, expected_namespaces) diff --git a/test/test_bind_names_python33.py b/test/test_bind_names_python33.py new file mode 100644 index 00000000..d527d922 --- /dev/null +++ b/test/test_bind_names_python33.py @@ -0,0 +1,669 @@ +import ast +import sys + +import pytest + +from python_minifier.rename import add_namespace, resolve_names +from python_minifier.rename.bind_names import bind_names +from python_minifier.rename.util import iter_child_namespaces +from python_minifier.util import is_ast_node + + +def assert_namespace_tree(source, expected_tree): + tree = ast.parse(source) + + add_namespace(tree) + bind_names(tree) + resolve_names(tree) + + actual = print_namespace(tree) + + print(actual) + assert actual.strip() == expected_tree.strip() + + +def print_namespace(namespace, indent=''): + s = '' + + if not indent: + s += '\n' + + def namespace_name(node): + if is_ast_node(node, (ast.FunctionDef, 'AsyncFunctionDef')): + return 'Function ' + node.name + elif isinstance(node, ast.ClassDef): + return 'Class ' + node.name + else: + return namespace.__class__.__name__ + + s += indent + '+ ' + namespace_name(namespace) + '\n' + + for name in sorted(namespace.global_names): + s += indent + ' - global ' + name + '\n' + + for name in sorted(namespace.nonlocal_names): + s += indent + ' - nonlocal ' + name + '\n' + + for binding in sorted(namespace.bindings, key=lambda b: b.name): + s += indent + ' - ' + repr(binding) + '\n' + + for child in iter_child_namespaces(namespace): + s += print_namespace(child, indent=indent + ' ') + + return s + + +def test_module_namespace(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +name_in_module = True +name_in_module = True +''' + + expected_namespaces = ''' ++ Module + - BuiltinBinding(name='True', allow_rename=True) + - NameBinding(name='name_in_module', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_lambda_namespace(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +name_in_module = 0 + +b = lambda arg, *args, **kwargs: arg + 1 +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='b', allow_rename=True) + - NameBinding(name='name_in_module', allow_rename=True) + + Lambda + - NameBinding(name='arg', allow_rename=False) + - NameBinding(name='args', allow_rename=True) + - NameBinding(name='kwargs', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_function_namespace(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +name_in_module = True + +def func(arg, *args, **kwargs): + name_in_func = True + print(name_in_module) + + def inner_func(): + print(name_in_module) + name_in_inner_func = True +''' + + expected_namespaces = ''' ++ Module + - BuiltinBinding(name='True', allow_rename=True) + - NameBinding(name='func', allow_rename=True) + - NameBinding(name='name_in_module', allow_rename=True) + - BuiltinBinding(name='print', allow_rename=True) + + Function func + - NameBinding(name='arg', allow_rename=True) + - NameBinding(name='args', allow_rename=True) + - NameBinding(name='inner_func', allow_rename=True) + - NameBinding(name='kwargs', allow_rename=True) + - NameBinding(name='name_in_func', allow_rename=True) + + Function inner_func + - NameBinding(name='name_in_inner_func', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +# region generator namespace + +def test_generator_namespace(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +a = (x for x in range(10)) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - BuiltinBinding(name='range', allow_rename=True) + + GeneratorExp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_generator_namespace(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +x = [] +f = [] +a = (x for x in f for x in x) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='f', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + GeneratorExp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_generator_namespace_2(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +c = '' +line = '' +file = [] +a = (c for line in file for c in line) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + + GeneratorExp + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_generator(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +c = '' +line = '' +file = [] +a = (c for c in (line for line in file)) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + + GeneratorExp + - NameBinding(name='c', allow_rename=True) + + GeneratorExp + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_generator_2(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +x = '' +a = (x for x in (x for x in x)) +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + GeneratorExp + - NameBinding(name='x', allow_rename=True) + + GeneratorExp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +# endregion + + +# region setcomp + +def test_setcomp_namespace(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +a = {x for x in range(10)} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - BuiltinBinding(name='range', allow_rename=True) + + SetComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_setcomp_namespace(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +x = [] +f = [] +a = {x for x in f for x in x} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='f', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + SetComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_setcomp_namespace_2(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +c = '' +line = '' +file = [] +a = {c for line in file for c in line} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + + SetComp + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_setcomp(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +c = '' +line = '' +file = [] +a = {c for c in {line for line in file}} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + + SetComp + - NameBinding(name='c', allow_rename=True) + + SetComp + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_setcomp_2(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +x = '' +a = {x for x in {x for x in x}} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + SetComp + - NameBinding(name='x', allow_rename=True) + + SetComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +# endregion + +# region listcomp + +def test_listcomp_namespace(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +a = [x for x in range(10)] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - BuiltinBinding(name='range', allow_rename=True) + + ListComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_listcomp_namespace(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +x = [] +f = [] +a = [x for x in f for x in x] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='f', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + ListComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_listcomp_namespace_2(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +c = '' +line = '' +file = [] +a = [c for line in file for c in line] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + + ListComp + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_listcomp(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +c = '' +line = '' +file = [] +a =[c for c in [line for line in file]] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + + ListComp + - NameBinding(name='c', allow_rename=True) + + ListComp + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_listcomp_2(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +x = '' +a =[x for x in [x for x in x]] +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + ListComp + - NameBinding(name='x', allow_rename=True) + + ListComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +# endregion + +# region dictcomp + +def test_dictcomp_namespace(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +a = {x: x for x in range(10)} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - BuiltinBinding(name='range', allow_rename=True) + + DictComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_dictcomp_namespace(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +x = [] +f = [] +a = {x: x for x, x in f for x, x in x} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='f', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + DictComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_multi_dictcomp_namespace_2(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +c = '' +line = '' +file = [] +a = {c: c for line, line in file for c, c in line} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + + DictComp + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_dictcomp(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +c = '' +line = '' +file = [] +a = {c: c for c, c in {line: line for line in file}} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='c', allow_rename=True) + - NameBinding(name='file', allow_rename=True) + - NameBinding(name='line', allow_rename=True) + + DictComp + - NameBinding(name='c', allow_rename=True) + + DictComp + - NameBinding(name='line', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_nested_dictcomp_2(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +x = {} +a = {x:x for x, x in {x: x for x in x}} +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='a', allow_rename=True) + - NameBinding(name='x', allow_rename=True) + + DictComp + - NameBinding(name='x', allow_rename=True) + + DictComp + - NameBinding(name='x', allow_rename=True) +''' + + assert_namespace_tree(source, expected_namespaces) + + +# endregion + +def test_class_namespace(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +OhALongName = 'Hello' +OhALongName = 'Hello' +MyOtherName = 'World' + +def func(): + class C: + OhALongName = ' World' + MyOtherName = OhALongName + ClassName = 0 + +func() +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='MyOtherName', allow_rename=True) + - NameBinding(name='OhALongName', allow_rename=False) + - NameBinding(name='func', allow_rename=True) + + Function func + - NameBinding(name='C', allow_rename=True) + + Class C + - nonlocal OhALongName + - NameBinding(name='ClassName', allow_rename=False) + - NameBinding(name='MyOtherName', allow_rename=False) +''' + + assert_namespace_tree(source, expected_namespaces) + + +def test_class_name_rebinding(): + if sys.version_info < (3, 3) or sys.version_info > (3, 4): + pytest.skip('Test is for python3.3 only') + + source = ''' +OhALongName = 'Hello' +OhALongName = 'Hello' +MyOtherName = 'World' + +def func(): + class C: + OhALongName = OhALongName + ' World' + MyOtherName = OhALongName + + +func() +''' + + expected_namespaces = ''' ++ Module + - NameBinding(name='MyOtherName', allow_rename=True) + - NameBinding(name='OhALongName', allow_rename=False) + - NameBinding(name='func', allow_rename=True) + + Function func + - NameBinding(name='C', allow_rename=True) + + Class C + - nonlocal OhALongName + - NameBinding(name='MyOtherName', allow_rename=False) +''' + + assert_namespace_tree(source, expected_namespaces) diff --git a/test/test_empty_fstring.py b/test/test_empty_fstring.py deleted file mode 100644 index 9fa23656..00000000 --- a/test/test_empty_fstring.py +++ /dev/null @@ -1,19 +0,0 @@ -import ast -import sys -import pytest -from python_minifier import unparse -from python_minifier.ast_compare import compare_ast - -def test_fstring_empty_str(): - if sys.version_info < (3, 6): - pytest.skip('f-string expressions not allowed in python < 3.6') - - source = r''' -f"""\ -{fg_br}""" -''' - - print(source) - expected_ast = ast.parse(source) - actual_ast = unparse(expected_ast) - compare_ast(expected_ast, ast.parse(actual_ast)) diff --git a/test/test_fstring.py b/test/test_fstring.py new file mode 100644 index 00000000..fb9821cf --- /dev/null +++ b/test/test_fstring.py @@ -0,0 +1,103 @@ +import ast +import sys + +import pytest + +from python_minifier import unparse +from python_minifier.ast_compare import compare_ast + + +@pytest.mark.parametrize('statement', [ + 'f"{1=!r:.4}"', + 'f"{1=:.4}"', + 'f"{1=!s:.4}"', + 'f"{1=:.4}"', + 'f"{1}"', + 'f"{1=}"', + 'f"{1=!s}"', + 'f"{1=!a}"' +]) +def test_fstring_statement(statement): + if sys.version_info < (3, 8): + pytest.skip('f-string debug specifier added in python 3.8') + + assert unparse(ast.parse(statement)) == statement + +def test_pep0701(): + if sys.version_info < (3, 12): + pytest.skip('f-string syntax is bonkers before python 3.12') + + statement = 'f"{f"{f"{f"{"hello"}"}"}"}"' + assert unparse(ast.parse(statement)) == statement + + statement = 'f"This is the playlist: {", ".join([])}"' + assert unparse(ast.parse(statement)) == statement + + statement = 'f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}"' + assert unparse(ast.parse(statement)) == statement + + statement = """ +f"This is the playlist: {", ".join([ + 'Take me back to Eden', # My, my, those eyes like fire + 'Alkaline', # Not acid nor alkaline + 'Ascensionism' # Take to the broken skies at last +])}" +""" + assert unparse(ast.parse(statement)) == 'f"This is the playlist: {", ".join(["Take me back to Eden","Alkaline","Ascensionism"])}"' + + #statement = '''print(f"This is the playlist: {"\N{BLACK HEART SUIT}".join(songs)}")''' + #assert unparse(ast.parse(statement)) == statement + + statement = '''f"Magic wand: {bag["wand"]}"''' + assert unparse(ast.parse(statement)) == statement + + statement = """ +f'''A complex trick: { + bag['bag'] # recursive bags! +}''' + """ + assert unparse(ast.parse(statement)) == 'f"A complex trick: {bag["bag"]}"' + + statement = '''f"These are the things: {", ".join(things)}"''' + assert unparse(ast.parse(statement)) == statement + + statement = '''f"{source.removesuffix(".py")}.c: $(srcdir)/{source}"''' + assert unparse(ast.parse(statement)) == statement + + statement = '''f"{f"{f"infinite"}"}"+' '+f"{f"nesting!!!"}"''' + assert unparse(ast.parse(statement)) == statement + + statement = '''f"{"\\n".join(a)}"''' + assert unparse(ast.parse(statement)) == statement + + statement = '''f"{f"{f"{f"{f"{f"{1+1}"}"}"}"}"}"''' + assert unparse(ast.parse(statement)) == statement + + statement = '''f"{"":*^{1:{1}}}"''' + assert unparse(ast.parse(statement)) == statement + + #statement = '''f"{"":*^{1:{1:{1}}}}"''' + #assert unparse(ast.parse(statement)) == statement + # SyntaxError: f-string: expressions nested too deeply + + statement = '''f"___{ + x +}___"''' + assert unparse(ast.parse(statement)) == '''f"___{x}___"''' + + statement = '''f"Useless use of lambdas: {(lambda x:x*2)}"''' + assert unparse(ast.parse(statement)) == statement + +def test_fstring_empty_str(): + if sys.version_info < (3, 6): + pytest.skip('f-string expressions not allowed in python < 3.6') + + source = r''' +f"""\ +{fg_br}""" +''' + + print(source) + expected_ast = ast.parse(source) + actual_ast = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(actual_ast)) diff --git a/test/test_generic_types.py b/test/test_generic_types.py new file mode 100644 index 00000000..07938798 --- /dev/null +++ b/test/test_generic_types.py @@ -0,0 +1,278 @@ +import ast +import sys +import pytest +from python_minifier import unparse +from python_minifier.ast_compare import compare_ast + +def test_type_statement(): + if sys.version_info < (3, 12): + pytest.skip('Improved generic syntax python < 3.12') + + + source = ''' +type Point = tuple[float, float] +type ListOrSet[T] = list[T] | set[T] +''' + + expected_ast = ast.parse(source) + actual_ast = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(actual_ast)) + +def test_function_generic(): + if sys.version_info < (3, 12): + pytest.skip('Improved generic syntax python < 3.12') + + source = ''' +def a(): ... +def func[T](a: T, b: T) -> T: + ... +''' + + expected_ast = ast.parse(source) + actual_ast = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(actual_ast)) + +def test_class_generic(): + if sys.version_info < (3, 12): + pytest.skip('Improved generic syntax python < 3.12') + + source = ''' +class A: + ... +class B[S]: + ... +class C[T: str]: + ... +''' + + expected_ast = ast.parse(source) + actual_ast = unparse(expected_ast) + compare_ast(expected_ast, ast.parse(actual_ast)) + + +def test_pep695_unparse(): + if sys.version_info < (3, 12): + pytest.skip('Improved generic syntax python < 3.12') + + source = ''' +class ClassA[T: str]: + def method1(self) -> T: + ... + +def func[T](a: T, b: T) -> T: + ... + +type ListOrSet[T] = list[T] | set[T] + +# This generic class is parameterized by a TypeVar T, a +# TypeVarTuple Ts, and a ParamSpec P. +class ChildClass[T, *Ts, **P]: ... + +class ClassA[S, T](Protocol): ... # OK + +class ClassB[S, T](Protocol[S, T]): ... # Recommended type checker error + +class ClassA[T: str]: ... + +class ClassA[T: dict[str, int]]: ... # OK + +class ClassB[T: "ForwardReference"]: ... # OK + +class ClassC[V]: + class ClassD[T: dict[str, V]]: ... # Type checker error: generic type + +class ClassE[T: [str, int]]: ... # Type checker error: illegal expression form + +class ClassA[AnyStr: (str, bytes)]: ... # OK + +class ClassB[T: ("ForwardReference", bytes)]: ... # OK + +class ClassC[T: ()]: ... # Type checker error: two or more types required + +class ClassD[T: (str, )]: ... # Type checker error: two or more types required + +t1 = (bytes, str) +class ClassE[T: t1]: ... # Type checker error: literal tuple expression required + +class ClassF[T: (3, bytes)]: ... # Type checker error: invalid expression form + +class ClassG[T: (list[S], str)]: ... # Type checker error: generic type + +# A non-generic type alias +type IntOrStr = int | str + +# A generic type alias +type ListOrSet[T] = list[T] | set[T] + +# A type alias that includes a forward reference +type AnimalOrVegetable = Animal | "Vegetable" + +# A generic self-referential type alias +type RecursiveList[T] = T | list[RecursiveList[T]] + +T = TypeVar("T") +type MyList = list[T] # Type checker error: traditional type variable usage + +# The following generates no compiler error, but a type checker +# should generate an error because an upper bound type must be concrete, +# and ``Sequence[S]`` is generic. Future extensions to the type system may +# eliminate this limitation. +class ClassA[S, T: Sequence[S]]: ... + +# The following generates no compiler error, because the bound for ``S`` +# is lazily evaluated. However, type checkers should generate an error. +class ClassB[S: Sequence[T], T]: ... + +class ClassA[T](BaseClass[T], param = Foo[T]): ... # OK + +print(T) # Runtime error: 'T' is not defined + +@dec(Foo[T]) # Runtime error: 'T' is not defined +class ClassA[T]: ... + + + +def func1[T](a: T) -> T: ... # OK + +print(T) # Runtime error: 'T' is not defined + +def func2[T](a = list[T]): ... # Runtime error: 'T' is not defined + +@dec(list[T]) # Runtime error: 'T' is not defined +def func3[T](): ... + +type Alias1[K, V] = Mapping[K, V] | Sequence[K] + +S = 0 + +def outer1[S](): + S = 1 + T = 1 + + def outer2[T](): + + def inner1(): + nonlocal S # OK because it binds variable S from outer1 + #nonlocal T # Syntax error: nonlocal binding not allowed for type parameter + + def inner2(): + global S # OK because it binds variable S from global scope + +class Outer: + class Private: + pass + + # If the type parameter scope was like a traditional scope, + # the base class 'Private' would not be accessible here. + class Inner[T](Private, Sequence[T]): + pass + + # Likewise, 'Inner' would not be available in these type annotations. + def method1[T](self, a: Inner[T]) -> Inner[T]: + return a + +T = 0 + +@decorator(T) # Argument expression `T` evaluates to 0 +class ClassA[T](Sequence[T]): + T = 1 + + # All methods below should result in a type checker error + # "type parameter 'T' already in use" because they are using the + # type parameter 'T', which is already in use by the outer scope + # 'ClassA'. + def method1[T](self): + ... + + def method2[T](self, x = T): # Parameter 'x' gets default value of 1 + ... + + def method3[T](self, x: T): # Parameter 'x' has type T (scoped to method3) + ... + +T = 0 + +# T refers to the global variable +print(T) # Prints 0 + +class Outer[T]: + T = 1 + + # T refers to the local variable scoped to class 'Outer' + print(T) # Prints 1 + + class Inner1: + T = 2 + + # T refers to the local type variable within 'Inner1' + print(T) # Prints 2 + + def inner_method(self): + # T refers to the type parameter scoped to class 'Outer'; + # If 'Outer' did not use the new type parameter syntax, + # this would instead refer to the global variable 'T' + print(T) # Prints 'T' + + def outer_method(self): + T = 3 + + # T refers to the local variable within 'outer_method' + print(T) # Prints 3 + + def inner_func(): + # T refers to the variable captured from 'outer_method' + print(T) # Prints 3 + +class ClassA[T1, T2, T3](list[T1]): + def method1(self, a: T2) -> None: + ... + + def method2(self) -> T3: + ... + +upper = ClassA[object, Dummy, Dummy] +lower = ClassA[T1, Dummy, Dummy] + +upper = ClassA[Dummy, object, Dummy] +lower = ClassA[Dummy, T2, Dummy] + +upper = ClassA[Dummy, Dummy, object] +lower = ClassA[Dummy, Dummy, T3] + + + +T1 = TypeVar("T1", infer_variance=True) # Inferred variance +T2 = TypeVar("T2") # Invariant +T3 = TypeVar("T3", covariant=True) # Covariant + +# A type checker should infer the variance for T1 but use the +# specified variance for T2 and T3. +class ClassA(Generic[T1, T2, T3]): ... + +K = TypeVar("K") + +class ClassA[V](dict[K, V]): ... # Type checker error + +class ClassB[K, V](dict[K, V]): ... # OK + +class ClassC[V]: + # The use of K and V for "method1" is OK because it uses the + # "traditional" generic function mechanism where type parameters + # are implicit. In this case V comes from an outer scope (ClassC) + # and K is introduced implicitly as a type parameter for "method1". + def method1(self, a: V, b: K) -> V | K: ... + + # The use of M and K are not allowed for "method2". A type checker + # should generate an error in this case because this method uses the + # new syntax for type parameters, and all type parameters associated + # with the method must be explicitly declared. In this case, ``K`` + # is not declared by "method2", nor is it supplied by a new-style + # type parameter defined in an outer scope. + def method2[M](self, a: M, b: K) -> M | K: ... + + +''' + + expected_ast = ast.parse(source) + unparse(expected_ast) + diff --git a/test/test_hoist_literals.py b/test/test_hoist_literals.py index 7a7be678..10602efa 100644 --- a/test/test_hoist_literals.py +++ b/test/test_hoist_literals.py @@ -5,6 +5,7 @@ from python_minifier import unparse from python_minifier.ast_compare import compare_ast +from python_minifier.ast_printer import print_ast from python_minifier.rename import add_namespace, bind_names, resolve_names, rename, rename_literals, allow_rename_locals, allow_rename_globals def hoist(source): @@ -491,3 +492,28 @@ def test_hoisted_types_py2(): expected_ast = ast.parse(expected) actual_ast = hoist(source) compare_ast(expected_ast, actual_ast) + +def test_no_hoist_slots(): + source = ''' +class SlotsA(object): + __slots__ = ['aaaaa', 'bbbbb'] + notslots = ['aaaaa'] +class SlotsB(object): + __slots__ = 'aaaaa', 'bbbbb' + notslots = ['aaaaa'] +''' + expected = ''' +A = 'aaaaa' +class SlotsA(object): + __slots__ = ['aaaaa', 'bbbbb'] + notslots = [A] +class SlotsB(object): + __slots__ = 'aaaaa', 'bbbbb' + notslots = [A] +''' + expected_ast = ast.parse(expected) + actual_ast = hoist(source) + + print(print_ast(expected_ast)) + print(print_ast(actual_ast)) + compare_ast(expected_ast, actual_ast) diff --git a/test/test_is_ast_node.py b/test/test_is_ast_node.py new file mode 100644 index 00000000..25d8b253 --- /dev/null +++ b/test/test_is_ast_node.py @@ -0,0 +1,40 @@ +import sys + +import pytest + +import python_minifier.ast_compat as ast +from python_minifier.util import is_ast_node + +def test_type_nodes(): + assert is_ast_node(ast.Str('a'), ast.Str) + + if hasattr(ast, 'Bytes'): + assert is_ast_node(ast.Bytes(b'a'), ast.Bytes) + + assert is_ast_node(ast.Num(1), ast.Num) + assert is_ast_node(ast.Num(0), ast.Num) + + if hasattr(ast, 'NameConstant'): + assert is_ast_node(ast.NameConstant(True), ast.NameConstant) + assert is_ast_node(ast.NameConstant(False), ast.NameConstant) + assert is_ast_node(ast.NameConstant(None), ast.NameConstant) + else: + assert is_ast_node(ast.Name(id='True', ctx=ast.Load()), ast.Name) + assert is_ast_node(ast.Name(id='False', ctx=ast.Load()), ast.Name) + assert is_ast_node(ast.Name(id='None', ctx=ast.Load()), ast.Name) + + assert is_ast_node(ast.Ellipsis(), ast.Ellipsis) + +def test_constant_nodes(): + # only test on python 3.8+ + if sys.version_info < (3, 8): + pytest.skip('Constant not available') + + assert is_ast_node(ast.Constant('a'), ast.Str) + assert is_ast_node(ast.Constant(b'a'), ast.Bytes) + assert is_ast_node(ast.Constant(1), ast.Num) + assert is_ast_node(ast.Constant(0), ast.Num) + assert is_ast_node(ast.Constant(True), ast.NameConstant) + assert is_ast_node(ast.Constant(False), ast.NameConstant) + assert is_ast_node(ast.Constant(None), ast.NameConstant) + assert is_ast_node(ast.Constant(ast.literal_eval('...')), ast.Ellipsis) diff --git a/tox.ini b/tox.ini index 65bc6185..83814d0e 100644 --- a/tox.ini +++ b/tox.ini @@ -56,6 +56,14 @@ deps = pyyaml==6.0.0 pyperf==2.4.1 +[testenv:python312] +basepython = /usr/local/bin/python3.12 +deps = + pytest==7.4.2 + sh==2.0.6 + pyyaml==6.0.1 + pyperf==2.6.1 + [testenv:pypy] basepython = /usr/bin/pypy diff --git a/typing_test/stubtest-allowlist.txt b/typing_test/stubtest-allowlist.txt new file mode 100644 index 00000000..dcab540d --- /dev/null +++ b/typing_test/stubtest-allowlist.txt @@ -0,0 +1 @@ +python_minifier.ast_compat.* diff --git a/xtest/manifests/python3.12_test_manifest.yaml b/xtest/manifests/python3.12_test_manifest.yaml new file mode 100644 index 00000000..4c143483 --- /dev/null +++ b/xtest/manifests/python3.12_test_manifest.yaml @@ -0,0 +1,7228 @@ +/usr/local/lib/python3.12/test/leakers/test_ctypes.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/leakers/test_selftype.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/regrtestdata/import_from_tests/test_regrtest_a.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/regrtestdata/import_from_tests/test_regrtest_c.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test___all__.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test__locale.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test__opcode.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test__xxinterpchannels.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test__xxsubinterpreters.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_abc.py: +- options: + preserve_locals: + - A + - B + - C + - D + rename_globals: true + status: passing +- options: + preserve_locals: + - A + - B + - C + - D + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: + - A + - B + - C + - D + status: passing +- options: + preserve_locals: + - A + - B + - C + - D + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_abstract_numbers.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_aifc.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_argparse.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_array.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ast.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncgen.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_buffered_proto.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_context.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_eager_task_factory.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_futures2.py: +- options: + preserve_locals: future + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: future + rename_globals: true + status: passing +- options: + preserve_locals: future + remove_literal_statements: true + status: passing +- options: + preserve_locals: future + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_locks.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_pep492.py: +- options: + preserve_locals: + - foo + - spam + rename_globals: true + status: passing +- options: + preserve_locals: + - foo + - spam + remove_literal_statements: true + status: passing +- options: + preserve_locals: + - foo + - spam + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: + - foo + - spam + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_proactor_events.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_protocols.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_queues.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_runners.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_selector_events.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_sendfile.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_server.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_sock_lowlevel.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_ssl.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_sslproto.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_subprocess.py: +- options: + preserve_globals: + - TestSubprocessTransport + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + preserve_globals: + - TestSubprocessTransport + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_taskgroups.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_threads.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_timeouts.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_transports.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_asyncio/test_waitfor.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_atexit.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_audioop.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_audit.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_augassign.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_base64.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_baseexception.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_bigaddrspace.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_bigmem.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/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.12/test/test_binop.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_bisect.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_bool.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_buffer.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_bufio.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_builtin.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_bytes.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_bz2.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_calendar.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_call.py: +- options: + convert_posargs_to_args: false + preserve_globals: + - A + preserve_locals: + - arg + rename_globals: true + status: passing +- options: + convert_posargs_to_args: false + preserve_locals: + - arg + status: passing +- options: + convert_posargs_to_args: false + preserve_globals: + - A + preserve_locals: + - arg + remove_literal_statements: true + rename_globals: true + status: passing +- options: + convert_posargs_to_args: false + preserve_locals: + - arg + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_capi/test_abstract.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_capi/test_bytearray.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_capi/test_bytes.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_capi/test_codecs.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_capi/test_complex.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_capi/test_dict.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_capi/test_eval_code_ex.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_capi/test_float.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_capi/test_getargs.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_capi/test_immortal.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_capi/test_list.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_capi/test_long.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_capi/test_mem.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_capi/test_set.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_capi/test_structmembers.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_capi/test_sys.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_capi/test_unicode.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_capi/test_watchers.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_cgi.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_cgitb.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_charmapcodec.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_class.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_cmath.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_cmd.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_cmd_line.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passings +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_code_module.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_codeccallbacks.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_codecencodings_cn.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_codecencodings_hk.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_codecencodings_iso2022.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_codecencodings_jp.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_codecencodings_kr.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_codecencodings_tw.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_codecmaps_cn.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_codecmaps_hk.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_codecmaps_jp.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_codecmaps_kr.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_codecmaps_tw.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_codecs.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_codeop.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_collections.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_colorsys.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_compare.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_compiler_assemble.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_compiler_codegen.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_complex.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_configparser.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_contains.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_context.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_copy.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_copyreg.py: +- options: + hoist_literals: false + preserve_globals: + - WithPrivate + - _WithLeadingUnderscoreAndPrivate + - TypeError + - type + - unittest + remove_literal_statements: true + rename_globals: true + status: passing +- options: + hoist_literals: false + status: passing +- options: + hoist_literals: false + preserve_globals: + - WithPrivate + - _WithLeadingUnderscoreAndPrivate + - TypeError + - type + - unittest + rename_globals: true + status: passing +- options: + hoist_literals: false + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_cprofile.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_crypt.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_csv.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_anon.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_array_in_pointer.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_arrays.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_as_parameter.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_bitfields.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_buffers.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_bytes.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_byteswap.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_callbacks.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_cast.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_cfuncs.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_checkretval.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_delattr.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_errno.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_find.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_frombuffer.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_funcptr.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_functions.py: +- options: + remove_literal_statements: true + remove_object_base: false + status: passing +- options: + remove_object_base: false + rename_globals: true + status: passing +- options: + remove_object_base: false + status: passing +- options: + remove_literal_statements: true + remove_object_base: false + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_incomplete.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_init.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_internals.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_keeprefs.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_libc.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_loading.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_memfunctions.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_numbers.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_objects.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_parameters.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_pep3118.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_pickling.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_pointers.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_prototypes.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_python_api.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_random_things.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_refcounts.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_repr.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_returnfuncptrs.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_simplesubclasses.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_sizes.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_slicing.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_stringptr.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_strings.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_struct_fields.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_structures.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_unaligned_structures.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_unicode.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_values.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_varsize_struct.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_win32.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ctypes/test_wintypes.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_curses.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_datetime.py: +- options: + preserve_globals: + - load_tests + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + preserve_globals: + - load_tests + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_dbm.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_dbm_dumb.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_dbm_gnu.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_dbm_ndbm.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_decimal.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_decorators.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_defaultdict.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_deque.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_descr.py: +- options: + hoist_literals: false + preserve_locals: + - junk + - self + - A + - B + - C + - D + - E + - F + - G + - d + rename_globals: true + status: passing +- options: + hoist_literals: false + preserve_locals: + - junk + - self + - A + - B + - C + - D + - E + - F + - G + - d + remove_literal_statements: true + status: passing +- options: + hoist_literals: false + preserve_locals: + - junk + - self + - A + - B + - C + - D + - E + - F + - G + - d + remove_literal_statements: true + rename_globals: true + status: passing +- options: + hoist_literals: false + preserve_locals: + - junk + - self + - A + - B + - C + - D + - E + - F + - G + - d + status: passing +/usr/local/lib/python3.12/test/test_dict_version.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_dictcomps.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_dictviews.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_difflib.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_doctest2.py: +- options: + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_dynamic.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_dynamicclassattribute.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_email/test__encoded_words.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_email/test__header_value_parser.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_email/test_asian_codecs.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_email/test_contentmanager.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_email/test_defect_handling.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_email/test_email.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_email/test_generator.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_email/test_headerregistry.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_email/test_inversion.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_email/test_message.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_email/test_parser.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_email/test_pickleable.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_email/test_policy.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_email/test_utils.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_embed.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ensurepip.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/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.12/test/test_enumerate.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_eof.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_epoll.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_errno.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_except_star.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_exception_hierarchy.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_exception_variations.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_faulthandler.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_fcntl.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_file.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_file_eintr.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_filecmp.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_fileinput.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_fileio.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_fileutils.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_finalization.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_float.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_flufl.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_fnmatch.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_fork1.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_format.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_fractions.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_frozen.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_fstring.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/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.12/test/test_functools.py: +- options: + remove_annotations: false + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_annotations: false + rename_globals: true + status: passing +- options: + remove_annotations: false + status: passing +- options: + remove_annotations: false + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_future_stmt/test_future.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_future_stmt/test_future_flags.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_future_stmt/test_future_multiple_features.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_future_stmt/test_future_multiple_imports.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_future_stmt/test_future_single_import.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_gc.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_generator_stop.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_generators.py: +- options: + preserve_locals: + - conjoin + - Queens + - Knights + - f + - g + - call_send + - call_throw + - func + - a + remove_literal_statements: true + status: passing +- options: + preserve_globals: + - GeneratorTest + - conjoin + - Queens + - Knights + - func + - a + - b + - support + preserve_locals: + - conjoin + - Queens + - Knights + - f + - g + - call_send + - call_throw + - func + - a + rename_globals: true + status: passing +- options: + preserve_globals: + - GeneratorTest + - conjoin + - Queens + - Knights + - func + - a + - b + - support + preserve_locals: + - conjoin + - Queens + - Knights + - f + - g + - call_send + - call_throw + - func + - a + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: + - conjoin + - Queens + - Knights + - f + - g + - call_send + - call_throw + - func + - a + status: passing +/usr/local/lib/python3.12/test/test_genericalias.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_genericclass.py: +- options: + preserve_locals: + - D + - Meta + - C + - C_is_none + remove_literal_statements: true + status: passing +- options: + preserve_locals: + - D + - Meta + - C + - C_is_none + status: passing +- options: + preserve_locals: + - D + - Meta + - C + - C_is_none + rename_globals: true + status: passing +- options: + preserve_locals: + - D + - Meta + - C + - C_is_none + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_genericpath.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_genexps.py: +- options: + preserve_globals: + - load_tests + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + preserve_globals: + - load_tests + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_getopt.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_getpass.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_getpath.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_glob.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_global.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_grammar.py: +- options: + preserve_locals: + - f + - x + - y + - b + - c + - e + - g + - k + - j + - h + - l + - k + - Spam + remove_annotations: false + rename_globals: true + status: passing +- options: + preserve_locals: + - f + - x + - y + - b + - c + - e + - g + - k + - j + - h + - l + - k + - Spam + remove_annotations: false + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: + - f + - x + - y + - b + - c + - e + - g + - k + - j + - h + - l + - k + - Spam + remove_annotations: false + status: passing +- options: + preserve_locals: + - f + - x + - y + - b + - c + - e + - g + - k + - j + - h + - l + - k + - Spam + remove_annotations: false + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_graphlib.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_grp.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_gzip.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_hash.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_hashlib.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_heapq.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_hmac.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_html.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_htmlparser.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_http_cookiejar.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_http_cookies.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_httplib.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_httpservers.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_idle.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_imaplib.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_imghdr.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/builtin/test_finder.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/builtin/test_loader.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/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.12/test/test_importlib/extension/test_loader.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/extension/test_path_hook.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/frozen/test_finder.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/frozen/test_loader.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/import_/test___loader__.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/import_/test___package__.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/import_/test_api.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/import_/test_caching.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/import_/test_fromlist.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/import_/test_meta_path.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/import_/test_packages.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/import_/test_path.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/import_/test_relative_imports.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/resources/test_reader.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/source/test_finder.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/source/test_path_hook.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/source/test_source_encoding.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/test_abc.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/test_api.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/test_lazy.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/test_locks.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/test_namespace_pkgs.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/test_pkg_import.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/test_spec.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_importlib/test_threaded_import.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_importlib/test_util.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_index.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_int.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_int_literal.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_interpreters.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_io.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ipaddress.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_isinstance.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_iter.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_iterlen.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_itertools.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_json/test_decode.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_json/test_default.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_json/test_dump.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_json/test_encode_basestring_ascii.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_json/test_enum.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_json/test_fail.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_json/test_float.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_json/test_indent.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_json/test_pass1.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_json/test_pass2.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_json/test_pass3.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_json/test_recursion.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_json/test_scanstring.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_json/test_separators.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_json/test_speedups.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_json/test_tool.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_json/test_unicode.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_keyword.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_keywordonlyarg.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_largefile.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_lib2to3/test_fixers.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_lib2to3/test_main.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_lib2to3/test_refactor.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_linecache.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_list.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_listcomps.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_locale.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_long.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_longexp.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_lzma.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_mailbox.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_mailcap.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_marshal.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_math.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_math_property.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_memoryio.py: +- options: + preserve_locals: + - PickleTestMemIO + rename_globals: true + status: passing +- options: + preserve_locals: + - PickleTestMemIO + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: + - PickleTestMemIO + remove_literal_statements: true + status: passing +- options: + preserve_locals: + - PickleTestMemIO + status: passing +/usr/local/lib/python3.12/test/test_memoryview.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_mimetypes.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_minidom.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_mmap.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_modulefinder.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_monitoring.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_multibytecodec.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_multiprocessing_main_handling.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_named_expressions.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_netrc.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_nis.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_nntplib.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_numeric_tower.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_opcache.py: +- options: + preserve_locals: Class + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: Class + rename_globals: true + status: passing +- options: + preserve_locals: Class + remove_literal_statements: true + status: passing +- options: + preserve_locals: Class + status: passing +/usr/local/lib/python3.12/test/test_opcodes.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_openpty.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_operator.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_optparse.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ordered_dict.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_pep646_syntax.py: +- options: + preserve_globals: + - load_tests + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_globals: + - load_tests + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_perf_profiler.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_perfmaps.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_pickle.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_picklebuffer.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_pickletools.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_pipes.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_pkg.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_pkgutil.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_platform.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_plistlib.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_poll.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_popen.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_poplib.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_positional_only_arg.py: +- options: + convert_posargs_to_args: false + preserve_locals: + - something + - a + - x + - b + - f + - g + remove_annotations: false + remove_literal_statements: true + status: passing +- options: + convert_posargs_to_args: false + preserve_globals: + - global_pos_only_f + - global_pos_only_and_normal + - global_pos_only_defaults + preserve_locals: + - something + - a + - x + - b + - f + - g + remove_annotations: false + rename_globals: true + status: passing +- options: + convert_posargs_to_args: false + preserve_locals: + - something + - a + - x + - b + - f + - g + remove_annotations: false + status: passing +- options: + convert_posargs_to_args: false + preserve_globals: + - global_pos_only_f + - global_pos_only_and_normal + - global_pos_only_defaults + preserve_locals: + - something + - a + - x + - b + - f + - g + remove_annotations: false + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_pow.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_print.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_profile.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_property.py: +- options: {} + status: passing +- options: + preserve_globals: + - PropertyUnreachableAttributeNoName + - PropertyUnreachableAttributeWithName + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_globals: + - PropertyUnreachableAttributeNoName + - PropertyUnreachableAttributeWithName + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_pstats.py: +- options: + preserve_locals: + - pass1 + - pass2 + - pass3 + remove_literal_statements: true + status: passing +- options: + preserve_locals: + - pass1 + - pass2 + - pass3 + rename_globals: true + status: passing +- options: + preserve_locals: + - pass1 + - pass2 + - pass3 + status: passing +- options: + preserve_locals: + - pass1 + - pass2 + - pass3 + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_pty.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_pulldom.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_pwd.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_py_compile.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_pyclbr.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_pyexpat.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_queue.py: +- options: + preserve_globals: + - import_helper + - threading + - threading_helper + - unittest + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + preserve_globals: + - import_helper + - threading + - threading_helper + - unittest + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_quopri.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_raise.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_random.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_range.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_re.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_readline.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_repl.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_reprlib.py: +- options: + preserve_globals: + - ClassWithFailingRepr + - ReprTests + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_globals: + - ClassWithFailingRepr + - ReprTests + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_resource.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_richcmp.py: +- options: + preserve_locals: + - Spam + rename_globals: true + status: passing +- options: + preserve_locals: + - Spam + status: passing +- options: + preserve_locals: + - Spam + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: + - Spam + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_rlcompleter.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_robotparser.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_sax.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_sched.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_scope.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_script_helper.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_secrets.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_select.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_selectors.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_set.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_setcomps.py: +- options: + preserve_globals: + - doctests + - load_tests + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + preserve_globals: + - doctests + - load_tests + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_shelve.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_shlex.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_signal.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_site.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_slice.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_smtpnet.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_sndhdr.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_socket.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_socketserver.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_sort.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_source_encoding.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_spwd.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_sqlite3/test_backup.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_sqlite3/test_cli.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_sqlite3/test_factory.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_sqlite3/test_hooks.py: +- options: + preserve_locals: + - bad_progress + remove_literal_statements: true + status: passing +- options: + preserve_locals: + - bad_progress + status: passing +- options: + preserve_locals: + - bad_progress + rename_globals: true + status: passing +- options: + preserve_locals: + - bad_progress + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_sqlite3/test_regression.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_sqlite3/test_transactions.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_sqlite3/test_types.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_sqlite3/test_userfunctions.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_ssl.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_stable_abi_ctypes.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_statistics.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_strftime.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_string.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_string_literals.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_stringprep.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_strptime.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_strtod.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_struct.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_structseq.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_subclassinit.py: +- options: + preserve_locals: + - MyClass + - NotGoingToWork + - Descriptor + remove_literal_statements: true + status: passing +- options: + preserve_locals: + - MyClass + - NotGoingToWork + - Descriptor + status: passing +- options: + preserve_locals: + - MyClass + - NotGoingToWork + - Descriptor + rename_globals: true + status: passing +- options: + preserve_locals: + - MyClass + - NotGoingToWork + - Descriptor + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/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.12/test/test_sunau.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_sundry.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_super.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_support.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_symtable.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_syntax.py: +- options: {} + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_sys_setprofile.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_syslog.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_tabnanny.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_tcl.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_telnetlib.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_tempfile.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_termios.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_textwrap.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_thread.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_threadedtempfile.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_threading_local.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_threadsignals.py: +- options: + preserve_globals: + - setUpModule + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + preserve_globals: + - setUpModule + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_time.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_timeit.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_timeout.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_tokenize.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_ttk_textonly.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_tty.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_tuple.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_turtle.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_type_aliases.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_type_annotations.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_type_cache.py: +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_type_comments.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_type_params.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_typechecks.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_types.py: +- options: + remove_annotations: false + rename_globals: true + status: passing +- options: + remove_annotations: false + status: passing +- options: + remove_annotations: false + remove_literal_statements: true + status: passing +- options: + remove_annotations: false + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_ucn.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_unary.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_unicode.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_unicode_identifiers.py: +- options: + preserve_locals: + - Unicode + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: + - Unicode + status: passing +- options: + preserve_locals: + - Unicode + rename_globals: true + status: passing +- options: + preserve_locals: + - Unicode + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_unicodedata.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_unittest/test_assertions.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_unittest/test_async_case.py: +- options: + preserve_globals: + - tearDownModule + - MyException + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + preserve_globals: + - tearDownModule + - MyException + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_unittest/test_break.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_unittest/test_discovery.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_unittest/test_functiontestcase.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_unittest/test_loader.py: +- options: + preserve_locals: + - MyTest + - MyTestCase + rename_globals: true + status: passing +- options: + preserve_locals: + - MyTest + - MyTestCase + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: + - MyTest + - MyTestCase + remove_literal_statements: true + status: passing +- options: + preserve_locals: + - MyTest + - MyTestCase + status: passing +/usr/local/lib/python3.12/test/test_unittest/test_program.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_unittest/test_result.py: +- options: + preserve_globals: + - Test_TextTestResult + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_unittest/test_runner.py: +- options: + preserve_globals: + - CustomError + preserve_locals: + - cleanup1 + - cleanup2 + - CleanUpExc + - exc2 + - foo + - bar + rename_globals: true + status: passing +- options: + preserve_globals: + - CustomError + preserve_locals: + - cleanup1 + - cleanup2 + - CleanUpExc + - exc2 + - foo + - bar + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: + - cleanup1 + - cleanup2 + - CleanUpExc + - exc2 + - foo + - bar + remove_literal_statements: true + status: passing +- options: + preserve_locals: + - cleanup1 + - cleanup2 + - CleanUpExc + - exc2 + - foo + - bar + status: passing +/usr/local/lib/python3.12/test/test_unittest/test_setups.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_unittest/test_skipping.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_unittest/test_suite.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_univnewlines.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_unparse.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_urllib2.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_urllib2_localnet.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_urllib2net.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_urllib_response.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_urllibnet.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_urlparse.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_userdict.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_userlist.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_userstring.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_utf8_mode.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_utf8source.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_uu.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_uuid.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_venv.py: [] +/usr/local/lib/python3.12/test/test_wait3.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_wait4.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_wave.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_weakref.py: +- options: + preserve_globals: + - FinalizeTestCase + preserve_locals: + - MyConfig + rename_globals: true + status: passing +- options: + preserve_locals: + - MyConfig + status: passing +- options: + preserve_globals: + - FinalizeTestCase + preserve_locals: + - MyConfig + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: + - MyConfig + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_weakset.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_webbrowser.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_with.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_wsgiref.py: +- options: + preserve_locals: + - CustomException + status: passing +- options: + preserve_locals: + - CustomException + rename_globals: true + status: passing +- options: + preserve_locals: + - CustomException + remove_literal_statements: true + status: passing +- options: + preserve_locals: + - CustomException + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_xdrlib.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_xml_dom_minicompat.py: +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_xml_etree.py: +- options: + preserve_globals: + - setUpModule + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + preserve_globals: + - setUpModule + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_xml_etree_c.py: +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_xxlimited.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_xxtestfuzz.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +/usr/local/lib/python3.12/test/test_yield_from.py: +- options: + preserve_locals: + - spam + - eggs + rename_globals: true + status: passing +- options: + preserve_locals: + - spam + - eggs + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_locals: + - spam + - eggs + remove_literal_statements: true + status: passing +- options: + preserve_locals: + - spam + - eggs + status: passing +/usr/local/lib/python3.12/test/test_zipapp.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_zipfile/test_core.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_zipfile64.py: +- options: + rename_globals: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_zipimport_support.py: +- options: + remove_literal_statements: true + status: passing +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_zlib.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing +/usr/local/lib/python3.12/test/test_zoneinfo/test_zoneinfo.py: +- options: + preserve_locals: + - ZISubclass + status: passing +- options: + preserve_globals: + - setUpModule + - tearDownModule + preserve_locals: + - ZISubclass + remove_literal_statements: true + rename_globals: true + status: passing +- options: + preserve_globals: + - setUpModule + - tearDownModule + preserve_locals: + - ZISubclass + rename_globals: true + status: passing +- options: + preserve_locals: + - ZISubclass + remove_literal_statements: true + status: passing +/usr/local/lib/python3.12/test/test_zoneinfo/test_zoneinfo_property.py: +- options: + remove_literal_statements: true + rename_globals: true + status: passing +- options: + remove_literal_statements: true + status: passing +- options: {} + status: passing +- options: + rename_globals: true + status: passing diff --git a/xtest/manifests/python3.8_test_manifest.yaml b/xtest/manifests/python3.8_test_manifest.yaml index 6b37bd1d..cef77a00 100644 --- a/xtest/manifests/python3.8_test_manifest.yaml +++ b/xtest/manifests/python3.8_test_manifest.yaml @@ -3793,15 +3793,7 @@ - options: remove_literal_statements: true rename_globals: true -/usr/lib64/python3.8/test/test_urllib2net.py: -- options: {} -- options: - rename_globals: true -- options: - remove_literal_statements: true -- options: - remove_literal_statements: true - rename_globals: true +/usr/lib64/python3.8/test/test_urllib2net.py: [] /usr/lib64/python3.8/test/test_urllib_response.py: - options: {} - options: diff --git a/xtest/manifests/python3.9_test_manifest.yaml b/xtest/manifests/python3.9_test_manifest.yaml index 7b6a551f..e3f60342 100644 --- a/xtest/manifests/python3.9_test_manifest.yaml +++ b/xtest/manifests/python3.9_test_manifest.yaml @@ -3738,15 +3738,7 @@ - options: remove_literal_statements: true rename_globals: true -/usr/local/lib/python3.9/test/test_urllib2net.py: -- options: {} -- options: - rename_globals: true -- options: - remove_literal_statements: true -- options: - remove_literal_statements: true - rename_globals: true +/usr/local/lib/python3.9/test/test_urllib2net.py: [] /usr/local/lib/python3.9/test/test_urllib_response.py: - options: {} - options: diff --git a/xtest/test_regrtest.py b/xtest/test_regrtest.py index 5c53deda..3120558a 100644 --- a/xtest/test_regrtest.py +++ b/xtest/test_regrtest.py @@ -37,7 +37,7 @@ def __init__(self, interpreter): def load(self): with open(self._manifest_path) as f: - self._files = yaml.safe_load(f) + self._files = yaml.safe_load(f) or {} def __len__(self): return sum([len(test_cases) for test_cases in self._files.values()])