diff --git a/.bumpversion.cfg b/.bumpversion.cfg index 75ee09b..44cb99e 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,16 +1,22 @@ [bumpversion] -current_version = 0.2.3 +current_version = 0.3.3 commit = True tag = True [bumpversion:file:pyproject.toml] +search = version = "{current_version}" +replace = version = "{new_version}" [bumpversion:file:repo_helper.yml] -[bumpversion:file:__pkginfo__.py] - [bumpversion:file:README.rst] [bumpversion:file:doc-source/index.rst] [bumpversion:file:coverage_pyver_pragma/__init__.py] +search = : str = "{current_version}" +replace = : str = "{new_version}" + +[bumpversion:file:.github/workflows/conda_ci.yml] +search = ={current_version}=py_1 +replace = ={new_version}=py_1 diff --git a/.dependabot/config.yml b/.dependabot/config.yml deleted file mode 100644 index 4584924..0000000 --- a/.dependabot/config.yml +++ /dev/null @@ -1,9 +0,0 @@ -# This file is managed by 'repo_helper'. Don't edit it directly. ---- -version: 1 -update_configs: -- package_manager: python - directory: / - update_schedule: weekly - default_reviewers: - - domdfcoding diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b0d6764..1983232 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -17,7 +17,10 @@ THE ISSUE WILL BE CLOSED IF INSUFFICIENT INFORMATION IS PROVIDED. ## Steps to Reproduce - + 1. 2. @@ -41,7 +44,7 @@ THE ISSUE WILL BE CLOSED IF INSUFFICIENT INFORMATION IS PROVIDED. * coverage_pyver_pragma: ## Installation source - + ## Other Additional Information: diff --git a/.github/actions_build_conda.sh b/.github/actions_build_conda.sh deleted file mode 100755 index 1acebbe..0000000 --- a/.github/actions_build_conda.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# This file is managed by 'repo_helper'. Don't edit it directly. - -set -e -x - -python -m repo_helper make-recipe || exit 1 - -# Switch to miniconda -source "/home/runner/miniconda/etc/profile.d/conda.sh" -hash -r -conda activate base -conda config --set always_yes yes --set changeps1 no -conda update -q conda -conda install conda-build -conda install anaconda-client -conda info -a - -conda config --add channels conda-forge || exit 1 -conda config --add channels domdfcoding || exit 1 - -conda build conda -c conda-forge -c domdfcoding --output-folder conda/dist --skip-existing - -exit 0 diff --git a/.github/actions_deploy_conda.sh b/.github/actions_deploy_conda.sh deleted file mode 100755 index 7fdb89a..0000000 --- a/.github/actions_deploy_conda.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -# This file is managed by 'repo_helper'. Don't edit it directly. - -set -e -x - -# Switch to miniconda -source "/home/runner/miniconda/etc/profile.d/conda.sh" -hash -r -conda activate base -conda config --set always_yes yes --set changeps1 no -conda update -q conda -conda install anaconda-client -conda info -a - -for f in conda/dist/noarch/coverage_pyver_pragma-*.tar.bz2; do - [ -e "$f" ] || continue - echo "$f" - conda install "$f" || exit 1 - echo "Deploying to Anaconda.org..." - anaconda -t "$ANACONDA_TOKEN" upload "$f" || exit 1 - echo "Successfully deployed to Anaconda.org." -done - -exit 0 diff --git a/.github/dependabot.yml b/.github/dependabot.yml index e769ad3..454225a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,5 +6,6 @@ updates: directory: / schedule: interval: weekly + open-pull-requests-limit: 0 reviewers: - domdfcoding diff --git a/.github/milestones.py b/.github/milestones.py new file mode 100755 index 0000000..5e868dc --- /dev/null +++ b/.github/milestones.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python + +# stdlib +import os +import sys + +# 3rd party +from github3 import GitHub +from github3.repos import Repository +from packaging.version import InvalidVersion, Version + +latest_tag = os.environ["GITHUB_REF_NAME"] + +try: + current_version = Version(latest_tag) +except InvalidVersion: + sys.exit() + +gh: GitHub = GitHub(token=os.environ["GITHUB_TOKEN"]) +repo: Repository = gh.repository(*os.environ["GITHUB_REPOSITORY"].split('/', 1)) + +for milestone in repo.milestones(state="open"): + try: + milestone_version = Version(milestone.title) + except InvalidVersion: + continue + if milestone_version == current_version: + sys.exit(not milestone.update(state="closed")) diff --git a/.github/stale.yml b/.github/stale.yml index bb7ca3f..bb7fa62 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -7,7 +7,7 @@ daysUntilStale: 180 # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. -daysUntilClose: 180 +daysUntilClose: false # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) onlyLabels: [] @@ -28,13 +28,13 @@ exemptMilestones: false exemptAssignees: false # Label to use when marking as stale -staleLabel: wontfix +staleLabel: stale # Comment to post when marking as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. +markComment: false +# This issue has been automatically marked as stale because it has not had +# recent activity. It will be closed if no further activity occurs. Thank you +# for your contributions. # Comment to post when removing the stale label. # unmarkComment: > diff --git a/.github/workflows/cleanup.yml b/.github/workflows/cleanup.yml deleted file mode 100644 index 741c0bd..0000000 --- a/.github/workflows/cleanup.yml +++ /dev/null @@ -1,14 +0,0 @@ -# This file is managed by 'repo_helper'. Don't edit it directly. ---- -name: Artefact Cleaner -on: - schedule: - - cron: 0 9 1 * * -jobs: - Clean: - runs-on: ubuntu-latest - steps: - - name: cleanup - uses: glassechidna/artifact-cleaner@v2 - with: - minimumAge: 1000000.0 diff --git a/.github/workflows/conda_ci.yml b/.github/workflows/conda_ci.yml index 8026e83..137475e 100644 --- a/.github/workflows/conda_ci.yml +++ b/.github/workflows/conda_ci.yml @@ -4,41 +4,65 @@ name: Conda Tests on: push: - pull_request: branches: ["master"] +permissions: + contents: read + jobs: tests: name: "Conda" - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 + defaults: + run: + shell: bash -l {0} steps: - name: Checkout 🛎️ - uses: "actions/checkout@v2" + uses: "actions/checkout@v4" - name: Setup Python 🐍 - uses: "actions/setup-python@v2" + uses: "actions/setup-python@v5" + with: + python-version: "3.11" + + - name: Setup Conda + uses: conda-incubator/setup-miniconda@v2.1.1 with: - python-version: "3.8" + activate-environment: env + conda-build-version: 3.28.4 + miniconda-version: py311_24.1.2-0 + python-version: "3.11" + miniforge-variant: Mambaforge - name: Install dependencies 🔧 run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade repo_helper + python -m pip install --upgrade "whey-conda" "whey" # $CONDA is an environment variable pointing to the root of the miniconda directory - $CONDA/bin/conda update -q conda - $CONDA/bin/conda install conda-build=3.21.0 - + $CONDA/bin/conda update -n base conda $CONDA/bin/conda config --add channels conda-forge $CONDA/bin/conda config --add channels domdfcoding - - name: "Build and install package" + - name: "Build and index channel" run: | - # This mess is only necessary because conda won't fix it themselves - # https://github.com/conda/conda/issues/1884 - - python -m repo_helper build --conda --out-dir conda-bld/noarch + python -m whey --builder whey_conda --out-dir conda-bld/noarch $CONDA/bin/conda index ./conda-bld || exit 1 - $CONDA/bin/conda install -c file://$(pwd)/conda-bld coverage_pyver_pragma -y || exit 1 + + - name: "Search for package" + run: | + $CONDA/bin/conda search -c file://$(pwd)/conda-bld coverage_pyver_pragma + $CONDA/bin/conda search -c file://$(pwd)/conda-bld --override-channels coverage_pyver_pragma + + - name: "Install package" + run: | + $CONDA/bin/conda install -c file://$(pwd)/conda-bld coverage_pyver_pragma=0.3.3=py_1 -y || exit 1 + + - name: "Run Tests" + run: | + rm -rf coverage_pyver_pragma + $CONDA/bin/conda install pytest coincidence || exit 1 + pip install -r tests/requirements.txt + pytest tests/ diff --git a/.github/workflows/docs_test_action.yml b/.github/workflows/docs_test_action.yml index 01232d5..8f60ba5 100644 --- a/.github/workflows/docs_test_action.yml +++ b/.github/workflows/docs_test_action.yml @@ -2,18 +2,36 @@ --- name: "Docs Check" on: - - pull_request - - push + push: + branches-ignore: + - 'repo-helper-update' + - 'pre-commit-ci-update-config' + - 'imgbot' + pull_request: + +permissions: + contents: read jobs: docs: runs-on: ubuntu-latest steps: - name: Checkout 🛎️ - uses: "actions/checkout@v1" + uses: "actions/checkout@v4" + + - name: Check for changed files + uses: dorny/paths-filter@v2 + id: changes + with: + list-files: "json" + filters: | + code: + - '!tests/**' + - name: Install and Build 🔧 - uses: ammaraskar/sphinx-action@master + uses: sphinx-toolbox/sphinx-action@sphinx-3.3.1 + if: steps.changes.outputs.code == 'true' with: - pre-build-command: apt-get update && apt-get install gcc python3-dev git pandoc -y && python -m pip install tox + pre-build-command: python -m pip install tox docs-folder: "doc-source/" - build-command: "tox -e docs -- " + build-command: "tox -e docs -- -W " diff --git a/.github/workflows/flake8.yml b/.github/workflows/flake8.yml index 177294b..5e67c5c 100644 --- a/.github/workflows/flake8.yml +++ b/.github/workflows/flake8.yml @@ -4,29 +4,47 @@ name: Flake8 on: push: + branches-ignore: + - 'repo-helper-update' + - 'pre-commit-ci-update-config' + - 'imgbot' pull_request: - branches: ["master"] + +permissions: + contents: read jobs: Run: name: "Flake8" - runs-on: "ubuntu-18.04" + runs-on: "ubuntu-22.04" steps: - name: Checkout 🛎️ - uses: "actions/checkout@v2" + uses: "actions/checkout@v4" + + - name: Check for changed files + uses: dorny/paths-filter@v2 + id: changes + with: + list-files: "json" + filters: | + code: + - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' - name: Setup Python 🐍 - uses: "actions/setup-python@v2" + if: steps.changes.outputs.code == 'true' + uses: "actions/setup-python@v5" with: - python-version: "3.8" + python-version: "3.9" - name: Install dependencies 🔧 + if: steps.changes.outputs.code == 'true' run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel - python -m pip install tox + python -m pip install tox~=3.0 - name: "Run Flake8" - run: "python -m tox -e lint -- --format github" + if: steps.changes.outputs.code == 'true' + run: "python -m tox -e lint -s false -- --format github" diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml index afee01e..4c22a52 100644 --- a/.github/workflows/mypy.yml +++ b/.github/workflows/mypy.yml @@ -4,8 +4,14 @@ name: mypy on: push: + branches-ignore: + - 'repo-helper-update' + - 'pre-commit-ci-update-config' + - 'imgbot' pull_request: - branches: ["master"] + +permissions: + contents: read jobs: Run: @@ -14,24 +20,35 @@ jobs: strategy: matrix: - os: ['windows-2019', 'macos-latest', 'ubuntu-20.04'] + os: ['ubuntu-22.04', 'windows-2022'] fail-fast: false steps: - name: Checkout 🛎️ - uses: "actions/checkout@v2" + uses: "actions/checkout@v4" + + - name: Check for changed files + uses: dorny/paths-filter@v2 + id: changes + with: + list-files: "json" + filters: | + code: + - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' - name: Setup Python 🐍 - uses: "actions/setup-python@v2" + if: steps.changes.outputs.code == 'true' + uses: "actions/setup-python@v5" with: - python-version: "3.6" + python-version: "3.9" - name: Install dependencies 🔧 run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade tox virtualenv + python -m pip install --upgrade tox~=3.0 virtualenv!=20.16.0 - name: "Run mypy" - run: "python -m tox -e mypy" + if: steps.changes.outputs.code == 'true' + run: "python -m tox -e mypy -s false" diff --git a/.github/workflows/octocheese.yml b/.github/workflows/octocheese.yml index b27338b..e26858d 100644 --- a/.github/workflows/octocheese.yml +++ b/.github/workflows/octocheese.yml @@ -3,10 +3,8 @@ name: "GitHub Releases" on: - push: - branches: ["master"] schedule: - - cron: 0 12 * * 2,4,6 + - cron: 0 12 * * * jobs: Run: diff --git a/.github/workflows/python_ci.yml b/.github/workflows/python_ci.yml index 054b63f..aacb588 100644 --- a/.github/workflows/python_ci.yml +++ b/.github/workflows/python_ci.yml @@ -4,51 +4,78 @@ name: Windows on: push: + branches-ignore: + - 'repo-helper-update' + - 'pre-commit-ci-update-config' + - 'imgbot' + pull_request: - branches: ["master"] + +permissions: + actions: write + issues: write + contents: read jobs: tests: - name: "windows-2019 / Python ${{ matrix.config.python-version }}" - runs-on: "windows-2019" + name: "windows-2022 / Python ${{ matrix.config.python-version }}" + runs-on: "windows-2022" continue-on-error: ${{ matrix.config.experimental }} env: - USING_COVERAGE: '3.6,3.7,3.8,3.9,3.10.0-alpha.5,pypy-3.6,pypy-3.7' + USING_COVERAGE: '3.7,3.8,3.9,3.10,3.11,3.12,3.13,pypy-3.7,pypy-3.8,pypy-3.9' strategy: fail-fast: False matrix: config: - - {python-version: "3.6", testenvs: "py36,build", experimental: False} - {python-version: "3.7", testenvs: "py37,build", experimental: False} - {python-version: "3.8", testenvs: "py38,build", experimental: False} - {python-version: "3.9", testenvs: "py39,build", experimental: False} - - {python-version: "3.10.0-alpha.5", testenvs: "py310-dev,build", experimental: True} - - {python-version: "pypy-3.6", testenvs: "pypy36,build", experimental: False} + - {python-version: "3.10", testenvs: "py310,build", experimental: False} + - {python-version: "3.11", testenvs: "py311,build", experimental: True} + - {python-version: "3.12", testenvs: "py312,build", experimental: True} + - {python-version: "3.13", testenvs: "py313,build", experimental: True} - {python-version: "pypy-3.7", testenvs: "pypy37,build", experimental: False} + - {python-version: "pypy-3.8", testenvs: "pypy38,build", experimental: False} + - {python-version: "pypy-3.9-v7.3.15", testenvs: "pypy39,build", experimental: True} steps: - name: Checkout 🛎️ - uses: "actions/checkout@v2" + uses: "actions/checkout@v4" + + - name: Check for changed files + if: startsWith(github.ref, 'refs/tags/') != true + uses: dorny/paths-filter@v2 + id: changes + with: + list-files: "json" + filters: | + code: + - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' - name: Setup Python 🐍 - uses: "actions/setup-python@v2" + id: setup-python + if: ${{ steps.changes.outputs.code == 'true' || steps.changes.outcome == 'skipped' }} + uses: "actions/setup-python@v5" with: python-version: "${{ matrix.config.python-version }}" - name: Install dependencies 🔧 + if: steps.setup-python.outcome == 'success' run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade tox virtualenv + python -m pip install --upgrade tox~=3.0 virtualenv!=20.16.0 - name: "Run Tests for Python ${{ matrix.config.python-version }}" - run: python -m tox -e "${{ matrix.config.testenvs }}" + if: steps.setup-python.outcome == 'success' + run: python -m tox -e "${{ matrix.config.testenvs }}" -s false - name: "Upload Coverage 🚀" - uses: actions/upload-artifact@v2 - if: ${{ always() }} + uses: actions/upload-artifact@v4 + if: ${{ always() && steps.setup-python.outcome == 'success' }} with: name: "coverage-${{ matrix.config.python-version }}" path: .coverage + include-hidden-files: true diff --git a/.github/workflows/python_ci_linux.yml b/.github/workflows/python_ci_linux.yml index bd1ed02..38d5522 100644 --- a/.github/workflows/python_ci_linux.yml +++ b/.github/workflows/python_ci_linux.yml @@ -4,66 +4,94 @@ name: Linux on: push: + branches-ignore: + - 'repo-helper-update' + - 'pre-commit-ci-update-config' + - 'imgbot' + tags: + - '*' pull_request: - branches: ["master"] + +permissions: + actions: write + issues: write + contents: read jobs: tests: - name: "ubuntu-20.04 / Python ${{ matrix.config.python-version }}" - runs-on: "ubuntu-20.04" + name: "ubuntu-22.04 / Python ${{ matrix.config.python-version }}" + runs-on: "ubuntu-22.04" continue-on-error: ${{ matrix.config.experimental }} env: - USING_COVERAGE: '3.6,3.7,3.8,3.9,3.10.0-alpha.5,pypy-3.6,pypy-3.7' + USING_COVERAGE: '3.7,3.8,3.9,3.10,3.11,3.12,3.13,pypy-3.7,pypy-3.8,pypy-3.9' strategy: fail-fast: False matrix: config: - - {python-version: "3.6", testenvs: "py36,build", experimental: False} - {python-version: "3.7", testenvs: "py37,build", experimental: False} - {python-version: "3.8", testenvs: "py38,build", experimental: False} - {python-version: "3.9", testenvs: "py39,build", experimental: False} - - {python-version: "3.10.0-alpha.5", testenvs: "py310-dev,build", experimental: True} - - {python-version: "pypy-3.6", testenvs: "pypy36,build", experimental: False} + - {python-version: "3.10", testenvs: "py310,build", experimental: False} + - {python-version: "3.11", testenvs: "py311,build", experimental: True} + - {python-version: "3.12", testenvs: "py312,build", experimental: True} + - {python-version: "3.13", testenvs: "py313,build", experimental: True} - {python-version: "pypy-3.7", testenvs: "pypy37,build", experimental: False} + - {python-version: "pypy-3.8", testenvs: "pypy38,build", experimental: False} + - {python-version: "pypy-3.9", testenvs: "pypy39,build", experimental: True} steps: - name: Checkout 🛎️ - uses: "actions/checkout@v2" + uses: "actions/checkout@v4" + + - name: Check for changed files + if: startsWith(github.ref, 'refs/tags/') != true + uses: dorny/paths-filter@v2 + id: changes + with: + list-files: "json" + filters: | + code: + - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' - name: Setup Python 🐍 - uses: "actions/setup-python@v2" + id: setup-python + if: ${{ steps.changes.outputs.code == 'true' || steps.changes.outcome == 'skipped' }} + uses: "actions/setup-python@v5" with: python-version: "${{ matrix.config.python-version }}" - name: Install dependencies 🔧 + if: steps.setup-python.outcome == 'success' run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade tox virtualenv + python -m pip install --upgrade tox~=3.0 virtualenv!=20.16.0 python -m pip install --upgrade coverage_pyver_pragma - name: "Run Tests for Python ${{ matrix.config.python-version }}" - run: python -m tox -e "${{ matrix.config.testenvs }}" + if: steps.setup-python.outcome == 'success' + run: python -m tox -e "${{ matrix.config.testenvs }}" -s false - name: "Upload Coverage 🚀" - uses: actions/upload-artifact@v2 - if: ${{ always() }} + uses: actions/upload-artifact@v4 + if: ${{ always() && steps.setup-python.outcome == 'success' }} with: name: "coverage-${{ matrix.config.python-version }}" path: .coverage + include-hidden-files: true Coverage: needs: tests - runs-on: "ubuntu-20.04" + runs-on: "ubuntu-22.04" steps: - name: Checkout 🛎️ - uses: "actions/checkout@v2" + uses: "actions/checkout@v4" - name: Setup Python 🐍 - uses: "actions/setup-python@v2" + uses: "actions/setup-python@v5" with: python-version: 3.8 @@ -73,26 +101,32 @@ jobs: python -m pip install --upgrade "coveralls>=3.0.0" coverage_pyver_pragma - name: "Download Coverage 🪂" - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: path: coverage - name: Display structure of downloaded files + id: show run: ls -R working-directory: coverage + continue-on-error: true - name: Combine Coverage 👷 + if: ${{ steps.show.outcome != 'failure' }} run: | shopt -s globstar python -m coverage combine coverage/**/.coverage - name: "Upload Combined Coverage Artefact 🚀" - uses: actions/upload-artifact@v2 + if: ${{ steps.show.outcome != 'failure' }} + uses: actions/upload-artifact@v4 with: name: "combined-coverage" path: .coverage + include-hidden-files: true - name: "Upload Combined Coverage to Coveralls" + if: ${{ steps.show.outcome != 'failure' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | @@ -101,69 +135,105 @@ jobs: Deploy: needs: tests - runs-on: "ubuntu-20.04" + runs-on: "ubuntu-22.04" steps: - name: Checkout 🛎️ - uses: "actions/checkout@v2" + uses: "actions/checkout@v4" if: startsWith(github.ref, 'refs/tags/') - name: Setup Python 🐍 - uses: "actions/setup-python@v2" + uses: "actions/setup-python@v5" + if: startsWith(github.ref, 'refs/tags/') with: python-version: 3.8 - if: startsWith(github.ref, 'refs/tags/') - name: Install dependencies 🔧 + if: startsWith(github.ref, 'refs/tags/') run: | python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade tox - if: startsWith(github.ref, 'refs/tags/') + python -m pip install --upgrade tox~=3.0 - name: Build distributions 📦 + if: startsWith(github.ref, 'refs/tags/') run: | tox -e build - if: startsWith(github.ref, 'refs/tags/') - name: Upload distribution to PyPI 🚀 if: startsWith(github.ref, 'refs/tags/') - uses: pypa/gh-action-pypi-publish@master + uses: pypa/gh-action-pypi-publish@v1.4.2 with: user: __token__ password: ${{ secrets.PYPI_TOKEN }} skip_existing: true + - name: Close milestone 🚪 + if: startsWith(github.ref, 'refs/tags/') + run: | + python -m pip install --upgrade github3.py packaging + python .github/milestones.py + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + Conda: needs: deploy - runs-on: "ubuntu-20.04" + runs-on: ubuntu-22.04 if: startsWith(github.ref, 'refs/tags/') || (startsWith(github.event.head_commit.message, 'Bump version') != true) steps: - name: Checkout 🛎️ - uses: "actions/checkout@v2" + uses: "actions/checkout@v4" - name: Setup Python 🐍 - uses: "actions/setup-python@v2" + uses: "actions/setup-python@v5" with: - python-version: 3.8 + python-version: 3.11 + + - name: Setup Conda + uses: conda-incubator/setup-miniconda@v2.1.1 + with: + activate-environment: env + conda-build-version: 3.28.4 + miniconda-version: py311_24.1.2-0 + python-version: "3.11" + miniforge-variant: Mambaforge - name: Install dependencies 🔧 run: | + python -VV + python -m site python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade repo_helper - - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh - bash miniconda.sh -b -p $HOME/miniconda - - - name: Build Conda 📦 + python -m pip install --upgrade "mkrecipe" "whey" + # $CONDA is an environment variable pointing to the root of the miniconda directory + $CONDA/bin/conda config --set always_yes yes --set changeps1 no + $CONDA/bin/conda update -n base conda + $CONDA/bin/conda info -a + $CONDA/bin/conda install conda-forge::py-lief=0.14.1 + $CONDA/bin/conda config --add channels conda-forge + $CONDA/bin/conda config --add channels domdfcoding + + $CONDA/bin/conda config --remove channels defaults + + - name: Build Conda Package 📦 run: | - chmod +x .github/actions_build_conda.sh - bash .github/actions_build_conda.sh + python -m mkrecipe --type wheel || exit 1 + $CONDA/bin/conda build conda -c conda-forge -c domdfcoding --output-folder conda/dist - - name: Deploy Conda 🚀 + - name: Deploy Conda Package 🚀 + if: startsWith(github.ref, 'refs/tags/') run: | - chmod +x .github/actions_deploy_conda.sh - bash .github/actions_deploy_conda.sh + $CONDA/bin/conda config --set always_yes yes --set changeps1 no + $CONDA/bin/conda install anaconda-client + $CONDA/bin/conda info -a + + for f in conda/dist/noarch/coverage_pyver_pragma-*.tar.bz2; do + [ -e "$f" ] || continue + echo "$f" + conda install "$f" || exit 1 + echo "Deploying to Anaconda.org..." + $CONDA/bin/anaconda -t "$ANACONDA_TOKEN" upload "$f" || exit 1 + echo "Successfully deployed to Anaconda.org." + done env: ANACONDA_TOKEN: ${{ secrets.ANACONDA_TOKEN }} diff --git a/.github/workflows/python_ci_macos.yml b/.github/workflows/python_ci_macos.yml index 0d0c451..5b8b3e2 100644 --- a/.github/workflows/python_ci_macos.yml +++ b/.github/workflows/python_ci_macos.yml @@ -4,51 +4,78 @@ name: macOS on: push: + branches-ignore: + - 'repo-helper-update' + - 'pre-commit-ci-update-config' + - 'imgbot' + pull_request: - branches: ["master"] + +permissions: + actions: write + issues: write + contents: read jobs: tests: - name: "macos-latest / Python ${{ matrix.config.python-version }}" - runs-on: "macos-latest" + name: "macos-${{ matrix.config.os-ver }} / Python ${{ matrix.config.python-version }}" + runs-on: "macos-${{ matrix.config.os-ver }}" continue-on-error: ${{ matrix.config.experimental }} env: - USING_COVERAGE: '3.6,3.7,3.8,3.9,3.10.0-alpha.5,pypy-3.6,pypy-3.7' + USING_COVERAGE: '3.7,3.8,3.9,3.10,3.11,3.12,3.13,pypy-3.7,pypy-3.8,pypy-3.9' strategy: fail-fast: False matrix: config: - - {python-version: "3.6", testenvs: "py36,build", experimental: False} - - {python-version: "3.7", testenvs: "py37,build", experimental: False} - - {python-version: "3.8", testenvs: "py38,build", experimental: False} - - {python-version: "3.9", testenvs: "py39,build", experimental: False} - - {python-version: "3.10.0-alpha.5", testenvs: "py310-dev,build", experimental: True} - - {python-version: "pypy-3.6", testenvs: "pypy36,build", experimental: False} - - {python-version: "pypy-3.7", testenvs: "pypy37,build", experimental: False} + - {python-version: "3.7", os-ver: "13", testenvs: "py37,build", experimental: False} + - {python-version: "3.8", os-ver: "14", testenvs: "py38,build", experimental: False} + - {python-version: "3.9", os-ver: "14", testenvs: "py39,build", experimental: False} + - {python-version: "3.10", os-ver: "14", testenvs: "py310,build", experimental: False} + - {python-version: "3.11", os-ver: "14", testenvs: "py311,build", experimental: True} + - {python-version: "3.12", os-ver: "14", testenvs: "py312,build", experimental: True} + - {python-version: "3.13", os-ver: "14", testenvs: "py313,build", experimental: True} + - {python-version: "pypy-3.7", os-ver: "13", testenvs: "pypy37,build", experimental: False} + - {python-version: "pypy-3.8", os-ver: "14", testenvs: "pypy38,build", experimental: False} + - {python-version: "pypy-3.9", os-ver: "14", testenvs: "pypy39,build", experimental: True} steps: - name: Checkout 🛎️ - uses: "actions/checkout@v2" + uses: "actions/checkout@v4" + + - name: Check for changed files + if: startsWith(github.ref, 'refs/tags/') != true + uses: dorny/paths-filter@v2 + id: changes + with: + list-files: "json" + filters: | + code: + - '!(doc-source/**|CONTRIBUTING.rst|.imgbotconfig|.pre-commit-config.yaml|.pylintrc|.readthedocs.yml)' - name: Setup Python 🐍 - uses: "actions/setup-python@v2" + id: setup-python + if: ${{ steps.changes.outputs.code == 'true' || steps.changes.outcome == 'skipped' }} + uses: "actions/setup-python@v5" with: python-version: "${{ matrix.config.python-version }}" - name: Install dependencies 🔧 + if: steps.setup-python.outcome == 'success' run: | python -VV python -m site python -m pip install --upgrade pip setuptools wheel - python -m pip install --upgrade tox virtualenv + python -m pip install --upgrade tox~=3.0 virtualenv!=20.16.0 - name: "Run Tests for Python ${{ matrix.config.python-version }}" - run: python -m tox -e "${{ matrix.config.testenvs }}" + if: steps.setup-python.outcome == 'success' + run: python -m tox -e "${{ matrix.config.testenvs }}" -s false - name: "Upload Coverage 🚀" - uses: actions/upload-artifact@v2 - if: ${{ always() }} + uses: actions/upload-artifact@v4 + if: ${{ always() && steps.setup-python.outcome == 'success' }} with: name: "coverage-${{ matrix.config.python-version }}" path: .coverage + include-hidden-files: true diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a56a7a0..1b3d9f5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,15 @@ exclude: ^$ +ci: + autoupdate_schedule: quarterly + repos: + - repo: https://github.com/repo-helper/pyproject-parser + rev: v0.13.0 + hooks: + - id: reformat-pyproject + - repo: https://github.com/pre-commit/pre-commit-hooks rev: v3.4.0 hooks: @@ -25,28 +33,28 @@ repos: - id: end-of-file-fixer - repo: https://github.com/domdfcoding/pre-commit-hooks - rev: v0.2.1 + rev: v0.4.0 hooks: - id: requirements-txt-sorter args: - --allow-git - id: check-docstring-first - exclude: ^(doc-source/conf|__pkginfo__|make_conda_recipe|setup|tests/.*)\.py$ + exclude: ^(doc-source/conf|__pkginfo__|setup|tests/.*)\.py$ - id: bind-requirements - - repo: https://github.com/domdfcoding/flake8-dunder-all - rev: v0.1.5 + - repo: https://github.com/python-formate/flake8-dunder-all + rev: v0.4.1 hooks: - id: ensure-dunder-all files: ^coverage_pyver_pragma/.*\.py$ - repo: https://github.com/domdfcoding/flake2lint - rev: v0.4.0 + rev: v0.4.3 hooks: - id: flake2lint - repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.8.0 + rev: v1.10.0 hooks: - id: python-no-eval - id: rst-backticks @@ -54,7 +62,7 @@ repos: - id: rst-inline-touching-normal - repo: https://github.com/asottile/pyupgrade - rev: v2.10.0 + rev: v2.12.0 hooks: - id: pyupgrade args: @@ -62,19 +70,24 @@ repos: - --keep-runtime-typing - repo: https://github.com/Lucas-C/pre-commit-hooks - rev: v1.1.9 + rev: v1.5.1 hooks: - id: remove-crlf - id: forbid-crlf - - repo: https://github.com/repo-helper/formate - rev: v0.4.2 + - repo: https://github.com/python-formate/snippet-fmt + rev: v0.1.5 + hooks: + - id: snippet-fmt + + - repo: https://github.com/python-formate/formate + rev: v0.8.0 hooks: - id: formate - exclude: ^(doc-source/conf|__pkginfo__|make_conda_recipe|setup)\.(_)?py$ + exclude: ^(doc-source/conf|__pkginfo__|setup)\.(_)?py$ - - repo: https://github.com/domdfcoding/dep_checker - rev: v0.5.0 + - repo: https://github.com/python-coincidence/dep_checker + rev: v0.8.0 hooks: - id: dep_checker args: diff --git a/.pylintrc b/.pylintrc index a21206a..81ecba0 100644 --- a/.pylintrc +++ b/.pylintrc @@ -66,7 +66,7 @@ confidence= # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" disable=all -enable=assert-on-tuple,astroid-error,bad-except-order,bad-inline-option,bad-option-value,bad-reversed-sequence,bare-except,binary-op-exception,boolean-datetime,catching-non-exception,cell-var-from-loop,confusing-with-statement,consider-merging-isinstance,consider-using-enumerate,consider-using-ternary,continue-in-finally,cyclic-import,deprecated-pragma,django-not-available,duplicate-except,duplicate-key,eval-used,exec-used,expression-not-assigned,fatal,file-ignored,fixme,global-at-module-level,global-statement,global-variable-not-assigned,global-variable-undefined,http-response-with-content-type-json,http-response-with-json-dumps,invalid-all-object,invalid-characters-in-docstring,len-as-condition,literal-comparison,locally-disabled,locally-enabled,lost-exception,lowercase-l-suffix,misplaced-bare-raise,missing-kwoa,mixed-line-endings,model-has-unicode,model-missing-unicode,model-no-explicit-unicode,model-unicode-not-callable,multiple-imports,new-db-field-with-default,non-ascii-bytes-literals,nonexistent-operator,not-in-loop,notimplemented-raised,overlapping-except,parse-error,pointless-statement,pointless-string-statement,raising-bad-type,raising-non-exception,raw-checker-failed,redefine-in-handler,redefined-argument-from-local,redefined-builtin,redundant-content-type-for-json-response,reimported,relative-import,return-outside-function,simplifiable-if-statement,singleton-comparison,syntax-error,trailing-comma-tuple,trailing-newlines,unbalanced-tuple-unpacking,undefined-all-variable,undefined-loop-variable,unexpected-line-ending-format,unidiomatic-typecheck,unnecessary-lambda,unnecessary-pass,unnecessary-semicolon,unneeded-not,unpacking-non-sequence,unreachable,unrecognized-inline-option,used-before-assignment,useless-else-on-loop,using-constant-test,wildcard-import,yield-outside-function,useless-return +enable=assert-on-tuple,astroid-error,bad-except-order,bad-inline-option,bad-option-value,bad-reversed-sequence,bare-except,binary-op-exception,boolean-datetime,catching-non-exception,cell-var-from-loop,confusing-with-statement,consider-merging-isinstance,consider-using-enumerate,consider-using-ternary,continue-in-finally,deprecated-pragma,django-not-available,duplicate-except,duplicate-key,eval-used,exec-used,expression-not-assigned,fatal,file-ignored,fixme,global-at-module-level,global-statement,global-variable-not-assigned,global-variable-undefined,http-response-with-content-type-json,http-response-with-json-dumps,invalid-all-object,invalid-characters-in-docstring,len-as-condition,literal-comparison,locally-disabled,locally-enabled,lost-exception,lowercase-l-suffix,misplaced-bare-raise,missing-kwoa,mixed-line-endings,model-has-unicode,model-missing-unicode,model-no-explicit-unicode,model-unicode-not-callable,multiple-imports,new-db-field-with-default,non-ascii-bytes-literals,nonexistent-operator,not-in-loop,notimplemented-raised,overlapping-except,parse-error,pointless-statement,pointless-string-statement,raising-bad-type,raising-non-exception,raw-checker-failed,redefine-in-handler,redefined-argument-from-local,redefined-builtin,redundant-content-type-for-json-response,reimported,relative-import,return-outside-function,simplifiable-if-statement,singleton-comparison,syntax-error,trailing-comma-tuple,trailing-newlines,unbalanced-tuple-unpacking,undefined-all-variable,undefined-loop-variable,unexpected-line-ending-format,unidiomatic-typecheck,unnecessary-lambda,unnecessary-pass,unnecessary-semicolon,unneeded-not,unpacking-non-sequence,unreachable,unrecognized-inline-option,used-before-assignment,useless-else-on-loop,using-constant-test,wildcard-import,yield-outside-function,useless-return [REPORTS] diff --git a/.readthedocs.yml b/.readthedocs.yml index ce3f99b..83fc025 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -5,11 +5,20 @@ version: 2 sphinx: builder: html configuration: doc-source/conf.py -formats: all +formats: + - pdf + - htmlzip python: - version: 3.8 install: - requirements: requirements.txt - requirements: doc-source/requirements.txt - - method: pip - path: . +build: + os: ubuntu-22.04 + tools: + python: '3.9' + jobs: + post_create_environment: + - pip install . + post_install: + - pip install sphinxcontrib-applehelp==1.0.4 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==2.0.1 + sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 01ed042..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -include __pkginfo__.py -include LICENSE -include requirements.txt -prune **/__pycache__ -recursive-include coverage_pyver_pragma *.pyi -include coverage_pyver_pragma/py.typed diff --git a/README.rst b/README.rst index e7077f6..8910632 100644 --- a/README.rst +++ b/README.rst @@ -26,48 +26,48 @@ coverage_pyver_pragma * - Activity - |commits-latest| |commits-since| |maintained| |pypi-downloads| * - QA - - |codefactor| |actions_flake8| |actions_mypy| |pre_commit_ci| + - |codefactor| |actions_flake8| |actions_mypy| * - Other - |license| |language| |requires| -.. |docs| image:: https://img.shields.io/readthedocs/coverage_pyver_pragma/latest?logo=read-the-docs - :target: https://coverage_pyver_pragma.readthedocs.io/en/latest +.. |docs| image:: https://img.shields.io/readthedocs/coverage-pyver-pragma/latest?logo=read-the-docs + :target: https://coverage-pyver-pragma.readthedocs.io/en/latest :alt: Documentation Build Status -.. |docs_check| image:: https://github.com/domdfcoding/coverage_pyver_pragma/workflows/Docs%20Check/badge.svg - :target: https://github.com/domdfcoding/coverage_pyver_pragma/actions?query=workflow%3A%22Docs+Check%22 +.. |docs_check| image:: https://github.com/python-coincidence/coverage_pyver_pragma/workflows/Docs%20Check/badge.svg + :target: https://github.com/python-coincidence/coverage_pyver_pragma/actions?query=workflow%3A%22Docs+Check%22 :alt: Docs Check Status -.. |actions_linux| image:: https://github.com/domdfcoding/coverage_pyver_pragma/workflows/Linux/badge.svg - :target: https://github.com/domdfcoding/coverage_pyver_pragma/actions?query=workflow%3A%22Linux%22 +.. |actions_linux| image:: https://github.com/python-coincidence/coverage_pyver_pragma/workflows/Linux/badge.svg + :target: https://github.com/python-coincidence/coverage_pyver_pragma/actions?query=workflow%3A%22Linux%22 :alt: Linux Test Status -.. |actions_windows| image:: https://github.com/domdfcoding/coverage_pyver_pragma/workflows/Windows/badge.svg - :target: https://github.com/domdfcoding/coverage_pyver_pragma/actions?query=workflow%3A%22Windows%22 +.. |actions_windows| image:: https://github.com/python-coincidence/coverage_pyver_pragma/workflows/Windows/badge.svg + :target: https://github.com/python-coincidence/coverage_pyver_pragma/actions?query=workflow%3A%22Windows%22 :alt: Windows Test Status -.. |actions_macos| image:: https://github.com/domdfcoding/coverage_pyver_pragma/workflows/macOS/badge.svg - :target: https://github.com/domdfcoding/coverage_pyver_pragma/actions?query=workflow%3A%22macOS%22 +.. |actions_macos| image:: https://github.com/python-coincidence/coverage_pyver_pragma/workflows/macOS/badge.svg + :target: https://github.com/python-coincidence/coverage_pyver_pragma/actions?query=workflow%3A%22macOS%22 :alt: macOS Test Status -.. |actions_flake8| image:: https://github.com/domdfcoding/coverage_pyver_pragma/workflows/Flake8/badge.svg - :target: https://github.com/domdfcoding/coverage_pyver_pragma/actions?query=workflow%3A%22Flake8%22 +.. |actions_flake8| image:: https://github.com/python-coincidence/coverage_pyver_pragma/workflows/Flake8/badge.svg + :target: https://github.com/python-coincidence/coverage_pyver_pragma/actions?query=workflow%3A%22Flake8%22 :alt: Flake8 Status -.. |actions_mypy| image:: https://github.com/domdfcoding/coverage_pyver_pragma/workflows/mypy/badge.svg - :target: https://github.com/domdfcoding/coverage_pyver_pragma/actions?query=workflow%3A%22mypy%22 +.. |actions_mypy| image:: https://github.com/python-coincidence/coverage_pyver_pragma/workflows/mypy/badge.svg + :target: https://github.com/python-coincidence/coverage_pyver_pragma/actions?query=workflow%3A%22mypy%22 :alt: mypy status -.. |requires| image:: https://requires.io/github/domdfcoding/coverage_pyver_pragma/requirements.svg?branch=master - :target: https://requires.io/github/domdfcoding/coverage_pyver_pragma/requirements/?branch=master +.. |requires| image:: https://dependency-dash.repo-helper.uk/github/python-coincidence/coverage_pyver_pragma/badge.svg + :target: https://dependency-dash.repo-helper.uk/github/python-coincidence/coverage_pyver_pragma/ :alt: Requirements Status -.. |coveralls| image:: https://img.shields.io/coveralls/github/domdfcoding/coverage_pyver_pragma/master?logo=coveralls - :target: https://coveralls.io/github/domdfcoding/coverage_pyver_pragma?branch=master +.. |coveralls| image:: https://img.shields.io/coveralls/github/python-coincidence/coverage_pyver_pragma/master?logo=coveralls + :target: https://coveralls.io/github/python-coincidence/coverage_pyver_pragma?branch=master :alt: Coverage -.. |codefactor| image:: https://img.shields.io/codefactor/grade/github/domdfcoding/coverage_pyver_pragma?logo=codefactor - :target: https://www.codefactor.io/repository/github/domdfcoding/coverage_pyver_pragma +.. |codefactor| image:: https://img.shields.io/codefactor/grade/github/python-coincidence/coverage_pyver_pragma?logo=codefactor + :target: https://www.codefactor.io/repository/github/python-coincidence/coverage_pyver_pragma :alt: CodeFactor Grade .. |pypi-version| image:: https://img.shields.io/pypi/v/coverage_pyver_pragma @@ -94,32 +94,28 @@ coverage_pyver_pragma :target: https://anaconda.org/domdfcoding/coverage_pyver_pragma :alt: Conda - Platform -.. |license| image:: https://img.shields.io/github/license/domdfcoding/coverage_pyver_pragma - :target: https://github.com/domdfcoding/coverage_pyver_pragma/blob/master/LICENSE +.. |license| image:: https://img.shields.io/github/license/python-coincidence/coverage_pyver_pragma + :target: https://github.com/python-coincidence/coverage_pyver_pragma/blob/master/LICENSE :alt: License -.. |language| image:: https://img.shields.io/github/languages/top/domdfcoding/coverage_pyver_pragma +.. |language| image:: https://img.shields.io/github/languages/top/python-coincidence/coverage_pyver_pragma :alt: GitHub top language -.. |commits-since| image:: https://img.shields.io/github/commits-since/domdfcoding/coverage_pyver_pragma/v0.2.3 - :target: https://github.com/domdfcoding/coverage_pyver_pragma/pulse +.. |commits-since| image:: https://img.shields.io/github/commits-since/python-coincidence/coverage_pyver_pragma/v0.3.3 + :target: https://github.com/python-coincidence/coverage_pyver_pragma/pulse :alt: GitHub commits since tagged version -.. |commits-latest| image:: https://img.shields.io/github/last-commit/domdfcoding/coverage_pyver_pragma - :target: https://github.com/domdfcoding/coverage_pyver_pragma/commit/master +.. |commits-latest| image:: https://img.shields.io/github/last-commit/python-coincidence/coverage_pyver_pragma + :target: https://github.com/python-coincidence/coverage_pyver_pragma/commit/master :alt: GitHub last commit -.. |maintained| image:: https://img.shields.io/maintenance/yes/2021 +.. |maintained| image:: https://img.shields.io/maintenance/yes/2025 :alt: Maintenance .. |pypi-downloads| image:: https://img.shields.io/pypi/dm/coverage_pyver_pragma :target: https://pypi.org/project/coverage_pyver_pragma/ :alt: PyPI - Downloads -.. |pre_commit_ci| image:: https://results.pre-commit.ci/badge/github/domdfcoding/coverage_pyver_pragma/master.svg - :target: https://results.pre-commit.ci/latest/github/domdfcoding/coverage_pyver_pragma/master - :alt: pre-commit.ci status - .. end shields Installation @@ -141,8 +137,8 @@ To install with ``conda``: .. code-block:: bash - $ conda config --add channels http://conda.anaconda.org/conda-forge - $ conda config --add channels http://conda.anaconda.org/domdfcoding + $ conda config --add channels https://conda.anaconda.org/conda-forge + $ conda config --add channels https://conda.anaconda.org/domdfcoding * Then install diff --git a/__pkginfo__.py b/__pkginfo__.py deleted file mode 100644 index 40c687f..0000000 --- a/__pkginfo__.py +++ /dev/null @@ -1,32 +0,0 @@ -# This file is managed by 'repo_helper'. Don't edit it directly. -# Copyright © 2020 Dominic Davis-Foster -# -# This file is distributed under the same license terms as the program it came with. -# There will probably be a file called LICEN[S/C]E in the same directory as this file. -# -# In any case, this program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# -# This script based on https://github.com/rocky/python-uncompyle6/blob/master/__pkginfo__.py -# - -# stdlib -import pathlib - -__all__ = [ - "__copyright__", - "__version__", - "repo_root", - "install_requires", - "extras_require", - ] - -__copyright__ = """ -2020-2021 Dominic Davis-Foster -""" - -__version__ = "0.2.3" -repo_root = pathlib.Path(__file__).parent -install_requires = (repo_root / "requirements.txt").read_text(encoding="utf-8").split('\n') -extras_require = {"all": []} diff --git a/coverage_pyver_pragma/__init__.py b/coverage_pyver_pragma/__init__.py index aacd0ac..fc478ef 100644 --- a/coverage_pyver_pragma/__init__.py +++ b/coverage_pyver_pragma/__init__.py @@ -27,14 +27,16 @@ # # stdlib +import functools import re from contextlib import suppress +from typing import Set # 3rd party -import coverage.python # type: ignore -import pyparsing # type: ignore -from coverage.config import DEFAULT_EXCLUDE # type: ignore -from coverage.misc import join_regex # type: ignore +import coverage.python +import pyparsing +from coverage.config import DEFAULT_EXCLUDE +from coverage.misc import join_regex # this package from coverage_pyver_pragma.grammar import GRAMMAR @@ -42,10 +44,10 @@ __author__: str = "Dominic Davis-Foster" __copyright__: str = "2020-2021 Dominic Davis-Foster" __license__: str = "MIT License" -__version__: str = "0.2.3" +__version__: str = "0.3.3" __email__: str = "dominic@davis-foster.co.uk" -__all__ = ["DSL_EXCLUDE", "evaluate_exclude"] +__all__ = ("DSL_EXCLUDE", "evaluate_exclude") DSL_EXCLUDE = re.compile(r'.*#\s*(?:pragma|PRAGMA)[:\s]?\s*(?:no|NO)\s*(?:cover|COVER)\s*\((.*)\)') """ @@ -53,17 +55,16 @@ where ``XXX`` is an expression to be evaluated to determine whether the line should be excluded from coverage. -.. versionadded:: 0.2.3 +.. versionadded:: 0.2.4 """ +@functools.lru_cache() def evaluate_exclude(expression: str) -> bool: """ Evaluate the given expression to determine whether the line should be excluded from coverage. - .. versionadded:: 0.2.3 - - | + .. versionadded:: 0.2.4 :param expression: """ @@ -71,18 +72,19 @@ def evaluate_exclude(expression: str) -> bool: return all(list(GRAMMAR.parseString(expression.lower(), parseAll=True))) -class PythonParser(coverage.python.PythonParser): # noqa: D102 +class PythonParser(coverage.python.PythonParser): - def lines_matching(self, *regexes): # noqa: D102 + def lines_matching(self, *regexes) -> Set[int]: # pragma: no cover (py311+) # TODO: why? combined = join_regex([*regexes, *DEFAULT_EXCLUDE]) regex_c = re.compile(combined) matches = set() + exclude = DSL_EXCLUDE - for idx, ltext in enumerate(self.lines, start=1): + for idx, ltext in enumerate(self.text.split('\n'), start=1): - dsl_m = DSL_EXCLUDE.match(ltext) + dsl_m = exclude.match(ltext) # Check if it matches the DSL regex: if dsl_m: @@ -100,5 +102,5 @@ def lines_matching(self, *regexes): # noqa: D102 return matches -def coverage_init(*args, **kwargs): - coverage.python.PythonParser.lines_matching = PythonParser.lines_matching +def coverage_init(*args, **kwargs) -> None: + coverage.python.PythonParser.lines_matching = PythonParser.lines_matching # type: ignore[assignment] diff --git a/coverage_pyver_pragma/grammar.py b/coverage_pyver_pragma/grammar.py index 4405283..0f827ae 100644 --- a/coverage_pyver_pragma/grammar.py +++ b/coverage_pyver_pragma/grammar.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # # grammar.py -""" +r""" .. versionadded:: 0.2.0 As with ``coverage.py``, lines are marked with comments in the form:: @@ -16,14 +16,15 @@ (:py:data:`VERSION_TAG`, :py:data:`PLATFORM_TAG` or :py:data:`IMPLEMENTATION_TAG`). The tags can be joined with the keywords ``AND``, ``OR`` and ``NOT``, with the exclamation mark ``!`` implying ``NOT``. Parentheses can be used to group sub expressions. -A series of tags without keywords in between them are evaluated with ``AND``. +A series of tags without keywords between them are evaluated with ``AND``. .. py:data:: VERSION_TAG A ``VERSION_TAG`` comprises an optional comparator (one of ``<=``, ``<``, ``>=``, ``>``), a version specifier in the form ``pyXX``, and an optional ``+`` to indicate ``>=``. -**Examples:** + +:bold-title:`Example:` .. parsed-literal:: @@ -39,7 +40,8 @@ A ``PLATFORM_TAG`` comprises a single word which will be compared (ignoring case) with the output of :func:`platform.system`. -**Examples:** + +:bold-title:`Example:` .. parsed-literal:: @@ -50,13 +52,17 @@ If the current platform cannot be determined all strings are treated as :py:obj:`True`. +.. raw:: latex + + \clearpage .. py:data:: IMPLEMENTATION_TAG An ``IMPLEMENTATION_TAG`` comprises a single word which will be compared (ignoring case) with the output of :func:`platform.python_implementation`. -**Examples:** + +:bold-title:`Example:` .. parsed-literal:: @@ -65,14 +71,15 @@ IronPython Jython + Examples ----------- -ignore if the Python version is less than or equal to 3.7:: +Ignore if the Python version is less than or equal to 3.7:: # pragma: no cover (<=py37) -ignore if running on Python 3.9:: +Ignore if running on Python 3.9:: # pragma: no cover (py39) @@ -92,9 +99,18 @@ # pragma: no cover (!CPython) +.. raw:: latex + + \clearpage + API Reference ---------------- +.. automodulesumm:: coverage_pyver_pragma.grammar + +.. autovariable:: GRAMMAR + :no-value: + """ # noqa: D400 # # Copyright © 2021 Dominic Davis-Foster @@ -119,6 +135,7 @@ # # stdlib +import os import platform import sys @@ -126,7 +143,7 @@ import packaging.specifiers from domdf_python_tools.doctools import prettify_docstrings from domdf_python_tools.stringlist import DelimitedList -from pyparsing import ( # type: ignore +from pyparsing import ( CaselessKeyword, CaselessLiteral, Combine, @@ -143,7 +160,7 @@ opAssoc ) -__all__ = [ +__all__ = ( "ImplementationTag", "LogicalAND", "LogicalNOT", @@ -155,14 +172,20 @@ "PLATFORM_TAG", "IMPLEMENTATION_TAG", "GRAMMAR", - ] + ) # This ensures coverage.py records the correct coverage for these modules # when they are under test -for module in [m for m in sys.modules if m.startswith("domdf_python_tools")]: +# pylint: disable=loop-global-usage,dotted-import-in-loop +for module in [m for m in sys.modules if m.startswith("domdf_python_tools")]: # pragma: no cover (macOS) if module in sys.modules: del sys.modules[module] +# pylint: enable=loop-global-usage,dotted-import-in-loop + +PYTHON_VERSION = os.environ.get("COV_PYTHON_VERSION", '.'.join(platform.python_version_tuple()[:2])) +PLATFORM = os.environ.get("COV_PLATFORM", platform.system()).casefold() +PYTHON_IMPLEMENTATION = os.environ.get("COV_PYTHON_IMPLEMENTATION", platform.python_implementation()).casefold() @prettify_docstrings @@ -173,7 +196,7 @@ class VersionTag(packaging.specifiers.SpecifierSet): A ``VERSION_TAG`` comprises an optional comparator (one of ``<=``, ``<``, ``>=``, ``>``), a version specifier in the form ``pyXX``, and an optional ``+`` to indicate ``>=``. - **Examples:** + :bold-title:`Examples:` .. parsed-literal:: @@ -208,8 +231,7 @@ def __repr__(self) -> str: # pragma: no cover return f"<{self.__class__.__name__}({str(self)!r})>" def __bool__(self) -> bool: - current_version = '.'.join(platform.python_version_tuple()[:2]) - return current_version in self + return PYTHON_VERSION in self @prettify_docstrings @@ -220,7 +242,7 @@ class PlatformTag(str): A ``PLATFORM_TAG`` comprises a single word which will be compared (ignoring case) with the output of :func:`platform.system`. - **Examples:** + :bold-title:`Examples:` .. parsed-literal:: @@ -229,6 +251,8 @@ class PlatformTag(str): Darwin # macOS Java + .. latex:clearpage:: + If the current platform cannot be determined all strings are treated as :py:obj:`True`. :param tokens: @@ -236,19 +260,17 @@ class PlatformTag(str): __slots__ = () - def __new__(cls, tokens: ParseResults): # noqa: D102 + def __new__(cls, tokens: ParseResults) -> "PlatformTag": # noqa: D102 return super().__new__(cls, str(tokens["platform"])) def __repr__(self) -> str: # pragma: no cover return f"<{self.__class__.__name__}({str(self)!r})>" def __bool__(self) -> bool: - current_platform = platform.system().casefold() - - if not current_platform: # pragma: no cover + if not PLATFORM: # pragma: no cover return True - return current_platform == self.casefold() + return PLATFORM == self.casefold() @prettify_docstrings @@ -259,7 +281,7 @@ class ImplementationTag(str): An ``IMPLEMENTATION_TAG`` comprises a single word which will be compared (ignoring case) with the output of :func:`platform.python_implementation`. - **Examples:** + :bold-title:`Examples:` .. parsed-literal:: @@ -269,18 +291,20 @@ class ImplementationTag(str): Jython :param tokens: + + .. latex:vspace:: -10px """ __slots__ = () - def __new__(cls, tokens: ParseResults): # noqa: D102 + def __new__(cls, tokens: ParseResults) -> "ImplementationTag": # noqa: D102 return super().__new__(cls, str(tokens["implementation"])) def __repr__(self) -> str: # pragma: no cover return f"<{self.__class__.__name__}({str(self)!r})>" def __bool__(self) -> bool: - return platform.python_implementation().casefold() == self.casefold() + return PYTHON_IMPLEMENTATION == self.casefold() @prettify_docstrings @@ -294,10 +318,10 @@ class LogicalOp: def __init__(self, tokens: ParseResults): self.tokens = DelimitedList(tokens[0]) - def __format__(self, format_spec): + def __format__(self, format_spec: str) -> str: return self.tokens.__format__(format_spec) - def __getitem__(self, item): + def __getitem__(self, item): # noqa: MAN001,MAN002 return self.tokens[item] def __str__(self) -> str: @@ -315,7 +339,7 @@ class LogicalAND(LogicalOp): :param tokens: """ - def __bool__(self): + def __bool__(self) -> bool: return bool(self[0]) and bool(self[2]) @@ -327,7 +351,7 @@ class LogicalOR(LogicalOp): :param tokens: """ - def __bool__(self): + def __bool__(self) -> bool: return bool(self[0]) or bool(self[2]) @@ -339,7 +363,7 @@ class LogicalNOT(LogicalOp): :param tokens: """ - def __bool__(self): + def __bool__(self) -> bool: return not bool(self[1]) @@ -358,7 +382,7 @@ def __bool__(self): GREATER_THAN_EQUAL = ">=" GREATER_THAN = '>' -OPS = [LESS_THAN, LESS_THAN_EQUAL, GREATER_THAN, GREATER_THAN_EQUAL] +OPS = [LESS_THAN, LESS_THAN_EQUAL, GREATER_THAN, GREATER_THAN_EQUAL] # pylint: disable=use-tuple-over-list COMPARATOR = Optional(oneOf(' '.join(OPS))).setResultsName("comparator") VERSION = Combine(CaselessLiteral("py") + Word(nums)).setResultsName("version") @@ -400,7 +424,7 @@ def __bool__(self): ) ) """ -The ``coverage_pyver_pragma`` expression grammar. +The :mod:`coverage_pyver_pragma` expression grammar. This can be used to parse an expression outside of the coverage context. """ diff --git a/doc-source/Source.rst b/doc-source/Source.rst index 4fa5ebb..8ff7dc4 100644 --- a/doc-source/Source.rst +++ b/doc-source/Source.rst @@ -3,28 +3,31 @@ Downloading source code ========================= The ``coverage_pyver_pragma`` source code is available on GitHub, -and can be accessed from the following URL: https://github.com/domdfcoding/coverage_pyver_pragma +and can be accessed from the following URL: https://github.com/python-coincidence/coverage_pyver_pragma If you have ``git`` installed, you can clone the repository with the following command: -.. code-block:: bash +.. prompt:: bash + + git clone https://github.com/python-coincidence/coverage_pyver_pragma + +.. parsed-literal:: - $ git clone https://github.com/domdfcoding/coverage_pyver_pragma" - > Cloning into 'coverage_pyver_pragma'... - > remote: Enumerating objects: 47, done. - > remote: Counting objects: 100% (47/47), done. - > remote: Compressing objects: 100% (41/41), done. - > remote: Total 173 (delta 16), reused 17 (delta 6), pack-reused 126 - > Receiving objects: 100% (173/173), 126.56 KiB | 678.00 KiB/s, done. - > Resolving deltas: 100% (66/66), done. + Cloning into 'coverage_pyver_pragma'... + remote: Enumerating objects: 47, done. + remote: Counting objects: 100% (47/47), done. + remote: Compressing objects: 100% (41/41), done. + remote: Total 173 (delta 16), reused 17 (delta 6), pack-reused 126 + Receiving objects: 100% (173/173), 126.56 KiB | 678.00 KiB/s, done. + Resolving deltas: 100% (66/66), done. | Alternatively, the code can be downloaded in a 'zip' file by clicking: | :guilabel:`Clone or download` --> :guilabel:`Download Zip` .. figure:: git_download.png - :alt: Downloading a 'zip' file of the source code. + :alt: Downloading a 'zip' file of the source code. - Downloading a 'zip' file of the source code + Downloading a 'zip' file of the source code Building from source diff --git a/doc-source/_static/style.css b/doc-source/_static/style.css index 13dc6b0..a6b8e4d 100644 --- a/doc-source/_static/style.css +++ b/doc-source/_static/style.css @@ -1,6 +1,19 @@ /* This file is managed by 'repo_helper'. Don't edit it directly. */ div.highlight { - -moz-tab-size: 4; /* Firefox */ - tab-size: 4; + -moz-tab-size: 4; + tab-size: 4; +} + +.field-list dt, dl.simple dt { + margin-top: 0.5rem; +} + +div.versionchanged ul, div.versionremoved ul { + margin-left: 20px; + margin-top: 0; +} + +.longtable.autosummary { + width: 100%; } diff --git a/doc-source/_templates/sidebar/navigation.html b/doc-source/_templates/sidebar/navigation.html deleted file mode 100644 index cd29152..0000000 --- a/doc-source/_templates/sidebar/navigation.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/doc-source/api.rst b/doc-source/api.rst index f4ed53a..8635d9c 100644 --- a/doc-source/api.rst +++ b/doc-source/api.rst @@ -2,4 +2,6 @@ Public API ============= +.. autosummary-widths:: 6/16 + .. automodule:: coverage_pyver_pragma diff --git a/doc-source/conf.py b/doc-source/conf.py index 890b38a..d903695 100644 --- a/doc-source/conf.py +++ b/doc-source/conf.py @@ -7,57 +7,28 @@ import re import sys -sys.path.append(os.path.abspath('.')) -sys.path.append(os.path.abspath("..")) +# 3rd party +from sphinx_pyproject import SphinxConfig -# this package -from __pkginfo__ import __version__ +sys.path.append('.') -github_username = "domdfcoding" -github_repository = "coverage_pyver_pragma" -github_url = f"https://github.com/{github_username}/{github_repository}" +config = SphinxConfig(globalns=globals()) +project = config["project"] +author = config["author"] +documentation_summary = config.description + +github_url = "https://github.com/{github_username}/{github_repository}".format_map(config) rst_prolog = f""".. |pkgname| replace:: coverage_pyver_pragma .. |pkgname2| replace:: ``coverage_pyver_pragma`` .. |browse_github| replace:: `Browse the GitHub Repository <{github_url}>`__ """ -author = "Dominic Davis-Foster" -project = "coverage_pyver_pragma" slug = re.sub(r'\W+', '-', project.lower()) -release = version = __version__ -copyright = "2020-2021 Dominic Davis-Foster" # pylint: disable=redefined-builtin -language = "en" -package_root = "coverage_pyver_pragma" - -extensions = [ - "sphinx_toolbox", - "sphinx_toolbox.more_autodoc", - "sphinx_toolbox.more_autosummary", - "sphinx_toolbox.tweaks.param_dash", - "sphinx.ext.intersphinx", - "sphinx.ext.mathjax", - "sphinxcontrib.httpdomain", - "sphinxcontrib.extras_require", - "sphinx.ext.todo", - "sphinxemoji.sphinxemoji", - "notfound.extension", - "sphinx_copybutton", - "sphinxcontrib.default_values", - "sphinxcontrib.toctree_plus", - "seed_intersphinx_mapping", - ] - -sphinxemoji_style = "twemoji" -todo_include_todos = bool(os.environ.get("SHOW_TODOS", 0)) -gitstamp_fmt = "%d %b %Y" - -templates_path = ["_templates"] -html_static_path = ["_static"] -source_suffix = ".rst" -master_doc = "index" -suppress_warnings = ["image.nonlocal_uri"] -pygments_style = "default" +release = version = config.version + +sphinx_builder = os.environ.get("SPHINX_BUILDER", "html").lower() +todo_include_todos = int(os.environ.get("SHOW_TODOS", 0)) and sphinx_builder != "latex" intersphinx_mapping = { "python": ("https://docs.python.org/3/", None), @@ -65,7 +36,6 @@ "pyparsing": ("https://pyparsing-docs.readthedocs.io/en/latest", None), } -html_theme = "furo" html_theme_options = { "light_css_variables": { "toc-title-font-size": "12pt", @@ -78,8 +48,6 @@ "admonition-font-size": "12pt", }, } -html_theme_path = ["../.."] -html_show_sourcelink = True # True will show link to source html_context = {} htmlhelp_basename = slug @@ -88,51 +56,55 @@ man_pages = [("index", slug, project, [author], 1)] texinfo_documents = [("index", slug, project, author, slug, project, "Miscellaneous")] -toctree_plus_types = { - "class", - "function", - "method", - "data", - "enum", - "flag", - "confval", - "directive", - "role", - "confval", - "protocol", - "typeddict", - "namedtuple", - "exception", - } +toctree_plus_types = set(config["toctree_plus_types"]) -add_module_names = False -hide_none_rtype = True -all_typevars = True -overloads_location = "bottom" - - -autodoc_exclude_members = [ # Exclude "standard" methods. - "__dict__", - "__class__", - "__dir__", - "__weakref__", - "__module__", - "__annotations__", - "__orig_bases__", - "__parameters__", - "__subclasshook__", - "__init_subclass__", - "__attrs_attrs__", - "__init__", - "__new__", - "__getnewargs__", - "__abstractmethods__", - "__hash__", - ] autodoc_default_options = { "members": None, # Include all members (methods). "special-members": None, "autosummary": None, "show-inheritance": None, - "exclude-members": ','.join(autodoc_exclude_members), + "exclude-members": ','.join(config["autodoc_exclude_members"]), } + +latex_elements = { + "printindex": "\\begin{flushleft}\n\\printindex\n\\end{flushleft}", + "tableofcontents": "\\pdfbookmark[0]{\\contentsname}{toc}\\sphinxtableofcontents", + } + + +# Fix for pathlib issue with sphinxemoji on Python 3.9 and Sphinx 4.x +def copy_asset_files(app, exc): + # 3rd party + from domdf_python_tools.compat import importlib_resources + from sphinx.util.fileutil import copy_asset + + if exc: + return + + asset_files = ["twemoji.js", "twemoji.css"] + for path in asset_files: + path_str = os.fspath(importlib_resources.files("sphinxemoji") / path) + copy_asset(path_str, os.path.join(app.outdir, "_static")) + + +def setup(app): + # 3rd party + from sphinx_toolbox.latex import better_header_layout + from sphinxemoji import sphinxemoji + + app.connect("config-inited", lambda app, config: better_header_layout(config)) + app.connect("build-finished", copy_asset_files) + app.add_js_file("https://unpkg.com/twemoji@latest/dist/twemoji.min.js") + app.add_js_file("twemoji.js") + app.add_css_file("twemoji.css") + app.add_transform(sphinxemoji.EmojiSubstitutions) + + +toctree_plus_types.add("envvar") +needspace_amount = r"5\baselineskip" +favicons = [{ + "rel": "icon", + "href": "https://python-coincidence.github.io/assets/coincidence.ico", + "sizes": "48x48", + "type": "image/vnd.microsoft.icon" + }] diff --git a/doc-source/configuration.rst b/doc-source/configuration.rst new file mode 100644 index 0000000..1ed71ee --- /dev/null +++ b/doc-source/configuration.rst @@ -0,0 +1,64 @@ +================= +Configuration +================= + +.. versionadded:: 0.3.0 + +When using Coverage.py's `reporting commands `_ +it may be desirable to generate a report for a different Python version / implementation / platform to the current one. +For instance, you are generating a report from a ``.coverage`` file produced on PyPy 3.6 on Windows, but you are running CPython 3.8 on Linux. + +``coverage_pyver_pragma`` provides three environment variables which can be used to set the target version and platform. + +.. envvar:: COV_PYTHON_VERSION + + Sets the Python version. Must be in the form :file:`{}.{}`. + + Defaults to the output of :func:`'.'.join(platform.python_version_tuple()[:2]) `. + + :bold-title:`Example:` + + .. prompt:: bash + + COV_PYTHON_VERSION=3.6 coverage report + +.. envvar:: COV_PLATFORM + + Sets the Python platform. + Must be a string which matches the output of :func:`platform.system` on the desired platform. + + Defaults to the output of :func:`platform.system`. + + :bold-title:`Example:` + + .. prompt:: bash + + COV_PLATFORM=Windows coverage report + +.. envvar:: COV_PYTHON_IMPLEMENTATION + + Sets the Python implementation. + Must be a string which matches the output of + :func:`platform.python_implementation` with the desired implementation. + + Defaults to the output of :func:`platform.python_implementation`. + + :bold-title:`Example:` + + .. prompt:: bash + + COV_PYTHON_IMPLEMENTATION=PyPy coverage report + +.. latex:clearpage:: + +If you generate your coverage reports through `tox `_ +you should configure `passenv `_ +to ensure the environment variables are passed through: + +.. code-block:: ini + + [testenv] + passenv = + COV_PYTHON_VERSION + COV_PLATFORM + COV_PYTHON_IMPLEMENTATION diff --git a/doc-source/contributing.rst b/doc-source/contributing.rst deleted file mode 100644 index 07d071a..0000000 --- a/doc-source/contributing.rst +++ /dev/null @@ -1,72 +0,0 @@ -Overview ---------- - -.. This file based on https://github.com/PyGithub/PyGithub/blob/master/CONTRIBUTING.md - -``coverage_pyver_pragma`` uses `tox `_ to automate testing and packaging, -and `pre-commit `_ to maintain code quality. - -Install ``pre-commit`` with ``pip`` and install the git hook: - -.. prompt:: bash - - python -m pip install pre-commit - pre-commit install - - -Coding style --------------- - -`formate `_ is used for code formatting. - -It can be run manually via ``pre-commit``: - -.. prompt:: bash - - pre-commit run formate -a - - -Or, to run the complete autoformatting suite: - -.. prompt:: bash - - pre-commit run -a - - -Automated tests -------------------- - -Tests are run with ``tox`` and ``pytest``. -To run tests for a specific Python version, such as Python 3.6: - -.. prompt:: bash - - tox -e py36 - - -To run tests for all Python versions, simply run: - -.. prompt:: bash - - tox - - -Type Annotations -------------------- - -Type annotations are checked using ``mypy``. Run ``mypy`` using ``tox``: - -.. prompt:: bash - - tox -e mypy - - - -Build documentation locally ------------------------------- - -The documentation is powered by Sphinx. A local copy of the documentation can be built with ``tox``: - -.. prompt:: bash - - tox -e docs diff --git a/doc-source/index.rst b/doc-source/index.rst index 59731bf..491a8bc 100644 --- a/doc-source/index.rst +++ b/doc-source/index.rst @@ -4,137 +4,132 @@ coverage_pyver_pragma .. start short_desc -**Plugin for Coverage.py to selectively ignore branches depending on the Python version.** +.. documentation-summary:: + :meta: .. end short_desc .. start shields -.. list-table:: - :stub-columns: 1 - :widths: 10 90 - - * - Docs - - |docs| |docs_check| - * - Tests - - |actions_linux| |actions_windows| |actions_macos| |coveralls| - * - PyPI - - |pypi-version| |supported-versions| |supported-implementations| |wheel| - * - Anaconda - - |conda-version| |conda-platform| - * - Activity - - |commits-latest| |commits-since| |maintained| |pypi-downloads| - * - QA - - |codefactor| |actions_flake8| |actions_mypy| |pre_commit_ci| - * - Other - - |license| |language| |requires| - -.. |docs| rtfd-shield:: - :project: coverage_pyver_pragma - :alt: Documentation Build Status - -.. |docs_check| actions-shield:: - :workflow: Docs Check - :alt: Docs Check Status - -.. |actions_linux| actions-shield:: - :workflow: Linux - :alt: Linux Test Status - -.. |actions_windows| actions-shield:: - :workflow: Windows - :alt: Windows Test Status - -.. |actions_macos| actions-shield:: - :workflow: macOS - :alt: macOS Test Status - -.. |actions_flake8| actions-shield:: - :workflow: Flake8 - :alt: Flake8 Status - -.. |actions_mypy| actions-shield:: - :workflow: mypy - :alt: mypy status - -.. |requires| requires-io-shield:: - :alt: Requirements Status - -.. |coveralls| coveralls-shield:: - :alt: Coverage - -.. |codefactor| codefactor-shield:: - :alt: CodeFactor Grade - -.. |pypi-version| pypi-shield:: - :project: coverage_pyver_pragma - :version: - :alt: PyPI - Package Version - -.. |supported-versions| pypi-shield:: - :project: coverage_pyver_pragma - :py-versions: - :alt: PyPI - Supported Python Versions - -.. |supported-implementations| pypi-shield:: - :project: coverage_pyver_pragma - :implementations: - :alt: PyPI - Supported Implementations - -.. |wheel| pypi-shield:: - :project: coverage_pyver_pragma - :wheel: - :alt: PyPI - Wheel - -.. |conda-version| image:: https://img.shields.io/conda/v/domdfcoding/coverage_pyver_pragma?logo=anaconda - :target: https://anaconda.org/domdfcoding/coverage_pyver_pragma - :alt: Conda - Package Version - -.. |conda-platform| image:: https://img.shields.io/conda/pn/domdfcoding/coverage_pyver_pragma?label=conda%7Cplatform - :target: https://anaconda.org/domdfcoding/coverage_pyver_pragma - :alt: Conda - Platform - -.. |license| github-shield:: - :license: - :alt: License - -.. |language| github-shield:: - :top-language: - :alt: GitHub top language - -.. |commits-since| github-shield:: - :commits-since: v0.2.3 - :alt: GitHub commits since tagged version - -.. |commits-latest| github-shield:: - :last-commit: - :alt: GitHub last commit - -.. |maintained| maintained-shield:: 2021 - :alt: Maintenance - -.. |pypi-downloads| pypi-shield:: - :project: coverage_pyver_pragma - :downloads: month - :alt: PyPI - Downloads - -.. |pre_commit_ci| pre-commit-ci-shield:: - :alt: pre-commit.ci status +.. only:: html + + .. list-table:: + :stub-columns: 1 + :widths: 10 90 + + * - Docs + - |docs| |docs_check| + * - Tests + - |actions_linux| |actions_windows| |actions_macos| |coveralls| + * - PyPI + - |pypi-version| |supported-versions| |supported-implementations| |wheel| + * - Anaconda + - |conda-version| |conda-platform| + * - Activity + - |commits-latest| |commits-since| |maintained| |pypi-downloads| + * - QA + - |codefactor| |actions_flake8| |actions_mypy| + * - Other + - |license| |language| |requires| + + .. |docs| rtfd-shield:: + :project: coverage-pyver-pragma + :alt: Documentation Build Status + + .. |docs_check| actions-shield:: + :workflow: Docs Check + :alt: Docs Check Status + + .. |actions_linux| actions-shield:: + :workflow: Linux + :alt: Linux Test Status + + .. |actions_windows| actions-shield:: + :workflow: Windows + :alt: Windows Test Status + + .. |actions_macos| actions-shield:: + :workflow: macOS + :alt: macOS Test Status + + .. |actions_flake8| actions-shield:: + :workflow: Flake8 + :alt: Flake8 Status + + .. |actions_mypy| actions-shield:: + :workflow: mypy + :alt: mypy status + + .. |requires| image:: https://dependency-dash.repo-helper.uk/github/python-coincidence/coverage_pyver_pragma/badge.svg + :target: https://dependency-dash.repo-helper.uk/github/python-coincidence/coverage_pyver_pragma/ + :alt: Requirements Status + + .. |coveralls| coveralls-shield:: + :alt: Coverage + + .. |codefactor| codefactor-shield:: + :alt: CodeFactor Grade + + .. |pypi-version| pypi-shield:: + :project: coverage_pyver_pragma + :version: + :alt: PyPI - Package Version + + .. |supported-versions| pypi-shield:: + :project: coverage_pyver_pragma + :py-versions: + :alt: PyPI - Supported Python Versions + + .. |supported-implementations| pypi-shield:: + :project: coverage_pyver_pragma + :implementations: + :alt: PyPI - Supported Implementations + + .. |wheel| pypi-shield:: + :project: coverage_pyver_pragma + :wheel: + :alt: PyPI - Wheel + + .. |conda-version| image:: https://img.shields.io/conda/v/domdfcoding/coverage_pyver_pragma?logo=anaconda + :target: https://anaconda.org/domdfcoding/coverage_pyver_pragma + :alt: Conda - Package Version + + .. |conda-platform| image:: https://img.shields.io/conda/pn/domdfcoding/coverage_pyver_pragma?label=conda%7Cplatform + :target: https://anaconda.org/domdfcoding/coverage_pyver_pragma + :alt: Conda - Platform + + .. |license| github-shield:: + :license: + :alt: License + + .. |language| github-shield:: + :top-language: + :alt: GitHub top language + + .. |commits-since| github-shield:: + :commits-since: v0.3.3 + :alt: GitHub commits since tagged version + + .. |commits-latest| github-shield:: + :last-commit: + :alt: GitHub last commit + + .. |maintained| maintained-shield:: 2025 + :alt: Maintenance + + .. |pypi-downloads| pypi-shield:: + :project: coverage_pyver_pragma + :downloads: month + :alt: PyPI - Downloads .. end shields -Installation ---------------- -.. start installation +Contents +---------- -.. installation:: coverage_pyver_pragma - :pypi: - :github: - :anaconda: - :conda-channels: conda-forge, domdfcoding +.. html-section:: -.. end installation .. toctree:: :hidden: @@ -143,23 +138,28 @@ Installation .. toctree:: :maxdepth: 3 - :caption: Documentation installation + configuration syntax api + Source + license -.. toctree:: - :maxdepth: 3 - :caption: Contributing +.. sidebar-links:: + :caption: Links + :github: + :pypi: coverage_pyver_pragma + + Contributing Guide - contributing - Source .. start links -View the :ref:`Function Index ` or browse the `Source Code <_modules/index.html>`__. +.. only:: html + + View the :ref:`Function Index ` or browse the `Source Code <_modules/index.html>`__. -`Browse the GitHub Repository `__ + :github:repo:`Browse the GitHub Repository ` .. end links diff --git a/doc-source/installation.rst b/doc-source/installation.rst index 714ec52..05c86ed 100644 --- a/doc-source/installation.rst +++ b/doc-source/installation.rst @@ -8,6 +8,11 @@ Installation :anaconda: :conda-channels: domdfcoding, conda-forge +.. raw:: latex + + \bigskip\bigskip\hrule\bigskip + + Then enable the plugin in your coverage configuration. The ``.coveragerc`` file in the repository root should contain the following options: diff --git a/doc-source/license.rst b/doc-source/license.rst new file mode 100644 index 0000000..a32aee3 --- /dev/null +++ b/doc-source/license.rst @@ -0,0 +1,10 @@ +========= +License +========= + +``coverage_pyver_pragma`` is licensed under the :choosealicense:`MIT` + +.. license-info:: MIT + +.. license:: + :py: coverage_pyver_pragma diff --git a/doc-source/requirements.txt b/doc-source/requirements.txt index 475aa77..f0a827f 100644 --- a/doc-source/requirements.txt +++ b/doc-source/requirements.txt @@ -1,14 +1,22 @@ -autodocsumm>=0.2.0 -default-values>=0.4.2 -extras-require>=0.2.0 -furo>=2020.11.19b18 -seed-intersphinx-mapping>=0.3.1 -sphinx<3.4.0,>=3.0.3 +default-values>=0.6.0 +extras-require>=0.5.0 +furo==2021.06.18b36 +html-section>=0.3.0 +seed-intersphinx-mapping>=1.2.2 +sphinx>=3.0.3 sphinx-copybutton>=0.2.12 -sphinx-notfound-page>=0.5 -sphinx-prompt>=1.1.0 -sphinx-tabs>=1.1.13 -sphinx-toolbox>=1.8.3 +sphinx-debuginfo>=0.2.2 +sphinx-favicon>=0.2 +sphinx-licenseinfo>=0.3.1 +sphinx-notfound-page>=0.7.1 +sphinx-pyproject>=0.1.0 +sphinx-toolbox>=3.5.0 +sphinxcontrib-applehelp==1.0.4 +sphinxcontrib-devhelp==1.0.2 +sphinxcontrib-htmlhelp==2.0.1 sphinxcontrib-httpdomain>=1.7.0 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==1.0.3 +sphinxcontrib-serializinghtml==1.1.5 sphinxemoji>=0.1.6 -toctree-plus>=0.1.0 +toctree-plus>=0.6.1 diff --git a/doc-source/syntax.rst b/doc-source/syntax.rst index 4db9263..1d17b1e 100644 --- a/doc-source/syntax.rst +++ b/doc-source/syntax.rst @@ -2,4 +2,8 @@ Syntax ========= +.. autosummary-widths:: 6/16 + .. automodule:: coverage_pyver_pragma.grammar + :no-autosummary: + :exclude-members: GRAMMAR diff --git a/formate.toml b/formate.toml index d07dfb5..be43e95 100644 --- a/formate.toml +++ b/formate.toml @@ -6,21 +6,17 @@ noqa-reformat = 60 ellipsis-reformat = 70 squish_stubs = 80 -[config] -indent = "\t" -line_length = 115 - [hooks.yapf] priority = 30 -[hooks.isort] -priority = 50 - [hooks.yapf.kwargs] yapf_style = ".style.yapf" +[hooks.isort] +priority = 50 + [hooks.isort.kwargs] -indent = "\t\t" +indent = " " multi_line_output = 8 import_heading_stdlib = "stdlib" import_heading_thirdparty = "3rd party" @@ -32,9 +28,11 @@ use_parentheses = true remove_redundant_aliases = true default_section = "THIRDPARTY" known_third_party = [ + "backports_entry_points_selectable", "coincidence", "coverage", "domdf_python_tools", + "importlib_metadata", "packaging", "pyparsing", "pytest", @@ -43,4 +41,8 @@ known_third_party = [ "pytest_rerunfailures", "pytest_timeout", ] -known_first_party = "coverage_pyver_pragma" +known_first_party = [ "coverage_pyver_pragma",] + +[config] +indent = " " +line_length = 115 diff --git a/justfile b/justfile new file mode 100644 index 0000000..e8ed871 --- /dev/null +++ b/justfile @@ -0,0 +1,22 @@ +default: lint + +pdf-docs: latex-docs + make -C doc-source/build/latex/ + +latex-docs: + SPHINX_BUILDER=latex tox -e docs + +unused-imports: + tox -e lint -- --select F401 + +incomplete-defs: + tox -e lint -- --select MAN + +vdiff: + git diff $(repo-helper show version -q)..HEAD + +bare-ignore: + greppy '# type:? *ignore(?!\[|\w)' -s + +lint: unused-imports incomplete-defs bare-ignore + tox -n qa diff --git a/pyproject.toml b/pyproject.toml index db64b30..1598e18 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,23 +4,24 @@ build-backend = "whey" [project] name = "coverage_pyver_pragma" -version = "0.2.3" +version = "0.3.3" description = "Plugin for Coverage.py to selectively ignore branches depending on the Python version." readme = "README.rst" -keywords = [] +keywords = [ "coverage",] dynamic = [ "requires-python", "classifiers", "dependencies",] -[[project.authors]] -email = "dominic@davis-foster.co.uk" -name = "Dominic Davis-Foster" [project.license] file = "LICENSE" +[[project.authors]] +name = "Dominic Davis-Foster" +email = "dominic@davis-foster.co.uk" + [project.urls] -Homepage = "https://github.com/domdfcoding/coverage_pyver_pragma" -"Issue Tracker" = "https://github.com/domdfcoding/coverage_pyver_pragma/issues" -"Source Code" = "https://github.com/domdfcoding/coverage_pyver_pragma" -Documentation = "https://coverage_pyver_pragma.readthedocs.io/en/latest" +Homepage = "https://github.com/python-coincidence/coverage_pyver_pragma" +"Issue Tracker" = "https://github.com/python-coincidence/coverage_pyver_pragma/issues" +"Source Code" = "https://github.com/python-coincidence/coverage_pyver_pragma" +Documentation = "https://coverage-pyver-pragma.readthedocs.io/en/latest" [tool.whey] base-classifiers = [ @@ -29,7 +30,122 @@ base-classifiers = [ "Topic :: Utilities", "Typing :: Typed", ] -python-versions = [ "3.6", "3.7", "3.8", "3.9",] +python-versions = [ "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13",] python-implementations = [ "CPython", "PyPy",] platforms = [ "Windows", "macOS", "Linux",] license-key = "MIT" + +[tool.mkrecipe] +extras = "all" +conda-channels = [ "conda-forge", "domdfcoding",] + +[tool.sphinx-pyproject] +github_username = "python-coincidence" +github_repository = "coverage_pyver_pragma" +author = "Dominic Davis-Foster" +project = "coverage-pyver-pragma" +copyright = "2020-2021 Dominic Davis-Foster" +language = "en" +package_root = "coverage_pyver_pragma" +extensions = [ + "sphinx_toolbox", + "sphinx_toolbox.more_autodoc", + "sphinx_toolbox.more_autosummary", + "sphinx_toolbox.documentation_summary", + "sphinx_toolbox.tweaks.param_dash", + "sphinxcontrib.toctree_plus", + "sphinx_toolbox.tweaks.latex_layout", + "sphinx_toolbox.tweaks.latex_toc", + "sphinx.ext.intersphinx", + "sphinx.ext.mathjax", + "sphinxcontrib.extras_require", + "sphinx.ext.todo", + "notfound.extension", + "sphinx_copybutton", + "sphinxcontrib.default_values", + "sphinx_debuginfo", + "sphinx_licenseinfo", + "seed_intersphinx_mapping", + "html_section", + "sphinx_toolbox.more_autosummary.column_widths", + "sphinx_favicon", +] +gitstamp_fmt = "%d %b %Y" +templates_path = [ "_templates",] +html_static_path = [ "_static",] +source_suffix = ".rst" +master_doc = "index" +suppress_warnings = [ "image.nonlocal_uri",] +pygments_style = "default" +html_theme = "furo" +html_theme_path = [ "../..",] +html_show_sourcelink = true +toctree_plus_types = [ + "class", + "confval", + "data", + "directive", + "enum", + "exception", + "flag", + "function", + "namedtuple", + "protocol", + "role", + "typeddict", +] +add_module_names = false +hide_none_rtype = true +all_typevars = true +overloads_location = "bottom" +html_codeblock_linenos_style = "table" +autodoc_exclude_members = [ + "__dict__", + "__class__", + "__dir__", + "__weakref__", + "__module__", + "__annotations__", + "__orig_bases__", + "__parameters__", + "__subclasshook__", + "__init_subclass__", + "__attrs_attrs__", + "__init__", + "__new__", + "__getnewargs__", + "__abstractmethods__", + "__hash__", +] + +[tool.mypy] +python_version = "3.9" +namespace_packages = true +check_untyped_defs = true +warn_unused_ignores = true +no_implicit_optional = true +show_error_codes = true + +[tool.snippet-fmt] +directives = [ "code-block",] + +[tool.snippet-fmt.languages.python] +reformat = true + +[tool.snippet-fmt.languages.TOML] +reformat = true + +[tool.snippet-fmt.languages.ini] + +[tool.snippet-fmt.languages.json] + +[tool.dependency-dash."requirements.txt"] +order = 10 + +[tool.dependency-dash."tests/requirements.txt"] +order = 20 +include = false + +[tool.dependency-dash."doc-source/requirements.txt"] +order = 30 +include = false diff --git a/repo_helper.yml b/repo_helper.yml index 49f7119..7894840 100644 --- a/repo_helper.yml +++ b/repo_helper.yml @@ -3,31 +3,38 @@ repo_name: coverage_pyver_pragma copyright_years: "2020-2021" author: "Dominic Davis-Foster" email: "dominic@davis-foster.co.uk" -version: "0.2.3" -username: "domdfcoding" +version: "0.3.3" +username: "python-coincidence" +assignee: "domdfcoding" +primary_conda_channel: "domdfcoding" license: 'MIT' short_desc: "Plugin for Coverage.py to selectively ignore branches depending on the Python version." use_whey: True min_coverage: 95 sphinx_html_theme: furo +docs_fail_on_warning: true +mypy_version: 1.16 +python_deploy_version: 3.9 conda_channels: - conda-forge -python_deploy_version: 3.6 - # Versions to run tests for python_versions: - - '3.6' - - '3.7' - - "3.8" - - "3.9" - - "3.10-dev" - - pypy36 - - pypy37 - -tests_dir: "tests" + '3.7': + "3.8": + "3.9": + "3.10": + "3.11": + experimental: true + "3.12": + experimental: true + "3.13": + experimental: true + pypy37: + pypy38: + pypy39: classifiers: - 'Development Status :: 4 - Beta' @@ -40,3 +47,18 @@ tox_unmanaged: intersphinx_mapping: - "'pyparsing': ('https://pyparsing-docs.readthedocs.io/en/latest', None)" + +keywords: + - coverage + +extra_sphinx_extensions: + - sphinx_toolbox.more_autosummary.column_widths + - sphinx_favicon + +exclude_files: + - contributing + +sphinx_conf_epilogue: + - toctree_plus_types.add("envvar") + - needspace_amount = r"5\baselineskip" + - 'favicons = [{"rel": "icon", "href": "https://python-coincidence.github.io/assets/coincidence.ico", "sizes": "48x48", "type": "image/vnd.microsoft.icon"}]' diff --git a/requirements.txt b/requirements.txt index d561be8..5d2fbca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ coverage>=5.5 -domdf-python-tools>=2.7.0 +domdf-python-tools>=2.8.0 packaging>=20.9 pyparsing>=2.4.7 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 27320c8..0000000 --- a/setup.cfg +++ /dev/null @@ -1,55 +0,0 @@ -# This file is managed by 'repo_helper'. -# You may add new sections, but any changes made to the following sections will be lost: -# * metadata -# * options -# * options.packages.find -# * mypy -# * options.entry_points - -[metadata] -name = coverage_pyver_pragma -author = Dominic Davis-Foster -author_email = dominic@davis-foster.co.uk -license = MIT License -keywords = -long_description = file: README.rst -long_description_content_type = text/x-rst -platforms = Windows, macOS, Linux -url = https://github.com/domdfcoding/coverage_pyver_pragma -project_urls = - Documentation = https://coverage_pyver_pragma.readthedocs.io/en/latest - Issue Tracker = https://github.com/domdfcoding/coverage_pyver_pragma/issues - Source Code = https://github.com/domdfcoding/coverage_pyver_pragma -classifiers = - Development Status :: 4 - Beta - Intended Audience :: Developers - License :: OSI Approved :: MIT License - Operating System :: OS Independent - Programming Language :: Python - Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Programming Language :: Python :: 3.9 - Programming Language :: Python :: Implementation :: CPython - Programming Language :: Python :: Implementation :: PyPy - Topic :: Utilities - Typing :: Typed - -[options] -python_requires = >=3.6.1 -zip_safe = False -include_package_data = True -packages = find: - -[options.packages.find] -exclude = - doc-source - tests - tests.* - -[mypy] -python_version = 3.6 -namespace_packages = True -check_untyped_defs = True -warn_unused_ignores = True diff --git a/setup.py b/setup.py deleted file mode 100644 index d0e7722..0000000 --- a/setup.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python -# This file is managed by 'repo_helper'. Don't edit it directly. - -# stdlib -import shutil -import sys - -# 3rd party -from setuptools import setup - -sys.path.append('.') - -# this package -from __pkginfo__ import * # pylint: disable=wildcard-import - -setup( - description="Plugin for Coverage.py to selectively ignore branches depending on the Python version.", - extras_require=extras_require, - install_requires=install_requires, - py_modules=[], - version=__version__, - ) - -shutil.rmtree("coverage_pyver_pragma.egg-info", ignore_errors=True) diff --git a/tests/demo_code.py b/tests/demo_code.py index 5289e78..ba59392 100644 --- a/tests/demo_code.py +++ b/tests/demo_code.py @@ -1,4 +1,5 @@ # stdlib +import platform import sys if sys.version_info < (3, 8): # pragma: no cover (py38+) @@ -7,3 +8,9 @@ pass else: # pragma: no cover (=0.1.0 +coincidence>=0.2.0 domdf-python-tools[testing]>=2.0.1 -iniconfig!=1.1.0,>=1.0.1 +importlib-metadata>=3.6.0 pytest>=6.0.0 pytest-cov>=2.8.1 -pytest-randomly>=3.3.1 +pytest-randomly>=3.7.0 pytest-rerunfailures>=9.0 pytest-timeout>=1.4.2 diff --git a/tests/test_grammar.py b/tests/test_grammar.py index fe55004..24496b9 100644 --- a/tests/test_grammar.py +++ b/tests/test_grammar.py @@ -1,11 +1,11 @@ # stdlib import platform import sys -from typing import Tuple +from typing import Tuple, Type # 3rd party import pytest -from pyparsing import ParseBaseException # type: ignore +from pyparsing import ParseBaseException # this package from coverage_pyver_pragma import evaluate_exclude @@ -15,7 +15,7 @@ platforms = {*platforms, *(p.lower() for p in platforms)} versions = [(2, 7)] -versions.extend((3, v) for v in range(11)) +versions.extend((3, v) for v in range(14)) versions.append((4, 0)) versions_before = versions[:versions.index(sys.version_info[:2])] @@ -30,7 +30,11 @@ @pytest.mark.parametrize("implementation", implementations) @pytest.mark.parametrize("plat", platforms) @pytest.mark.parametrize("version", versions_before) -def test_grammar_dont_exclude(version: Tuple[int, int], implementation: str, plat: str): +def test_grammar_dont_exclude( + version: Tuple[int, int], + implementation: str, + plat: str, + ) -> None: assert not evaluate_exclude(f" None: assert evaluate_exclude(f"<=py{version[0]}{version[1]} and {platform.python_implementation()}") assert evaluate_exclude(f"<=py{version[0]}{version[1]} or {implementation}") @@ -59,7 +67,7 @@ def test_grammar_exclude(version: Tuple[int, int], implementation: str, plat: st assert evaluate_exclude(f"<=py{version[0]}{version[1]} or !{implementation} and {platform.system()}") -def test_grammar_current_platform_etc(): +def test_grammar_current_platform_etc() -> None: version = sys.version_info assert evaluate_exclude(f"py{version[0]}{version[1]}") assert evaluate_exclude(f"<=py{version[0]}{version[1]}") @@ -80,13 +88,20 @@ def test_grammar_current_platform_etc(): assert evaluate_exclude(f"{platform.system()}") -@pytest.mark.parametrize("expression", [ - "36", - "36 and", - "py36 and", - "windows and", - "!bpython and pypy", - ]) -def test_bad_grammar(expression: str): - with pytest.raises(ParseBaseException): +@pytest.mark.parametrize( + "expression, exception", + [ + ("36", ParseBaseException), + ("36 and", ParseBaseException), + ("py36 and", ParseBaseException), + ("windows and", ParseBaseException), + ("!bpython and pypy", ParseBaseException), + (" None: + with pytest.raises(exception): evaluate_exclude(expression) + + +# TODO: tests for LogicalOp classes diff --git a/tests/test_plugin.py b/tests/test_plugin.py index afec1d9..9138582 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -3,11 +3,11 @@ from io import StringIO # 3rd party -import coverage # type: ignore +import coverage import pytest -from coincidence import only_version +from coincidence import min_version, only_version from coincidence.regressions import check_file_regression -from coverage.python import PythonParser # type: ignore +from coverage.python import PythonParser from domdf_python_tools.paths import PathPlus from pytest_regressions.file_regression import FileRegressionFixture @@ -22,10 +22,14 @@ pytest.param("3.7", marks=only_version(3.7, "Output differs on each version.")), pytest.param("3.8", marks=only_version(3.8, "Output differs on each version.")), pytest.param("3.9", marks=only_version(3.9, "Output differs on each version.")), - pytest.param("3.10", marks=only_version("3.10", "Output differs on each version.")), + pytest.param("3.10", marks=min_version("3.10", "Output differs on each version.")), ] ) -def test_plugin(tmp_pathplus: PathPlus, file_regression: FileRegressionFixture, version): +def test_plugin( + tmp_pathplus: PathPlus, + file_regression: FileRegressionFixture, + version: str, + ) -> None: coverage_pyver_pragma.coverage_init() assert PythonParser.lines_matching is coverage_pyver_pragma.PythonParser.lines_matching diff --git a/tests/test_plugin_/test_plugin_3_10_.txt b/tests/test_plugin_/test_plugin_3_10_.txt index 8d99077..1d9bcb8 100644 --- a/tests/test_plugin_/test_plugin_3_10_.txt +++ b/tests/test_plugin_/test_plugin_3_10_.txt @@ -1,5 +1,5 @@ -Name Stmts Miss Cover ----------------------------------------- -tests/demo_code.py 2 0 100% ----------------------------------------- -TOTAL 2 0 100% +Name Stmts Miss Cover Missing +-------------------------------------------------- +tests/demo_code.py 3 0 100% +-------------------------------------------------- +TOTAL 3 0 100% diff --git a/tests/test_plugin_/test_plugin_3_6_.txt b/tests/test_plugin_/test_plugin_3_6_.txt index cb891a7..38b012e 100644 --- a/tests/test_plugin_/test_plugin_3_6_.txt +++ b/tests/test_plugin_/test_plugin_3_6_.txt @@ -1,5 +1,5 @@ -Name Stmts Miss Cover ----------------------------------------- -tests/demo_code.py 3 0 100% ----------------------------------------- -TOTAL 3 0 100% +Name Stmts Miss Cover Missing +-------------------------------------------------- +tests/demo_code.py 4 0 100% +-------------------------------------------------- +TOTAL 4 0 100% diff --git a/tests/test_plugin_/test_plugin_3_7_.txt b/tests/test_plugin_/test_plugin_3_7_.txt index cb891a7..38b012e 100644 --- a/tests/test_plugin_/test_plugin_3_7_.txt +++ b/tests/test_plugin_/test_plugin_3_7_.txt @@ -1,5 +1,5 @@ -Name Stmts Miss Cover ----------------------------------------- -tests/demo_code.py 3 0 100% ----------------------------------------- -TOTAL 3 0 100% +Name Stmts Miss Cover Missing +-------------------------------------------------- +tests/demo_code.py 4 0 100% +-------------------------------------------------- +TOTAL 4 0 100% diff --git a/tests/test_plugin_/test_plugin_3_8_.txt b/tests/test_plugin_/test_plugin_3_8_.txt index 8d99077..770dfbc 100644 --- a/tests/test_plugin_/test_plugin_3_8_.txt +++ b/tests/test_plugin_/test_plugin_3_8_.txt @@ -1,5 +1,5 @@ -Name Stmts Miss Cover ----------------------------------------- +Name Stmts Miss Cover Missing +-------------------------------------------------- tests/demo_code.py 2 0 100% ----------------------------------------- +-------------------------------------------------- TOTAL 2 0 100% diff --git a/tests/test_plugin_/test_plugin_3_9_.txt b/tests/test_plugin_/test_plugin_3_9_.txt index 99b2a17..38b012e 100644 --- a/tests/test_plugin_/test_plugin_3_9_.txt +++ b/tests/test_plugin_/test_plugin_3_9_.txt @@ -1,5 +1,5 @@ -Name Stmts Miss Cover ----------------------------------------- +Name Stmts Miss Cover Missing +-------------------------------------------------- tests/demo_code.py 4 0 100% ----------------------------------------- +-------------------------------------------------- TOTAL 4 0 100% diff --git a/tox.ini b/tox.ini index ed83765..16f3cee 100644 --- a/tox.ini +++ b/tox.ini @@ -3,9 +3,15 @@ # * tox # * envlists # * testenv +# * testenv:.package +# * testenv:py313-dev +# * testenv:py313 +# * testenv:py312-dev +# * testenv:py312 # * testenv:docs # * testenv:build # * testenv:lint +# * testenv:perflint # * testenv:mypy # * testenv:pyup # * flake8 @@ -14,85 +20,136 @@ # * pytest [tox] -envlist = py36, py37, py38, py39, py310-dev, pypy36, pypy37, mypy, build +envlist = + py37 + py38 + py39 + py310 + py311 + py312 + py313 + pypy37 + pypy38 + pypy39 + mypy + build skip_missing_interpreters = True isolated_build = True requires = - pip>=20.3.3 + pip>=21,!=22.2 tox-envlist>=0.2.1 - tox-pip-version>=0.0.7 + tox~=3.0 + virtualenv!=20.16.0 [envlists] -test = py36, py37, py38, py39, py310-dev, pypy36, pypy37 +test = py37, py38, py39, py310, py311, py312, py313, pypy37, pypy38, pypy39 qa = mypy, lint -cov = py36, coverage +cov = py39, coverage [testenv] -setenv = PYTHONDEVMODE = 1 +setenv = + PYTHONDEVMODE=1 + PIP_DISABLE_PIP_VERSION_CHECK=1 + SETUPTOOLS_USE_DISTUTILS=stdlib deps = -r{toxinidir}/tests/requirements.txt commands = python --version python -m pytest --cov=coverage_pyver_pragma -r aR tests/ {posargs} +[testenv:.package] +setenv = + PYTHONDEVMODE=1 + PIP_DISABLE_PIP_VERSION_CHECK=1 + +[testenv:py313] +download = True +setenv = + PYTHONDEVMODE=1 + PIP_DISABLE_PIP_VERSION_CHECK=1 + UNSAFE_PYO3_SKIP_VERSION_CHECK=1 + +[testenv:py312] +download = True +setenv = + PYTHONDEVMODE=1 + PIP_DISABLE_PIP_VERSION_CHECK=1 + [testenv:docs] setenv = SHOW_TODOS = 1 +passenv = SPHINX_BUILDER basepython = python3.8 -pip_version = pip>=21 changedir = {toxinidir}/doc-source deps = -r{toxinidir}/doc-source/requirements.txt -commands = sphinx-build -M html . ./build {posargs} +commands = sphinx-build -M {env:SPHINX_BUILDER:html} . ./build {posargs} [testenv:build] +setenv = + PYTHONDEVMODE=1 + PIP_DISABLE_PIP_VERSION_CHECK=1 + PIP_PREFER_BINARY=1 + UNSAFE_PYO3_SKIP_VERSION_CHECK=1 skip_install = True changedir = {toxinidir} deps = - virtualenv - git+https://github.com/pypa/build + build[virtualenv]>=0.3.1 check-wheel-contents>=0.1.0 twine>=3.2.0 + cryptography<40; implementation_name == "pypy" and python_version <= "3.7" commands = python -m build --sdist --wheel "{toxinidir}" twine check dist/*.tar.gz dist/*.whl check-wheel-contents dist/ [testenv:lint] -basepython = python3.6 +basepython = python3.9 changedir = {toxinidir} ignore_errors = True skip_install = True deps = - flake8 >=3.8.2 - flake8-2020 >= 1.6.0 + flake8>=3.8.2,<5 + flake8-2020>=1.6.0 flake8-builtins>=1.5.3 flake8-docstrings>=1.5.0 flake8-dunder-all>=0.1.1 + flake8-encodings>=0.1.0 flake8-github-actions>=0.1.0 - flake8-pyi>=20.10.0 - flake8-pytest-style>=1.3.0 + flake8-noqa>=1.1.0,<=1.2.2 + flake8-pyi>=20.10.0,<=22.8.0 + flake8-pytest-style>=1.3.0,<2 + flake8-quotes>=3.3.0 + flake8-slots>=0.1.0 flake8-sphinx-links>=0.0.4 flake8-strftime>=0.1.1 flake8-typing-imports>=1.10.0 - flake8-encodings>=0.1.0 - flake8-slots>=0.1.0 - git+https://github.com/PyCQA/pydocstyle@5118faa7173b0e5bbc230c4adf628758e13605bf - git+https://github.com/domdfcoding/flake8-quotes.git - git+https://github.com/domdfcoding/flake8-rst-docstrings.git git+https://github.com/domdfcoding/flake8-rst-docstrings-sphinx.git + git+https://github.com/domdfcoding/flake8-rst-docstrings.git + git+https://github.com/python-formate/flake8-unused-arguments.git@magic-methods + git+https://github.com/python-formate/flake8-missing-annotations.git + git+https://github.com/domdfcoding/pydocstyle.git@stub-functions pygments>=2.7.1 + importlib_metadata<4.5.0; python_version<'3.8' commands = python3 -m flake8_rst_docstrings_sphinx coverage_pyver_pragma tests --allow-toolbox {posargs} +[testenv:perflint] +basepython = python3.9 +changedir = {toxinidir} +ignore_errors = True +skip_install = True +deps = perflint +commands = python3 -m perflint coverage_pyver_pragma {posargs} + [testenv:mypy] -basepython = python3.6 +basepython = python3.9 ignore_errors = True changedir = {toxinidir} deps = - mypy==0.800 + mypy==1.16 -r{toxinidir}/tests/requirements.txt -r{toxinidir}/stubs.txt commands = mypy coverage_pyver_pragma tests {posargs} [testenv:pyup] -basepython = python3.6 +basepython = python3.9 skip_install = True ignore_errors = True changedir = {toxinidir} @@ -101,12 +158,16 @@ commands = pyup_dirs coverage_pyver_pragma tests --py36-plus --recursive [flake8] max-line-length = 120 -select = E111 E112 E113 E121 E122 E125 E127 E128 E129 E131 E133 E201 E202 E203 E211 E222 E223 E224 E225 E225 E226 E227 E228 E231 E241 E242 E251 E261 E262 E265 E271 E272 E303 E304 E306 E402 E502 E703 E711 E712 E713 E714 E721 W291 W292 W293 W391 W504 YTT101 YTT102 YTT103 YTT201 YTT202 YTT203 YTT204 YTT301 YTT302 YTT303 STRFTIME001 STRFTIME002 SXL001 PT001 PT002 PT003 PT005 PT006 PT007 PT008 PT009 PT010 PT011 PT012 PT013 PT014 PT015 PT016 PT017 PT018 PT019 PT020 PT021 RST201 RST202 RST203 RST204 RST205 RST206 RST207 RST208 RST210 RST211 RST212 RST213 RST214 RST215 RST216 RST217 RST218 RST219 RST299 RST301 RST302 RST303 RST304 RST305 RST306 RST399 RST401 RST499 RST900 RST901 RST902 RST903 Q001 Q002 Q003 A001 A002 A003 TYP001 TYP002 TYP003 TYP004 TYP005 TYP006 ENC001 ENC002 ENC003 ENC004 Y001,Y002 Y003 Y004 Y005 Y006 Y007 Y008 Y009 Y010 Y011 Y012 Y013 Y014 Y015 Y090 Y091 E301 E302 E305 D100 D101 D102 D103 D104 D106 D201 D204 D207 D208 D209 D210 D211 D212 D213 D214 D215 D300 D301 D400 D402 D403 D404 D415 D417 DALL000 SLOT000 SLOT001 SLOT002 +select = E111 E112 E113 E121 E122 E125 E127 E128 E129 E131 E133 E201 E202 E203 E211 E222 E223 E224 E225 E225 E226 E227 E228 E231 E241 E242 E251 E261 E262 E265 E271 E272 E303 E304 E306 E402 E502 E703 E711 E712 E713 E714 E721 W291 W292 W293 W391 W504 YTT101 YTT102 YTT103 YTT201 YTT202 YTT203 YTT204 YTT301 YTT302 YTT303 STRFTIME001 STRFTIME002 SXL001 PT001 PT002 PT003 PT006 PT007 PT008 PT009 PT010 PT011 PT012 PT013 PT014 PT015 PT016 PT017 PT018 PT019 PT020 PT021 RST201 RST202 RST203 RST204 RST205 RST206 RST207 RST208 RST210 RST211 RST212 RST213 RST214 RST215 RST216 RST217 RST218 RST219 RST299 RST301 RST302 RST303 RST304 RST305 RST306 RST399 RST401 RST499 RST900 RST901 RST902 RST903 Q001 Q002 Q003 A001 A002 TYP001 TYP002 TYP003 TYP004 TYP005 TYP006 ENC001 ENC002 ENC003 ENC004 ENC011 ENC012 ENC021 ENC022 ENC023 ENC024 ENC025 ENC026 Y001,Y002 Y003 Y004 Y005 Y006 Y007 Y008 Y009 Y010 Y011 Y012 Y013 Y014 Y015 Y090 Y091 NQA001 NQA002 NQA003 NQA004 NQA005 NQA102 NQA103 E301 E302 E305 D100 D101 D102 D103 D104 D106 D201 D204 D207 D208 D209 D210 D211 D212 D213 D214 D215 D300 D301 D400 D402 D403 D404 D415 D417 DALL000 SLOT000 SLOT001 SLOT002 extend-exclude = doc-source,old,build,dist,__pkginfo__.py,setup.py,venv rst-directives = TODO + autovariable envvar extras-require + license + license-info +rst-roles = choosealicense per-file-ignores = tests/*: D100 D101 D102 D103 D104 D106 D201 D204 D207 D208 D209 D210 D211 D212 D213 D214 D215 D300 D301 D400 D402 D403 D404 D415 D417 DALL000 SLOT000 SLOT001 SLOT002 */*.pyi: E301 E302 E305 D100 D101 D102 D103 D104 D106 D201 D204 D207 D208 D209 D210 D211 D212 D213 D214 D215 D300 D301 D400 D402 D403 D404 D415 D417 DALL000 SLOT000 SLOT001 SLOT002 @@ -115,17 +176,26 @@ inline-quotes = " multiline-quotes = """ docstring-quotes = """ count = True +min_python_version = 3.7 +unused-arguments-ignore-abstract-functions = True +unused-arguments-ignore-overload-functions = True +unused-arguments-ignore-magic-methods = True +unused-arguments-ignore-variadic-names = True [coverage:report] fail_under = 95 +show_missing = True exclude_lines = raise AssertionError raise NotImplementedError if 0: if False: - if TYPE_CHECKING: - if typing.TYPE_CHECKING: + if TYPE_CHECKING + if typing.TYPE_CHECKING if __name__ == .__main__.: +omit = */test/* + */.tox/* + */venv/* [check-wheel-contents] ignore = W002 @@ -137,18 +207,16 @@ addopts = --color yes --durations 25 timeout = 300 [testenv:coverage] -basepython = python3.6 +basepython = python3.8 ignore_errors = True whitelist_externals = /bin/bash changedir = {toxinidir} deps = coverage>=5 +passenv = + COV_PYTHON_VERSION + COV_PLATFORM + COV_PYTHON_IMPLEMENTATION commands = /bin/bash -c "rm -rf htmlcov" - coverage html --rc-file cov-report.ini + coverage html --rcfile cov-report.ini /bin/bash -c "DISPLAY=:0 firefox 'htmlcov/index.html'" - -[coverge:report] -omit = - */test/* - */.tox/* - */venv/*