From f93e1b2e279ec695f05a04c8eefd02f104e2dbbb Mon Sep 17 00:00:00 2001 From: Ivan Carvalho <8753214+IvanIsCoding@users.noreply.github.com> Date: Thu, 28 Mar 2024 13:00:49 -0400 Subject: [PATCH] Replace Tox with Nox (#861) * Use nox * Trying to fix nox * Fix tests * Minor items in lint * More nox details * Update Contributing.md * Add release notes * Add scipy requirement to noxfile * Move flake8 to pyproject.toml (against its will) * Revert RETWORKX_TEST_PRESERVE_IMAGES * Running tox errors * Capitalization * Try to make docs work * Edit error messages for tox * Add constraints to docs install * Include extras appropriately * Add test_with_version * Switch lint to ruff * Port some changes from nox to tox * Remove file that should not be there * Incorporate recent changes into Nox * Fix Noxfile * Revert tox usage * Include Python 3.12 * Faster lint phase * Reuse install code * Restore tox.ini and add print to the end of commands --------- Co-authored-by: Matthew Treinish --- .github/workflows/docs_dev.yml | 2 +- .github/workflows/docs_release.yml | 2 +- .github/workflows/main.yml | 12 +-- .gitignore | 1 + CONTRIBUTING.md | 55 +++++++------ noxfile.py | 78 +++++++++++++++++++ .../notes/swap-nox-tox-dea2bb14c400641c.yaml | 6 ++ tools/build_documentation_dev.sh | 2 +- tools/build_documentation_release.sh | 2 +- tox.ini | 16 +++- 10 files changed, 140 insertions(+), 36 deletions(-) create mode 100644 noxfile.py create mode 100644 releasenotes/notes/swap-nox-tox-dea2bb14c400641c.yaml diff --git a/.github/workflows/docs_dev.yml b/.github/workflows/docs_dev.yml index ded574a4b..a253cc46b 100644 --- a/.github/workflows/docs_dev.yml +++ b/.github/workflows/docs_dev.yml @@ -22,7 +22,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -U virtualenv setuptools wheel tox + pip install -U virtualenv setuptools wheel nox sudo apt-get install graphviz pandoc - name: Build docs run: | diff --git a/.github/workflows/docs_release.yml b/.github/workflows/docs_release.yml index 0b4bca283..843ed6743 100644 --- a/.github/workflows/docs_release.yml +++ b/.github/workflows/docs_release.yml @@ -23,7 +23,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -U virtualenv setuptools wheel tox + pip install -U virtualenv setuptools wheel nox sudo apt-get install graphviz pandoc - name: Build docs run: | diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f9ffd0599..a087276e1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -90,12 +90,12 @@ jobs: toolchain: ${{ matrix.rust }} targets: ${{ matrix.platform.rust-target }} - name: 'Install dependencies' - run: python -m pip install --upgrade tox + run: python -m pip install --upgrade nox - name: 'Install binary dependencies' run: sudo apt-get install -y graphviz if: runner.os == 'Linux' - name: 'Run tests' - run: tox -epy + run: nox -e test tests_stubs: if: github.repository_owner == 'Qiskit' needs: [tests] @@ -114,9 +114,9 @@ jobs: - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: 'Install dependencies' - run: python -m pip install --upgrade tox + run: python -m pip install --upgrade nox - name: 'Run rustworkx stub tests' - run: tox -estubs + run: nox -estubs coverage: if: github.repository_owner == 'Qiskit' needs: [tests] @@ -179,9 +179,9 @@ jobs: - name: Install binary deps run: sudo apt-get install -y graphviz - name: Install deps - run: pip install -U tox + run: pip install -U nox - name: Build Docs - run: tox -edocs + run: nox -e docs - uses: actions/upload-artifact@v4 with: name: html_docs diff --git a/.gitignore b/.gitignore index 8e9676069..6afef31f5 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ docs/apiref/ docs/source/apiref/ docs/source/stubs/ .tox/ +.nox/ retworkx/*.so retworkx/*pyd *.stestr/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c318bb002..5ae80b1d9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -110,28 +110,37 @@ also run successfully. Before you open a new pull request for your change, you'll want to run the test suite locally. The easiest way to run the test suite is to use -[**tox**](https://tox.readthedocs.io/en/latest/#). You can install tox -with pip: `pip install -U tox`. Tox provides several advantages, but the +[**Nox**](https://nox.thea.codes/en/stable/). You can install Nox +with pip: `pip install -U nox`. Nox provides several advantages, but the biggest one is that it builds an isolated virtualenv for running tests. This means it does not pollute your system python when running. However, by default -tox will recompile rustworkx from source every time it is run even if there +Nox will recompile rustworkx from source every time it is run even if there are no changes made to the rust code. To avoid this you can use the -`--skip-pkg-install` package if you'd like to rerun tests without recompiling. -Note, you only want to use this flag if you recently ran tox and there are no +`--no-install` package if you'd like to rerun tests without recompiling. +Note, you only want to use this flag if you recently ran Nox and there are no rust code (or packaged python code) changes to the repo since then. Otherwise -the rustworkx package tox installs in it's virtualenv will be out of date (or +the rustworkx package Nox installs in it's virtualenv will be out of date (or missing). -Note, if you run tests outside of tox that you can **not** run the tests from +Note, if you run tests outside of Nox that you can **not** run the tests from the root of the repo, this is because rustworkx packaging shim will conflict with imports from rustworkx the installed version of rustworkx (which contains the compiled extension). +#### Running tests with a specific Python version + +If you want to run the tests with a specific version of Python, use the `test_with_version` +target. For example, to launch a test with version 3.11 the command is: + +```python +nox --python 3.11 -e test_with_version +``` + #### Running subsets of tests If you just want to run a subset of tests you can pass a selection regex to the test runner. For example, if you want to run all tests that have "dag" in the -test id you can run: `tox -epy -- dag`. You can pass arguments directly to the +test id you can run: `nox -e test -- dag`. You can pass arguments directly to the test runner after the bare `--`. To see all the options on test selection you can refer to the stestr manual: @@ -142,22 +151,22 @@ you can do this faster with the `-n`/`--no-discover` option. For example: to run a module: ``` -tox -epy -- -n test_max_weight_matching +nox -e test -- -n test_max_weight_matching ``` or to run the same module by path: ``` -tox -epy -- -n graph/test_nodes.py +nox -e test -- -n graph/test_nodes.py ``` to run a class: ``` -tox -epy -- -n graph.test_nodes.TestNodes +nox -e test -- -n graph.test_nodes.TestNodes ``` to run a method: ``` -tox -epy -- -n graph.test_nodes.TestNodes.test_no_nodes +nox -e test -- -n graph.test_nodes.TestNodes.test_no_nodes ``` -It's important to note that tox will be running from the `tests/` directory in +It's important to note that Nox will be running from the `tests/` directory in the repo, so any paths you pass to the test runner via path need to be relative to that directory. @@ -165,7 +174,7 @@ to that directory. When running the visualization tests, each test will generate a visualization and only fail if an exception is raised by the call. Each test saves the output -image to the current working directory (which if running tests with `tox` is +image to the current working directory (which if running tests with `nox` is `tests/`) to ensure the generated image is usable. However to not clutter the system each test cleans up this generated image and by default a test run does not include any way to view the images from the visualization tests. @@ -177,7 +186,7 @@ skip the cleanup. This will enable you to look at the output image and ensure th visualization is correct. For example, running: ``` -RUSTWORKX_TEST_PRESERVE_IMAGES=1 tox -epy +RUSTWORKX_TEST_PRESERVE_IMAGES=1 nox -e test ``` will run the visualization tests and preserve the generated image files after @@ -230,25 +239,25 @@ cargo clippy Python is used primarily for tests and some small pieces of packaging and namespace configuration code in the actual library. [black](https://github.com/psf/black) and [flake8](https://flake8.pycqa.org/en/latest/) are used to enforce consistent -style in the python code in the repository. You can run them via tox using: +style in the python code in the repository. You can run them via Nox using: ```bash -tox -elint +nox -e lint ``` This will also run `cargo fmt` in check mode to ensure that you ran `cargo fmt` and will fail if the Rust code doesn't conform to the style rules. -If black returns a code formatting error you can run `tox -eblack` to automatically +If black returns a code formatting error you can run `nox -e black` to automatically update the code formatting to conform to the style. ### Building documentation -Just like with tests building documentation is done via tox. This will handle +Just like with tests building documentation is done via Nox. This will handle compiling rustworkx, installing the python dependencies, and then building the documentation in an isolated venv. You can run just the docs build with: ``` -tox -edocs +nox -e docs ``` which will output the html rendered documentation in `docs/build/html` which you can view locally in a web browser. @@ -291,10 +300,10 @@ Having type annotations is very helpful for Python end-users. Adding annotations lets users type check their code with [mypy](http://mypy-lang.org/), which can be helpful for finding bugs when using rustworkx. -Just like with tests for the code, annotations are also tested via tox. +Just like with tests for the code, annotations are also tested via Nox. ``` -tox -estubs +nox -e stubs ``` One important thing to note is that if you're adding a new function to the Rust @@ -433,7 +442,7 @@ it has been tagged:: Building the release notes is part of the standard rustworkx documentation builds. To check what the rendered html output of the release notes will look -like for the current state of the repo you can run: `tox -edocs` which will +like for the current state of the repo you can run: `nox -e docs` which will build all the documentation into `docs/_build/html` and the release notes in particular will be located at `docs/_build/html/release_notes.html` diff --git a/noxfile.py b/noxfile.py new file mode 100644 index 000000000..5b28b9544 --- /dev/null +++ b/noxfile.py @@ -0,0 +1,78 @@ +import nox + +nox.options.reuse_existing_virtualenvs = True +nox.options.stop_on_first_error = True + +deps = [ + "setuptools-rust", + "fixtures", + "testtools>=2.5.0", + "networkx>=2.5", + "scipy>=1.7", + "stestr>=4.1", +] + +lint_deps = [ + "black~=22.0", + "ruff~=0.1", + "setuptools-rust", +] + +stubs_deps = [ + "mypy==1.8.0", + "typing-extensions", +] + +def install_rustworkx(session): + session.install(*deps) + session.install(".[all]", "-c", "constraints.txt") + +# We define a common base such that -e test triggers a test with the current +# Python version of the interpreter and -e test_with_version launches +# a test with the specified version of Python. +def base_test(session): + install_rustworkx(session) + session.chdir("tests") + session.run("python", "-m", "unittest", "discover", *session.posargs) + +@nox.session(python=["3"]) +def test(session): + base_test(session) + +@nox.session(python=["3.8", "3.9", "3.10", "3.11", "3.12"]) +def test_with_version(session): + base_test(session) + +@nox.session(python=["3"]) +def lint(session): + black(session) + session.install(*lint_deps) + session.run("ruff", "check", "rustworkx", "retworkx", "setup.py") + session.run("cargo", "fmt", "--all", "--", "--check", external=True) + session.run("python", "tools/find_stray_release_notes.py") + +@nox.session(python=["3"]) +def docs(session): + install_rustworkx(session) + session.install("-r", "docs/source/requirements.txt", "-c", "constraints.txt") + session.run("python", "-m", "ipykernel", "install", "--user") + session.run("jupyter", "kernelspec", "list") + session.chdir("docs") + session.run("sphinx-build", "-W", "-d", "build/.doctrees", "-b", "html", "source", "build/html", *session.posargs) + +@nox.session(python=["3"]) +def docs_clean(session): + session.chdir("docs") + session.run("rm", "-rf", "build", "source/apiref", external=True) + +@nox.session(python=["3"]) +def black(session): + session.install(*[d for d in lint_deps if "black" in d]) + session.run("black", "rustworkx", "tests", "retworkx", *session.posargs) + +@nox.session(python=["3"]) +def stubs(session): + install_rustworkx(session) + session.install(*stubs_deps) + session.chdir("tests") + session.run("python", "-m", "mypy.stubtest", "--concise", "rustworkx") diff --git a/releasenotes/notes/swap-nox-tox-dea2bb14c400641c.yaml b/releasenotes/notes/swap-nox-tox-dea2bb14c400641c.yaml new file mode 100644 index 000000000..490e46fc8 --- /dev/null +++ b/releasenotes/notes/swap-nox-tox-dea2bb14c400641c.yaml @@ -0,0 +1,6 @@ +--- +other: + - | + Switched automated testing environment from + Tox to `Nox `__. This + change should not impact the end-user \ No newline at end of file diff --git a/tools/build_documentation_dev.sh b/tools/build_documentation_dev.sh index 49a3572d3..68eca6c34 100755 --- a/tools/build_documentation_dev.sh +++ b/tools/build_documentation_dev.sh @@ -18,7 +18,7 @@ set -e # Build the documentation. -RUSTWORKX_DEV_DOCS=1 tox -edocs +RUSTWORKX_DEV_DOCS=1 nox -e docs # Copy the stable docs from the git repo TMP_DIR=$(mktemp -d) diff --git a/tools/build_documentation_release.sh b/tools/build_documentation_release.sh index 059ba3e91..3bc8b47d6 100755 --- a/tools/build_documentation_release.sh +++ b/tools/build_documentation_release.sh @@ -18,7 +18,7 @@ set -e # Build the documentation. -tox -edocs +nox -edocs # Extract the release version from Cargo.toml VERSION=$(grep -Po -m1 'version = "\K[0-9]+\.[0-9]+' Cargo.toml) diff --git a/tox.ini b/tox.ini index c5318d93b..c417ac0f1 100644 --- a/tox.ini +++ b/tox.ini @@ -28,6 +28,7 @@ passenv = changedir = {toxinidir}/tests commands = python -m unittest discover {posargs} + python -c "print('\nrustworkx no longer supports tox. Please run the equivalent comand with nox:\n\n\tnox -e test\n')" [testenv:lint] basepython = python3 @@ -41,6 +42,8 @@ commands = ruff check ../rustworkx ../retworkx . ../setup.py cargo fmt --all -- --check python {toxinidir}/tools/find_stray_release_notes.py + python -c "print('\nrustworkx no longer supports tox. Please run the equivalent comand with nox:\n\n\tnox -e lint\n')" + [testenv:docs] basepython = python3 @@ -59,19 +62,24 @@ commands = python -m ipykernel install --user jupyter kernelspec list sphinx-build -W -d {toxinidir}/docs/build/.doctrees -b html source build/html {posargs} + python -c "print('\nrustworkx no longer supports tox. Please run the equivalent comand with nox:\n\n\tnox -e docs\n')" [testenv:docs-clean] skip_install = true deps = allowlist_externals = rm -commands = rm -rf {toxinidir}/docs/build {toxinidir}/docs/source/apiref +commands = + rm -rf {toxinidir}/docs/build {toxinidir}/docs/source/apiref + python -c "print('\nrustworkx no longer supports tox. Please run the equivalent comand with nox:\n\n\tnox -e docs_clean\n')" [testenv:black] basepython = python3 skip_install = true deps = black~=22.0 -commands = black {posargs} '../rustworkx' '../tests' '../retworkx' +commands = + black {posargs} '../rustworkx' '../tests' '../retworkx' + python -c "print('\nrustworkx no longer supports tox. Please run the equivalent comand with nox:\n\tnox -e black\n')" [testenv:stubs] basepython = python3 @@ -81,4 +89,6 @@ deps = extras = mpl graphviz -commands = python -m mypy.stubtest --concise rustworkx +commands = + python -m mypy.stubtest --concise rustworkx + python -c "print('\nrustworkx no longer supports tox. Please run the equivalent comand with nox:\n\n\tnox -e stubs\n')"