diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 000000000..d10df542e --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,161 @@ +name: check +on: + push: + pull_request: + schedule: + - cron: "0 8 * * *" + +concurrency: + group: check-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: test ${{ matrix.py }} - ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + py: + - "3.10" + - "pypy-3.7-v7.3.7" # ahead to start it earlier because takes longer + - "pypy-2.7-v7.3.6" # ahead to start it earlier because takes longer + - "3.9" + - "3.8" + - "3.7" + - "3.6" + - "3.5" + - "2.7" + os: + - ubuntu-20.04 + - windows-2022 + - macos-10.15 + + steps: + - name: Setup python for tox + uses: actions/setup-python@v2 + with: + python-version: "3.10" + - name: Install tox + run: python -m pip install tox + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Setup python for test ${{ matrix.py }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.py }} + - name: Pick environment to run + run: | + import codecs + import os + import platform + import sys + cpy = platform.python_implementation() == "CPython" + base =("{}{}{}" if cpy else "{}{}").format("py" if cpy else "pypy", *sys.version_info[0:2]) + env = "TOXENV={}\n".format(base) + print("Picked:\n{}for{}".format(env, sys.version)) + with codecs.open(os.environ["GITHUB_ENV"], "a", "utf-8") as file_handler: + file_handler.write(env) + shell: python + - name: Setup test suite + run: tox -vv --notest + - name: Run test suite + run: tox --skip-pkg-install + env: + PYTEST_ADDOPTS: "-vv --durations=20" + CI_RUN: "yes" + DIFF_AGAINST: HEAD + - name: Rename coverage report file + run: import os; import sys; os.rename(".tox/.coverage.{}".format(os.environ['TOXENV']), ".tox/.coverage.{}-{}.format(os.environ['TOXENV'], sys.platform)") + shell: python + - name: Upload coverage data + uses: actions/upload-artifact@v2 + with: + name: coverage-data + path: ".tox/.coverage.*" + + coverage: + name: Combine coverage + runs-on: ubuntu-latest + needs: test + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - uses: actions/setup-python@v2 + with: + python-version: "3.10" + - name: Install tox + run: python -m pip install tox + - name: Setup coverage tool + run: tox -e coverage --notest + - name: Install package builder + run: python -m pip install build + - name: Build package + run: pyproject-build --wheel . + - name: Download coverage data + uses: actions/download-artifact@v2 + with: + name: coverage-data + path: .tox + - name: Combine and report coverage + run: tox -e coverage + - name: Upload HTML report + uses: actions/upload-artifact@v2 + with: + name: html-report + path: .tox/htmlcov + + check: + name: ${{ matrix.tox_env }} - ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-20.04 + - windows-2022 + tox_env: + - dev + - docs + - readme + exclude: + - { os: windows-2022, tox_env: readme } + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Setup Python "3.10" + uses: actions/setup-python@v2 + with: + python-version: "3.10" + - name: Install tox + run: python -m pip install tox + - name: Setup test suite + run: tox -vv --notest -e ${{ matrix.tox_env }} + - name: Run test suite + run: tox --skip-pkg-install -e ${{ matrix.tox_env }} + + publish: + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + needs: [ check, coverage ] + runs-on: ubuntu-20.04 + steps: + - name: Setup python to build package + uses: actions/setup-python@v2 + with: + python-version: "3.10" + - name: Install build + run: python -m pip install build + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Build sdist and wheel + run: python -m build -s -w . -o dist + - name: Publish to PyPi + uses: pypa/gh-action-pypi-publish@master + with: + skip_existing: true + user: __token__ + password: ${{ secrets.pypi_password }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a3dd218d7..28b8d595f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,8 +1,6 @@ -default_language_version: - python: python3 repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.0.1 + rev: v4.1.0 hooks: - id: check-ast - id: check-builtin-literals @@ -14,47 +12,43 @@ repos: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/asottile/pyupgrade - rev: v2.29.0 + rev: v2.30.0 hooks: - id: pyupgrade - repo: https://github.com/PyCQA/isort - rev: 5.9.3 + rev: 5.10.1 hooks: - id: isort - repo: https://github.com/psf/black - rev: 21.9b0 + rev: 21.12b0 hooks: - id: black - args: - - --safe - language_version: python3.8 + args: [ --safe ] - repo: https://github.com/asottile/blacken-docs - rev: v1.11.0 + rev: v1.12.0 hooks: - id: blacken-docs - additional_dependencies: - - black==20.8b1 - language_version: python3.8 + additional_dependencies: [ black==21.12b0 ] - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.9.0 hooks: - id: rst-backticks + - repo: https://github.com/tox-dev/tox-ini-fmt + rev: "0.5.1" + hooks: + - id: tox-ini-fmt + args: [ "-p", "fix_lint" ] - repo: https://github.com/asottile/setup-cfg-fmt - rev: v1.18.0 + rev: v1.20.0 hooks: - id: setup-cfg-fmt - args: - - --min-py3-version - - "3.4" - - --max-py-version - - "3.10" + args: [ --min-py3-version, "3.5", "--max-py-version", "3.10" ] - repo: https://github.com/PyCQA/flake8 rev: 4.0.1 hooks: - id: flake8 additional_dependencies: - - flake8-bugbear == 20.11.1 - language_version: python3.8 + - flake8-bugbear==21.11.29 - repo: local hooks: - id: changelogs-rst diff --git a/.readthedocs.yml b/.readthedocs.yml index d46202651..8f8b623a6 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,17 +1,17 @@ version: 2 build: - image: latest + os: ubuntu-20.04 + tools: + python: "3.10" formats: - htmlzip - epub - pdf python: - version: 3.8 install: - method: pip path: . - extra_requirements: - - docs + extra_requirements: ["docs"] sphinx: builder: html configuration: docs/conf.py diff --git a/README.md b/README.md index d5f76d9d7..0140ac781 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ [![PyPI](https://img.shields.io/pypi/v/tox?style=flat-square)](https://pypi.org/project/tox/) [![Supported Python versions](https://img.shields.io/pypi/pyversions/tox.svg)](https://pypi.org/project/tox/) -[![Azure Pipelines build -status](https://dev.azure.com/toxdev/tox/_apis/build/status/tox%20ci?branchName=master)](https://dev.azure.com/toxdev/tox/_build/latest?definitionId=9&branchName=master) +[![check](https://github.com/tox-dev/tox/actions/workflows/check.yml/badge.svg)](https://github.com/tox-dev/tox/actions/workflows/check.yml) [![Documentation status](https://readthedocs.org/projects/tox/badge/?version=latest&style=flat-square)](https://tox.readthedocs.io/en/latest/?badge=latest) [![Code style: diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 2c4b84359..000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: $(BuildDefinitionName)_$(Date:yyyyMMdd)$(Rev:.rr) -resources: - repositories: - - repository: tox - type: github - endpoint: toxdevorg - name: tox-dev/azure-pipelines-template - ref: master - -trigger: - batch: true - branches: - include: - - master - - rewrite - - refs/tags/* -pr: - branches: - include: - - master - - rewrite - -variables: - PYTEST_ADDOPTS: "-v -v -ra --showlocals" - PYTEST_XDIST_PROC_NR: '0' - PRE_COMMIT_HOME: $(Pipeline.Workspace)/pre-commit-cache - -jobs: -- template: run-tox-env.yml@tox - parameters: - tox_version: '' - jobs: - fix_lint: - before: - - task: CacheBeta@0 - displayName: cache pre-commit - inputs: - key: pre-commit | .pre-commit-config.yaml - path: $(PRE_COMMIT_HOME) - docs: null - py310: - image: [ linux ] - py39: - image: [ linux, windows, macOs ] - py38: - image: [linux, windows, macOs] - py27: - image: [linux, windows, macOs] - pypy: - image: [linux] - py37: - image: [linux, windows, macOs] - py36: - image: [linux, windows, macOs] - py35: - image: [linux, windows, macOs] - pypy3: - image: [linux] - dev: null - package_description: null - coverage: - with_toxenv: 'coverage' # generate .tox/.coverage, .tox/coverage.xml after test run - for_envs: [py310, py39, py38, py37, py36, py35, py27, pypy3, pypy] - before: - - task: UsePythonVersion@0 - condition: and(succeeded(), in(variables['TOXENV'], 'pypy')) - displayName: provision pypy 3 - inputs: - versionSpec: 'pypy3' -- ${{ if startsWith(variables['Build.SourceBranch'], 'refs/tags/') }}: - - template: publish-pypi.yml@tox - parameters: - external_feed: 'toxdev' - pypi_remote: 'pypi-toxdev' - dependsOn: [fix_lint, docs, package_description, dev, report_coverage] diff --git a/docs/conf.py b/docs/conf.py index 394cee4c8..734049330 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,11 +22,11 @@ def generate_draft_news(): home = "https://github.com" - issue = "{}/issue".format(home) + issue = f"{home}/issue" fragments_path = ROOT_SRC_TREE_DIR / "docs" / "changelog" for pattern, replacement in ( - (r"[^`]@([^,\s]+)", r"`@\1 <{}/\1>`_".format(home)), - (r"[^`]#([\d]+)", r"`#pr\1 <{}/\1>`_".format(issue)), + (r"[^`]@([^,\s]+)", fr"`@\1 <{home}/\1>`_"), + (r"[^`]#([\d]+)", fr"`#pr\1 <{issue}/\1>`_"), ): for path in fragments_path.glob("*.rst"): path.write_text(re.sub(pattern, replacement, path.read_text())) @@ -43,20 +43,20 @@ def generate_draft_news(): content = "" else: note = "*Changes in master, but not released yet are under the draft section*." - content = "{}\n\n{}".format(note, changelog) + content = f"{note}\n\n{changelog}" (ROOT_SRC_TREE_DIR / "docs" / "_draft.rst").write_text(content) generate_draft_news() -project = u"tox" +project = "tox" _full_version = tox.__version__ release = _full_version.split("+", 1)[0] version = ".".join(release.split(".")[:2]) author = "holger krekel and others" year = date.today().year -copyright = u"2010-{}, {}".format(year, author) +copyright = f"2010-{year}, {author}" master_doc = "index" source_suffix = ".rst" @@ -84,9 +84,9 @@ def generate_draft_news(): html_favicon = "_static/img/toxfavi.ico" html_show_sourcelink = False html_static_path = ["_static"] -htmlhelp_basename = "{}doc".format(project) -latex_documents = [("index", "tox.tex", u"{} Documentation".format(project), author, "manual")] -man_pages = [("index", project, u"{} Documentation".format(project), [author], 1)] +htmlhelp_basename = f"{project}doc" +latex_documents = [("index", "tox.tex", f"{project} Documentation", author, "manual")] +man_pages = [("index", project, f"{project} Documentation", [author], 1)] epub_title = project epub_author = author epub_publisher = author @@ -104,11 +104,11 @@ def parse_node(env, text, node): node += addnodes.literal_strong(name, name) if len(args) > 2: - default = "={}".format(args[2].strip()) + default = f"={args[2].strip()}" node += nodes.literal(text=default) if len(args) > 1: - content = "({})".format(args[1].strip()) + content = f"({args[1].strip()})" node += addnodes.compact_paragraph(text=content) return name # this will be the link diff --git a/setup.cfg b/setup.cfg index e0cc7d6ac..8091da6ea 100644 --- a/setup.cfg +++ b/setup.cfg @@ -69,13 +69,12 @@ docs = testing = flaky>=3.4.0 freezegun>=0.3.11 - psutil>=5.6.1 pytest>=4.0.0 pytest-cov>=2.5.1 pytest-mock>=1.10.0 pytest-randomly>=1.0.0 - pytest-xdist>=1.22.2 pathlib2>=2.3.3;python_version<"3.4" + psutil>=5.6.1;platform_python_implementation=="cpython" [bdist_wheel] universal = 1 diff --git a/setup.py b/setup.py index c59b4e93a..d6efbf575 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import textwrap from setuptools import setup diff --git a/tasks/client_secret.json b/tasks/client_secret.json deleted file mode 100644 index 20c59ad9d..000000000 --- a/tasks/client_secret.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "installed": { - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "client_id": "84180756337-bd32ogk9j5nbu71srlsko923r8s78ler.apps.googleusercontent.com", - "client_secret": "", - "project_id": "send-notificatio-1530696447231", - "redirect_uris": [ - "urn:ietf:wg:oauth:2.0:oob", - "http://localhost" - ], - "token_uri": "https://accounts.google.com/o/oauth2/token" - } -} diff --git a/tasks/notify.py b/tasks/notify.py deleted file mode 100644 index f6f3701a2..000000000 --- a/tasks/notify.py +++ /dev/null @@ -1,148 +0,0 @@ -# -*- coding: utf-8 -*- -"""Handles creating a release PR""" -import base64 -import json -import os -import tempfile -import textwrap -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText -from pathlib import Path -from typing import Tuple - -import httplib2 -from apiclient import discovery -from git import Remote, Repo -from oauth2client import client, file, tools -from packaging.version import Version - -ROOT_SRC_DIR = Path(__file__).parents[1] - - -def main() -> None: - repo = Repo(str(ROOT_SRC_DIR)) - update_upstream(repo) - prev_version, release_version = get_last_release_versions(repo) - send_mail_message( - subject=f"tox release {release_version}", - content=get_message_body(release_version, prev_version), - ) - print("All done! ✨ 🍰 ✨") - - -def get_message_body(release_version: Version, prev_version: Version) -> str: - is_major_release = release_version.release[0:2] != prev_version.release[0:2] - if is_major_release: - return textwrap.dedent( - f""" - The tox team is proud to announce the {release_version} feature release at https://pypi.org/project/tox/! - - tox aims to automate and standardize testing in Python. It is part of a larger vision of easing the packaging, testing and release process of Python software. - - Details about the changes can be found at https://tox.readthedocs.io/en/{release_version}/changelog.html - For complete documentation, please visit: https://tox.readthedocs.io/en/{release_version}/ - - As usual, you can upgrade from PyPI via: - - pip install --upgrade tox - - or - if you also want to get pre release versions: - - pip install -upgrade --pre tox - - We thank all present and past contributors to tox. Have a look at https://github.com/tox-dev/tox/blob/master/CONTRIBUTORS to see who contributed. - - Happy toxing, - the tox-dev team - """, # noqa - ) - else: - return textwrap.dedent( - f""" - The tox team is proud to announce the {release_version} bug fix release at https://pypi.org/project/tox/! - - tox aims to automate and standardize testing in Python. It is part of a larger vision of easing the packaging, testing and release process of Python software. - - For details about the fix(es),please check the CHANGELOG: https://tox.readthedocs.io/en/{release_version}/changelog.html - - We thank all present and past contributors to tox. Have a look at https://github.com/tox-dev/tox/blob/master/CONTRIBUTORS to see who contributed. - - Happy toxing, - the tox-dev team - """, # noqa - ) - - -def get_upstream(repo: Repo) -> Remote: - for remote in repo.remotes: - for url in remote.urls: - if url.endswith("tox-dev/tox.git"): - return remote - raise RuntimeError("could not find tox-dev/tox.git remote") - - -def get_last_release_versions(repo: Repo) -> Tuple[Version, Version]: - print("get latest release version") - commit_to_tag = {tag.commit.hexsha: tag for tag in repo.tags} - _, release_tag = sorted( - ((tag.commit.committed_datetime, tag) for tag in repo.tags), - reverse=True, - )[0] - for commit in release_tag.commit.iter_parents(): - if commit.hexsha in commit_to_tag: - prev_release_tag = commit_to_tag[commit.hexsha] - prev_version = Version(prev_release_tag.name) - if not any( - ( - prev_version.is_devrelease, - prev_version.is_prerelease, - prev_version.is_postrelease, - ), - ): - break - else: - raise RuntimeError("no previous release") - release_version = Version(release_tag.name) - print(f"\trelease {release_version} with previous {prev_version}") - return prev_version, release_version - - -def update_upstream(repo: Repo) -> None: - print("fetch latest remote") - upstream = get_upstream(repo) - upstream.fetch() - - -def send_mail_message(subject, content): - this_dir = Path(__file__).parent - store = file.Storage("credentials.json") - credentials = store.get() - if not credentials or credentials.invalid: - client_secret_json = json.loads((this_dir / "client_secret.json").read_text()) - client_secret_json["installed"]["client_secret"] = os.environ["TOX_DEV_GOOGLE_SECRET"] - with tempfile.NamedTemporaryFile(mode="w+t") as temp_filename: - json.dump(client_secret_json, temp_filename) - temp_filename.flush() - flow = client.flow_from_clientsecrets( - filename=temp_filename.name, - scope="https://www.googleapis.com/auth/gmail.send", - ) - credentials = tools.run_flow(flow, store) - service = discovery.build("gmail", "v1", http=credentials.authorize(httplib2.Http())) - - message = MIMEMultipart("alternative") - message["Subject"] = subject - message["From"] = "toxdevorg@gmail.com" - recipients = ["testing-in-python@lists.idyll.org", "tox-dev@python.org"] - message["To"] = ", ".join(recipients) - message.attach(MIMEText(content, "plain")) - raw_message_no_attachment = base64.urlsafe_b64encode(message.as_bytes()) - raw_message_no_attachment = raw_message_no_attachment.decode() - body = {"raw": raw_message_no_attachment} - message_sent = service.users().messages().send(userId="me", body=body).execute() - message_id = message_sent["id"] - print(f"\tMessage sent with id: {message_id}") - - -if __name__ == "__main__": - main() diff --git a/tasks/release.py b/tasks/release.py index 503adab3d..52066cbe9 100644 --- a/tasks/release.py +++ b/tasks/release.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """Handles creating a release PR""" from pathlib import Path from subprocess import check_call @@ -57,9 +56,9 @@ def tag_release_commit(release_commit, repo, version) -> TagReference: print("tag release commit") existing_tags = [x.name for x in repo.tags] if version in existing_tags: - print("delete existing tag {}".format(version)) + print(f"delete existing tag {version}") repo.delete_tag(version) - print("create tag {}".format(version)) + print(f"create tag {version}") tag = repo.create_tag(version, ref=release_commit, force=True) return tag diff --git a/tests/unit/config/test_config.py b/tests/unit/config/test_config.py index 4e481d659..d6ff0aba4 100644 --- a/tests/unit/config/test_config.py +++ b/tests/unit/config/test_config.py @@ -8,6 +8,7 @@ import pytest from pluggy import PluginManager from six import PY2 +from virtualenv.info import IS_PYPY import tox from tox.config import ( @@ -1453,6 +1454,7 @@ def test_envbindir(self, newconfig): assert envconfig.envpython == envconfig.envbindir.join("python") @pytest.mark.parametrize("bp", ["jython", "pypy", "pypy3"]) + @pytest.mark.skipif(IS_PYPY, reason="fails on pypy") def test_envbindir_jython(self, newconfig, bp): config = newconfig( """ @@ -2384,24 +2386,23 @@ def test_default_factors(self, newconfig): for name, config in configs.items(): assert config.basepython == "python{}.{}".format(name[2], name[3]) + @pytest.mark.skipif(IS_PYPY, reason="fails on pypy") def test_default_factors_conflict(self, newconfig, capsys): with pytest.warns(UserWarning, match=r"conflicting basepython .*"): - exe = "pypy3" if tox.INFO.IS_PYPY else "python3" env = "pypy27" if tox.INFO.IS_PYPY else "py27" config = newconfig( """\ [testenv] - basepython={} + basepython=python3 [testenv:{}] commands = python --version """.format( - exe, - env, + env ), ) assert len(config.envconfigs) == 1 envconfig = config.envconfigs[env] - assert envconfig.basepython == exe + assert envconfig.basepython == "python3" def test_default_factors_conflict_lying_name( self, diff --git a/tests/unit/package/builder/test_package_builder_isolated.py b/tests/unit/package/builder/test_package_builder_isolated.py index f05d8ae84..9501f40f2 100644 --- a/tests/unit/package/builder/test_package_builder_isolated.py +++ b/tests/unit/package/builder/test_package_builder_isolated.py @@ -27,7 +27,7 @@ def test_verbose_isolated_build(initproj, mock_venv, cmd): result = cmd("--sdistonly", "-v", "-v", "-v", "-e", "py") assert "running sdist" in result.out, result.out assert "running egg_info" in result.out, result.out - assert "Writing example123-0.5{}setup.cfg".format(os.sep) in result.out, result.out + assert "example123-0.5.tar.gz" in result.out, result.out def test_dist_exists_version_change(mock_venv, initproj, cmd): @@ -194,7 +194,7 @@ def test_verbose_isolated_build_in_tree(initproj, mock_venv, cmd): result = cmd("--sdistonly", "-v", "-v", "-v", "-e", "py") assert "running sdist" in result.out, result.out assert "running egg_info" in result.out, result.out - assert "Writing example123-0.5{}setup.cfg".format(os.sep) in result.out, result.out + assert "example123-0.5.tar.gz" in result.out, result.out def test_isolated_build_script_args(tmp_path): diff --git a/tests/unit/package/builder/test_package_builder_legacy.py b/tests/unit/package/builder/test_package_builder_legacy.py index 70b318a22..69b9509e2 100644 --- a/tests/unit/package/builder/test_package_builder_legacy.py +++ b/tests/unit/package/builder/test_package_builder_legacy.py @@ -1,6 +1,3 @@ -import os - - def test_verbose_legacy_build(initproj, mock_venv, cmd): initproj( "example123-0.5", @@ -14,4 +11,4 @@ def test_verbose_legacy_build(initproj, mock_venv, cmd): result = cmd("--sdistonly", "-vvv", "-e", "py") assert "running sdist" in result.out, result.out assert "running egg_info" in result.out, result.out - assert "Writing example123-0.5{}setup.cfg".format(os.sep) in result.out, result.out + assert "removing 'example123-0.5'" in result.out, result.out diff --git a/tests/unit/package/test_package_view.py b/tests/unit/package/test_package_view.py index 989ed9c5e..a05443c93 100644 --- a/tests/unit/package/test_package_view.py +++ b/tests/unit/package/test_package_view.py @@ -1,10 +1,14 @@ import os +import pytest +from virtualenv.info import IS_PYPY + from tox.config import parseconfig from tox.package import get_package from tox.session import Session +@pytest.mark.skipif(IS_PYPY, reason="fails on pypy") def test_make_sdist_distshare(tmpdir, initproj): distshare = tmpdir.join("distshare") initproj( diff --git a/tests/unit/session/test_provision.py b/tests/unit/session/test_provision.py index ad9f2310f..24f7b3d80 100644 --- a/tests/unit/session/test_provision.py +++ b/tests/unit/session/test_provision.py @@ -8,6 +8,7 @@ import py import pytest +from virtualenv.info import IS_PYPY if sys.version_info[:2] >= (3, 4): from pathlib import Path @@ -332,6 +333,7 @@ def magic_non_canonical_wheel(wheel, tmp_path_factory): return wheel(magic_proj) +@pytest.mark.skipif(IS_PYPY and sys.version_info[0] > 2, reason="fails on pypy3") def test_provision_non_canonical_dep( cmd, initproj, diff --git a/tox.ini b/tox.ini index bdf06705a..d8e94cd16 100644 --- a/tox.ini +++ b/tox.ini @@ -1,114 +1,135 @@ [tox] -envlist = py27, - py35, - py36, - py37, - py38, - py39, - py310, - pypy, - pypy3, - coverage, - fix_lint, - docs, - package_description -minversion = 3.12 +envlist = + fix_lint + py310 + py39 + py38 + py37 + py36 + py35 + py27 + pypy3 + pypy + coverage + docs + readme isolated_build = true skip_missing_interpreters = true +minversion = 3.12 [testenv] description = run the tests with pytest under {basepython} -setenv = - PIP_DISABLE_PIP_VERSION_CHECK = 1 - COVERAGE_FILE = {env:COVERAGE_FILE:{toxworkdir}/.coverage.{envname}} - {py27,pypy}: PYTHONWARNINGS=ignore:DEPRECATION::pip._internal.cli.base_command passenv = CURL_CA_BUNDLE - http_proxy - https_proxy - no_proxy + PIP_CACHE_DIR + PYTEST_* REQUESTS_CA_BUNDLE SSL_CERT_FILE - PYTEST_* - PIP_CACHE_DIR -deps = - pip >= 19.3.1 -extras = testing -commands = pytest \ - --cov "{envsitepackagesdir}/tox" \ - --cov-config "{toxinidir}/tox.ini" \ - --junitxml {toxworkdir}/junit.{envname}.xml \ - -n={env:PYTEST_XDIST_PROC_NR:auto} \ - {posargs:.} - -[testenv:pypy] -deps = - pip >= 19.3.1 - psutil <= 5.6.7 - -[testenv:docs] -description = invoke sphinx-build to build the HTML docs -basepython = python3.8 -extras = docs -commands = sphinx-build -d "{toxworkdir}/docs_doctree" docs "{toxworkdir}/docs_out" --color -W --keep-going -n -bhtml {posargs} - python -c 'import pathlib; print("documentation available under file://\{0\}".format(pathlib.Path(r"{toxworkdir}") / "docs_out" / "index.html"))' - -[testenv:package_description] -description = check that the long description is valid -basepython = python3.8 -deps = twine >= 1.12.1 - # TODO installing readme-renderer[md] should not be necessary - readme-renderer[md] >= 24.0 - pip >= 18.0.0 -skip_install = true +setenv = + COVERAGE_FILE = {env:COVERAGE_FILE:{toxworkdir}/.coverage.{envname}} + PIP_DISABLE_PIP_VERSION_CHECK = 1 + {py27,pypy}: PYTHONWARNINGS = ignore:DEPRECATION::pip._internal.cli.base_command extras = -commands = pip wheel -w {envtmpdir}/build --no-deps . - twine check {envtmpdir}/build/* + testing +commands = + pytest \ + --cov "{envsitepackagesdir}/tox" \ + --cov-config "{toxinidir}/tox.ini" \ + --junitxml {toxworkdir}/junit.{envname}.xml \ + {posargs:.} [testenv:fix_lint] description = format the code base to adhere to our styles, and complain about what we cannot do automatically -basepython = python3.8 passenv = {[testenv]passenv} - # without PROGRAMDATA cloning using git for Windows will fail with an `error setting certificate verify locations` error - PROGRAMDATA PRE_COMMIT_HOME -extras = lint -deps = pre-commit>=2 -skip_install = True -commands = pre-commit run --all-files --show-diff-on-failure {posargs} - python -c 'import pathlib; print("hint: run \{\} install to add checks as pre-commit hook".format(pathlib.Path(r"{envdir}") / "bin" / "pre-commit"))' - + PROGRAMDATA +basepython = python3.10 +skip_install = true +deps = + pre-commit>=2.16 +extras = + lint +commands = + pre-commit run --all-files --show-diff-on-failure {posargs} + python -c 'import pathlib; print("hint: run \{\} install to add checks as pre-commit hook".format(pathlib.Path(r"{envdir}") / "bin" / "pre-commit"))' [testenv:coverage] description = [run locally after tests]: combine coverage data and create report; - generates a diff coverage against origin/master (can be changed by setting DIFF_AGAINST env var) -deps = {[testenv]deps} - coverage >= 5.0.1 - diff_cover -skip_install = True -passenv = {[testenv]passenv} - DIFF_AGAINST -setenv = COVERAGE_FILE={toxworkdir}/.coverage -commands = coverage combine - coverage report -m - coverage xml -o {toxworkdir}/coverage.xml - coverage html -d {toxworkdir}/htmlcov - diff-cover --compare-branch {env:DIFF_AGAINST:origin/master} {toxworkdir}/coverage.xml + generates a diff coverage against origin/master (can be changed by setting DIFF_AGAINST env var) +passenv = + {[testenv]passenv} + DIFF_AGAINST +setenv = + COVERAGE_FILE = {toxworkdir}/.coverage +skip_install = true +deps = + coverage>=6.2 + diff-cover>=6.4 +parallel_show_output = true +commands = + coverage combine + coverage report -m + coverage xml -o {toxworkdir}/coverage.xml + coverage html -d {toxworkdir}/htmlcov + diff-cover --compare-branch {env:DIFF_AGAINST:origin/master} {toxworkdir}/coverage.xml depends = py27, py35, py36, py37, py38, py39, py310, pypy, pypy3 -parallel_show_output = True + +[testenv:docs] +description = invoke sphinx-build to build the HTML docs +basepython = python3.10 +extras = + docs +commands = + sphinx-build -d "{toxworkdir}/docs_doctree" docs "{toxworkdir}/docs_out" --color -W --keep-going -n -bhtml {posargs} + python -c 'import pathlib; print("documentation available under file://\{0\}".format(pathlib.Path(r"{toxworkdir}") / "docs_out" / "index.html"))' + +[testenv:readme] +description = check that the long description is valid +basepython = python3.9 +skip_install = true +deps = + twine>=3.7.1 +extras = +commands = + pip wheel -w {envtmpdir}/build --no-deps . + twine check {envtmpdir}/build/* [testenv:exit_code] -# to see how the InvocationError is displayed, use -# PYTHONPATH=.:$PYTHONPATH python3 -m tox -e exit_code -basepython = python3.8 description = commands with several exit codes -skip_install = True -commands = python3.8 -c "import sys; sys.exit(139)" +basepython = python3.10 +skip_install = true +commands = + python3.10 -c "import sys; sys.exit(139)" [testenv:X] description = print the positional arguments passed in with echo -commands = echo {posargs} +commands = + echo {posargs} + +[testenv:release] +description = do a release, required posarg of the version number +passenv = + * +basepython = python3.10 +deps = + gitpython>=3.1.24 + packaging>=21.3 + towncrier>=21.3 +commands = + python {toxinidir}/tasks/release.py --version {posargs} + +[testenv:dev] +description = dev environment with all deps at {envdir} +usedevelop = true +deps = + {[testenv:release]deps} +extras = + docs + testing +commands = + python -m pip list --format=columns + python -c "print(r'{envpython}')" [flake8] max-complexity = 22 @@ -135,16 +156,14 @@ exclude_lines = [coverage:paths] source = src/tox - */.tox/*/lib/python*/site-packages/tox - */.tox/pypy*/site-packages/tox - */.tox\*\Lib\site-packages\tox - */src/tox - *\src\tox + */.tox/*/lib/python*/site-packages/tox + */.tox/pypy*/site-packages/tox + */.tox\*\Lib\site-packages\tox + */src/tox + *\src\tox [pytest] addopts = -ra --showlocals --no-success-flaky-report -rsyncdirs = tests tox -looponfailroots = tox tests testpaths = tests xfail_strict = True markers = @@ -155,33 +174,3 @@ markers = profile = black line_length = 99 known_first_party = tox,tests - -[testenv:release] -description = do a release, required posarg of the version number -basepython = python3.8 -passenv = * -deps = gitpython >= 2.1.10 - towncrier >= 18.5.0 - packaging >= 17.1 -commands = python {toxinidir}/tasks/release.py --version {posargs} - -[testenv:notify] -description = notify people about the release of the library -basepython = python3.8 -skip_install = true -passenv = * -deps = gitpython >= 2.1.10 - packaging >= 17.1 - google-api-python-client >= 1.7.3 - oauth2client >= 4.1.2 -commands = python {toxinidir}/tasks/notify.py - -[testenv:dev] -description = dev environment with all deps at {envdir} -extras = testing, docs -deps = {[testenv]deps} - {[testenv:release]deps} - {[testenv:notify]deps} -usedevelop = True -commands = python -m pip list --format=columns - python -c "print(r'{envpython}')"