From 03ebaa089f4181c64cd19c2093ac5a94fa1643a8 Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Sat, 25 Dec 2021 16:09:37 -0500 Subject: [PATCH] Switch out tox for nox It's nicer to work with especially as it uses a bog standard Python file for configuration. Its output is cleaner and it doesn't hide any magic too. Also the mypy cache has been reenabled since it speeds up pre-commit hooks significantly which makes life easier :) Hopefully this makes the initial set up process relatively painfree. --- .github/workflows/doc.yml | 7 +- .github/workflows/fuzz.yml | 5 +- .github/workflows/test.yml | 12 +- .gitignore | 48 ++++-- docs/contributing/the_basics.md | 149 ++++++++++++++---- mypy.ini | 3 - noxfile.py | 100 ++++++++++++ fuzz.py => scripts/fuzz.py | 0 .../requirements.txt | 2 - tox.ini | 64 -------- 10 files changed, 259 insertions(+), 131 deletions(-) create mode 100644 noxfile.py rename fuzz.py => scripts/fuzz.py (100%) rename test_requirements.txt => tests/requirements.txt (83%) delete mode 100644 tox.ini diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 5689d2887c4..6d5e7fe7131 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -25,9 +25,8 @@ jobs: - name: Install dependencies run: | - python -m pip install --upgrade pip setuptools wheel - python -m pip install -e ".[d]" - python -m pip install -r "docs/requirements.txt" + python -m pip install --upgrade pip + python -m pip install --upgrade nox - name: Build documentation - run: sphinx-build -a -b html -W --keep-going docs/ docs/_build + run: nox --force-color -s docs diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 146277a7312..8b6019e00b0 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -28,8 +28,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install --upgrade tox + python -m pip install --upgrade nox - name: Run fuzz tests - run: | - tox -e fuzz + run: nox --force-color -s fuzz diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7ba2a84d049..168c24cbaf1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -26,6 +26,8 @@ jobs: matrix: python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "pypy-3.7"] os: [ubuntu-latest, macOS-latest, windows-latest] + env: + FORCE_COLOR: 1 steps: - uses: actions/checkout@v2 @@ -38,17 +40,15 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install --upgrade tox + python -m pip install --upgrade nox - name: Unit tests if: "!startsWith(matrix.python-version, 'pypy')" - run: | - tox -e ci-py -- -v --color=yes + run: nox -s tests-${{ matrix.python-version }} -- --no-xdist --verbose - - name: Unit tests pypy + - name: Unit tests (pypy) if: "startsWith(matrix.python-version, 'pypy')" - run: | - tox -e ci-pypy3 -- -v --color=yes + run: nox -s tests-pypy3 -- --no-xdist --verbose - name: Publish coverage to Coveralls # If pushed / is a pull request against main repo AND diff --git a/.gitignore b/.gitignore index 249499b135e..0f13e921385 100644 --- a/.gitignore +++ b/.gitignore @@ -1,26 +1,44 @@ -.venv +# Testing, packaging, and documentation artifacts .coverage .coverage.* -_build -.DS_Store -.vscode -docs/_static/pypi.svg -.tox -__pycache__ - -# Packaging artifacts -black.egg-info -black.dist-info +docs/_build/ +docs/build/ build/ dist/ +black.egg-info +black.dist-info/ pip-wheel-metadata/ -.eggs +.eggs/ +wheels/ -src/_black_version.py -.idea +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec +# Virtual environments +env +venv +.env +.venv +.nox +.tox + +# Caches / temporary files +.mypy_cache/ .dmypy.json *.swp .hypothesis/ -venv/ .ipynb_checkpoints/ +__pycache__/ + +# Black autogenerated files +docs/_static/pypi.svg +src/_black_version.py + +# Personal developer files +.vscode/ +.editorconfig +.DS_Store +.idea diff --git a/docs/contributing/the_basics.md b/docs/contributing/the_basics.md index 9325a9e44ed..590ad9dda2d 100644 --- a/docs/contributing/the_basics.md +++ b/docs/contributing/the_basics.md @@ -7,65 +7,141 @@ An overview on contributing to the _Black_ project. Development on the latest version of Python is preferred. As of this writing it's 3.9. You can use any operating system. -Install development dependencies inside a virtual environment of your choice, for -example: +Most development tasks are automated by [nox][nox] which automatically creates virtual +environments and running the right commands. You'll most likely run the test suite, +build docs, etc. using nox. Often, you can run `python -m pip install nox` to install +and use it. + +```{tip} +If you're on Linux or MacOS you might want to use [pipx][pipx] to install nox (and +optionally pre-commit) to avoid interfering with the system Python installation. + +Alternatively install them into the virtual environment you'll be setting up below. +``` + +### Running black from source tree + +To run the `black` executable from your source tree during development, install _Black_ +locally using editable installation (inside a virtual environment). You can then invoke +your local source tree _Black_ normally. + +**Linux / MacOS** ```console $ python3 -m venv .venv $ source .venv/bin/activate -(.venv)$ pip install -r test_requirements.txt -(.venv)$ pip install -e .[d] -(.venv)$ pre-commit install +(.venv)$ pip install -e .[d,jupyter] ``` -Before submitting pull requests, run lints and tests with the following commands from -the root of the black repo: +**Windows** ```console -# Linting -(.venv)$ pre-commit run -a +$ py -m venv .venv +$ .venv\Scripts\activate +(.venv)$ python -m pip install -e .[d,jupyter] +``` + +### Running linters -# Unit tests -(.venv)$ tox -e py +_Black_ uses [pre-commit][pre-commit] to manage linting. It has been configured with a +list of _pre-commit hooks_ that each check a certain aspect of the codebase. -# Optional Fuzz testing -(.venv)$ tox -e fuzz +```console +$ nox -s lint ``` -### News / Changelog Requirement +You can also setup pre-commit to automatically run before committing. First, install +pre-commit similarly to nox and install the Git pre commit hook: -`Black` has CI that will check for an entry corresponding to your PR in `CHANGES.md`. If -you feel this PR does not require a changelog entry please state that in a comment and a -maintainer can add a `skip news` label to make the CI pass. Otherwise, please ensure you -have a line in the following format: +```console +$ python -m pip install pre-commit +$ pre-commit install +``` -```md -- `Black` is now more awesome (#X) +### Running tests + +Before opening a pull request that involves code, please run the test suite to verify +the changes didn't break anything. + +```console +$ nox -s tests-3.9 ``` -Note that X should be your PR number, not issue number! To workout X, please use -[Next PR Number](https://ichard26.github.io/next-pr-number/?owner=psf&name=black). This -is not perfect but saves a lot of release overhead as now the releaser does not need to -go back and workout what to add to the `CHANGES.md` for each release. +The example above runs tests against Python 3.9. You can also use other versions like +`3.7` and `pypy3`. If you don't specify a Python version, nox will look for Python +installations for all the versions _Black_ supports and run the suite for each! -### Style Changes +By default, the test suite is ran with coverage and parallelization enabled, but you can +disable them if they're causing you trouble: + +```console +# to disable parallelization +$ nox -s tests-3.9 -- --no-xdist +# to disable coverage +$ nox -s tests-3.9 -- --no-cov +# to disable both +$ nox -s tests-3.9 -- --no-cov --no-xdist +``` + +If you need to run the test suite manually, install the test dependencies in the virtual +environment you've [previously set up](#running-black-from-source-tree) and then run +pytest: + +**Linux / MacOS** + +```console +(.venv)$ pip install -r tests/requirements.txt +(.venv)$ pytest +``` + +**Windows** + +```console +(.venv)$ python -m pip install -r tests\requirements.txt +(.venv)$ pytest +``` + +### Building documentation + +If you make changes to docs, you can test they still build locally too. + +```console +$ nox -s docs +``` + +If you are making many changes to docs, you may find it helpful to use the `docs-live` +session. Each time you make a change to the docs they're rebuilt and the browser tab +reloads. + +```console +$ nox -s docs-live +``` + +## Style changes If a change would affect the advertised code style, please modify the documentation (The _Black_ code style) to reflect that change. Patches that fix unintended bugs in formatting don't need to be mentioned separately though. If the change is implemented -with the `--preview` flag, please include the change in the future style document -instead and write the changelog entry under a dedicated "Preview changes" heading. +with the `--preview` flag, please include the change in +{doc}`/the_black_code_style/future_style` instead and write the changelog entry under a +dedicated "Preview changes" heading. -### Docs Testing +## Changelog requirement -If you make changes to docs, you can test they still build locally too. +_Black_ has CI that will check for an entry corresponding to your PR in `CHANGES.md`. If +you feel this PR does not require a changelog entry please state that in a comment and a +maintainer can add a `skip news` label to make the CI pass. Otherwise, please ensure you +have a line in the following format: -```console -(.venv)$ pip install -r docs/requirements.txt -(.venv)$ pip install [-e] .[d] -(.venv)$ sphinx-build -a -b html -W docs/ docs/_build/ +```md +- `Black` is now more awesome (#X) ``` +Note that X should be your PR number, not issue number! To workout X, please use +[Next PR Number](https://ichard26.github.io/next-pr-number/?owner=psf&name=black). This +is not perfect but saves a lot of release overhead as now the releaser does not need to +go back and workout what to add to the `CHANGES.md` for each release. + ## Hygiene If you're fixing a bug, add a test. Run it first to confirm it fails, then fix the bug, @@ -77,4 +153,9 @@ any large feature, first open an issue for us to discuss the idea first. ## Finally Thanks again for your interest in improving the project! You're taking action when most -people decide to sit and watch. +people decide to sit and watch. If you ever need help feel free to ask on the relevant +issue or chat with us in the [Python Discord server](https://discord.gg/RtVdv86PrH). + +[nox]: https://nox.thea.codes/en/stable/ +[pipx]: https://pypa.github.io/pipx/ +[pre-commit]: https://pre-commit.com/ diff --git a/mypy.ini b/mypy.ini index cfceaa3ee86..d4b3a239997 100644 --- a/mypy.ini +++ b/mypy.ini @@ -32,9 +32,6 @@ warn_unreachable=True disallow_untyped_defs=True check_untyped_defs=True -# No incremental mode -cache_dir=/dev/null - [mypy-black] # The following is because of `patch_click()`. Remove when # we drop Python 3.6 support. diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 00000000000..f47168c9fa4 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,100 @@ +import shutil +from pathlib import Path +from typing import Union + +import nox + +SUPPORTED_PYTHONS = ["3.6", "3.7", "3.8", "3.9", "3.10", "pypy3"] +THIS_DIR = Path(__file__).parent +TESTS_DIR = THIS_DIR / "tests" +SCRIPTS_DIR = THIS_DIR / "scripts" + +# ============ # +# Utilities +# ============ # + + +def get_flag(session: nox.Session, flag: str) -> bool: + if flag in session.posargs: + index = session.posargs.index(flag) + del session.posargs[index] + return True + + return False + + +def wipe(session: nox.Session, path: Union[str, Path]) -> None: + if isinstance(path, str): + path = Path.cwd() / path + if not path.exists(): + return + + normalized = path.relative_to(Path.cwd()) + if path.is_file(): + session.log(f"Deleting '{normalized}' file") + path.unlink() + elif path.is_dir(): + session.log(f"Deleting '{normalized}' directory") + shutil.rmtree(path) + + +# ============ # +# Sessions +# ============ # + + +@nox.session() +def lint(session: nox.Session) -> None: + session.install("pre-commit>=2.9.2") + session.run("pre-commit", "run", "--all-files", "--show-diff-on-failure") + + +@nox.session(python=SUPPORTED_PYTHONS) +def tests(session: nox.Session) -> None: + coverage = not get_flag(session, "--no-cov") + parallelize = not get_flag(session, "--no-xdist") + + session.install("-r", str(TESTS_DIR / "requirements.txt")) + session.install(".[d]") + base = ["pytest", str(TESTS_DIR), "-Wall", "--strict-config", "--strict-markers"] + if coverage: + session.run("coverage", "erase") + base.extend(("--cov", "--cov-append")) + if parallelize: + base.extend(("--numprocesses", "auto")) + + session.run("python", "-m", "pip", "uninstall", "ipython", "-y") + session.run(*base, "--run-optional=no_jupyter", *session.posargs) + session.install(".[jupyter]") + session.run(*base, "--run-optional=jupyter", "-m", "jupyter", *session.posargs) + if coverage: + session.run("coverage", "report") + + +@nox.session() +def docs(session: nox.Session) -> None: + session.install("-e", ".[d]") + session.cd("docs") + wipe(session, "_build") + session.install("-r", "requirements.txt") + session.run("sphinx-build", ".", "_build", "-E", "-W", "-a", "--keep-going") + + +@nox.session(name="docs-live") +def docs_live(session: nox.Session) -> None: + session.install("-e", ".[d]") + session.cd("docs") + wipe(session, "_build") + session.install("-r", "requirements.txt", "sphinx-autobuild") + session.run( + "sphinx-autobuild", ".", "_build", "--ignore", "**/pypi.svg", *session.posargs + ) + + +@nox.session() +def fuzz(session: nox.Session) -> None: + session.install("-r", str(TESTS_DIR / "requirements.txt"), "hypothesmith") + session.install(".") + session.run("coverage", "erase") + session.run("coverage", "run", str(SCRIPTS_DIR / "fuzz.py")) + session.run("coverage", "report") diff --git a/fuzz.py b/scripts/fuzz.py similarity index 100% rename from fuzz.py rename to scripts/fuzz.py diff --git a/test_requirements.txt b/tests/requirements.txt similarity index 83% rename from test_requirements.txt rename to tests/requirements.txt index 5bc494d5999..e70f0b4dc6d 100644 --- a/test_requirements.txt +++ b/tests/requirements.txt @@ -1,6 +1,4 @@ coverage >= 5.3 -pre-commit pytest >= 6.1.1 pytest-xdist >= 2.2.1 pytest-cov >= 2.11.1 -tox diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 090dc522cad..00000000000 --- a/tox.ini +++ /dev/null @@ -1,64 +0,0 @@ -[tox] -envlist = {,ci-}py{36,37,38,39,310,py3},fuzz - -[testenv] -setenv = PYTHONPATH = {toxinidir}/src -skip_install = True -# We use `recreate=True` because otherwise, on the second run of `tox -e py`, -# the `no_jupyter` tests would run with the jupyter extra dependencies installed. -# See https://github.com/psf/black/issues/2367. -recreate = True -deps = - -r{toxinidir}/test_requirements.txt -; parallelization is disabled on CI because pytest-dev/pytest-xdist#620 occurs too frequently -; local runs can stay parallelized since they aren't rolling the dice so many times as like on CI -commands = - pip install -e .[d] - coverage erase - pytest tests --run-optional no_jupyter \ - !ci: --numprocesses auto \ - --cov {posargs} - pip install -e .[jupyter] - pytest tests --run-optional jupyter \ - -m jupyter \ - !ci: --numprocesses auto \ - --cov --cov-append {posargs} - coverage report - -[testenv:{,ci-}pypy3] -setenv = PYTHONPATH = {toxinidir}/src -skip_install = True -recreate = True -deps = - -r{toxinidir}/test_requirements.txt -; a separate worker is required in ci due to https://foss.heptapod.net/pypy/pypy/-/issues/3317 -; this seems to cause tox to wait forever -; remove this when pypy releases the bugfix -commands = - pip install -e .[d] - coverage erase - pytest tests \ - --run-optional no_jupyter \ - !ci: --numprocesses auto \ - ci: --numprocesses 1 \ - --cov {posargs} - pip install -e .[jupyter] - pytest tests --run-optional jupyter \ - -m jupyter \ - !ci: --numprocesses auto \ - ci: --numprocesses 1 \ - --cov --cov-append {posargs} - coverage report - -[testenv:fuzz] -skip_install = True -deps = - -r{toxinidir}/test_requirements.txt - hypothesmith - lark-parser < 0.10.0 -; lark-parser's version is set due to a bug in hypothesis. Once it solved, that would be fixed. -commands = - pip install -e .[d] - coverage erase - coverage run fuzz.py - coverage report