From 7375786a2503e75bbc5bb13562aac92660537d39 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 11 Nov 2026 16:42:32 +0000 Subject: [PATCH 1/7] MAINT: Replace flake8 with ruff ruff already runs pyflakes (F), the pycodestyle errors and warnings that it implements (E, W) and the flake8-bugbear rules (B), and black handles the whitespace checks of pycodestyle. The only check that flake8 added was the 99-character limit on comments, docstrings and long strings, which black cannot shorten. ruff's E501 now enforces the same limit through [tool.ruff.lint.pycodestyle] max-line-length = 99, while black and the rest of ruff keep the 88-character line length. ruff E501 passes on arch at 99 characters. - Remove .flake8 (max-line-length = 99, ignore = E203, W503, BLK100: ruff ignores E203 and does not implement W503, and flake8-black was never used). - Remove the flake8 step from the Lint workflow, and flake8 and flake8-bugbear from the development requirements. --- .flake8 | 4 ---- .github/workflows/lint.yml | 10 +++------- pyproject.toml | 9 +++++---- requirements-dev.txt | 2 -- 4 files changed, 8 insertions(+), 17 deletions(-) delete mode 100644 .flake8 diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 0417842f92..0000000000 --- a/.flake8 +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -# Leave at 99 for now -max-line-length = 99 -ignore = E203,W503,BLK100 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 033cf8ae20..f2ee962d00 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -8,8 +8,8 @@ on: jobs: lint: - # The oldest and the newest supported Python. flake8 and black parse the code with - # the grammar of the Python that runs them. + # The oldest and the newest supported Python. black parses the code with the grammar + # of the Python that runs it. name: Lint, Python ${{ matrix.python-version }} runs-on: ubuntu-latest defaults: @@ -31,15 +31,11 @@ jobs: id: install run: | python -m pip install --upgrade pip - python -m pip install black flake8 isort ruff "numpydoc>=1.10" + python -m pip install black isort ruff "numpydoc>=1.10" python -m pip list # Every check runs even when an earlier one fails, so that the log shows all of # the problems - - name: flake8 - if: ${{ !cancelled() && steps.install.outcome == 'success' }} - run: flake8 arch - - name: ruff if: ${{ !cancelled() && steps.install.outcome == 'success' }} run: ruff check arch diff --git a/pyproject.toml b/pyproject.toml index 787045f8a7..9d8f32b3b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -129,8 +129,6 @@ dev = [ "black[jupyter]~=25.9.0", "isort~=6.0", "colorama", - "flake8", - "flake8-bugbear", "mypy>=1.3", "pandas-stubs", "scipy-stubs", @@ -240,8 +238,6 @@ ignore = [ # Required to allow black formatting # Whitespace before ':' (Needed for black) "E203", - # Line too long (### > 88 characters) (Needed for black) - "E501", # Multiple statements on one line (colon) (E701) "E701", # Always ignore @@ -304,6 +300,11 @@ ignore = [ "PLR0917", ] +# black keeps code within 88 characters but cannot shorten comments, docstrings and long +# strings. E501 limits every line to 99 characters, as flake8 did. +[tool.ruff.lint.pycodestyle] +max-line-length = 99 + [tool.ruff.lint.per-file-ignores] # Has function names test for running test suite, not a (pytest) )test "arch/utility/__init__.py" = ["PT028"] diff --git a/requirements-dev.txt b/requirements-dev.txt index 21bd955465..8ebf69469f 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -26,8 +26,6 @@ numpydoc>=1.10 black[jupyter]~=25.1.0 isort~=5.12 colorama -flake8 -flake8-bugbear mypy ruff>=0.8.6 pyupgrade>=3.4.0 From 7acf76ca3aaa4401055587acae70f0a5a21955bf Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 11 Nov 2026 16:42:58 +0000 Subject: [PATCH 2/7] MAINT: Move the development requirements into dependency groups PEP 735 dependency groups in pyproject.toml replace requirements.txt, requirements-dev.txt, doc/requirements.txt, the requirements.txt of the critical value simulations and the test, doc and dev extras, which were not features of arch. pip 25.1 or later installs them with "--group": - build: what "pip install -e . --no-build-isolation" needs - test: pytest >= 9, pytest-cov, pytest-xdist and coverage, with numpydoc - notebooks: jupyter and nbconvert for the example notebooks - lint: black, isort, ruff, mypy and the stubs, with numpydoc - docstrings: numpydoc >= 1.10, included by test and lint - dev: build, test, lint and notebooks, with matplotlib, seaborn and pytest-randomly - doc: Sphinx, sphinx-immaterial and nbsphinx, in addition to dev - simulation: colorama, joblib and psutil for the simulation scripts The dependencies of arch are listed once, in [project]. The groups do not repeat them; pip installs them with arch. The duplicated pins had drifted apart (black 25.1 and 25.9, isort 5.12 and 6.0, ruff 0.8.6 while CI used the newest of each). The Lint workflow now installs the lint group, with black 26.10.1, isort 9.0 and ruff 0.17.4 or later, the versions that it used. Not carried over: setuptools and wheel (meson-python builds arch), patsy and packaging (dependencies of statsmodels and of arch), jinja2 (a dependency of Sphinx), sphinx-autodoc-typehints (not in the Sphinx extensions), the pins of the unused doc extra, pyupgrade (ruff has the UP rules), the jupyterlab-code-formatter editor plugin, property_cached (unused) and colorama outside the simulation group. numba is optional and the CI jobs that test it install it, so it is in no group; it has no wheels for some supported platforms. The Snyk pins stay, in the groups that pull in those packages. [build-system] requires meson-python >= 0.18.0, the first release that supports the license and license-files fields, and uses the normalized name setuptools-scm. CI: - Azure Linux installs the build, test and notebooks groups in the same pip command as the exact versions of numpy, scipy, ..., so pip resolves them together. In the conda job, pip installs the groups after the conda packages, so that it keeps numpy from conda-forge. - Azure Windows installs the build and test groups with PACKAGES instead of requirements-dev.txt and requirements.txt. It no longer installs the linters, Sphinx, jupyter or pytest-randomly, which the fast tests do not use, so the tests run in the same order as on Linux. - Windows ARM installs the test group instead of pinning pytest, which adds numpydoc (arch/tests/test_docstrings.py now runs there) and pytest-cov. - The documentation workflow installs the dev and doc groups. README.md and the contributing guide show how to install the groups. --- .github/workflows/generate-documentation.yml | 3 +- .github/workflows/lint.yml | 3 +- .github/workflows/windows-arm.yml | 7 +- README.md | 21 ++- .../simulation/requirements.txt | 3 - ci/azure/azure_template_windows.yml | 12 +- ci/azure/install-posix.sh | 21 ++- doc/requirements.txt | 25 --- doc/source/contributing.rst | 45 +++++- pyproject.toml | 147 +++++++++--------- requirements-dev.txt | 54 ------- requirements.txt | 6 - 12 files changed, 162 insertions(+), 185 deletions(-) delete mode 100644 arch/unitroot/critical_values/simulation/requirements.txt delete mode 100644 doc/requirements.txt delete mode 100644 requirements-dev.txt delete mode 100644 requirements.txt diff --git a/.github/workflows/generate-documentation.yml b/.github/workflows/generate-documentation.yml index b0fdea1912..0e490b2197 100644 --- a/.github/workflows/generate-documentation.yml +++ b/.github/workflows/generate-documentation.yml @@ -34,8 +34,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - python -m pip install -r requirements.txt - python -m pip install -r requirements-dev.txt + python -m pip install --group dev --group doc - name: Install arch run: | diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index f2ee962d00..fbea753f10 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -27,11 +27,12 @@ jobs: with: python-version: ${{ matrix.python-version }} + # The lint dependency group in pyproject.toml - name: Install the linters id: install run: | python -m pip install --upgrade pip - python -m pip install black isort ruff "numpydoc>=1.10" + python -m pip install --group lint python -m pip list # Every check runs even when an earlier one fails, so that the log shows all of diff --git a/.github/workflows/windows-arm.yml b/.github/workflows/windows-arm.yml index a6aa8fc9b9..4b3a11a3e7 100644 --- a/.github/workflows/windows-arm.yml +++ b/.github/workflows/windows-arm.yml @@ -64,17 +64,18 @@ jobs: python -c "import platform, sys; print(sys.version, platform.machine())" python -c "import sys, sysconfig; print(sysconfig.get_platform()); sys.exit(sysconfig.get_platform() != 'win-arm64')" - # Only wheels, so that the job fails if a dependency would have to be compiled + # Only wheels, so that the job fails if a dependency would have to be compiled. The + # test requirements are the test dependency group in pyproject.toml. - name: Install the dependencies env: NUMBA: ${{ matrix.numba }} run: | - packages=(numpy scipy pandas statsmodels matplotlib seaborn "pytest>=9,<10" pytest-xdist) + packages=(numpy scipy pandas statsmodels matplotlib seaborn) if [[ "${NUMBA}" == "true" ]]; then packages+=(numba) fi python -m pip install --upgrade pip - python -m pip install --only-binary=:all: "${packages[@]}" + python -m pip install --only-binary=:all: --group test "${packages[@]}" - name: Build the wheel run: | diff --git a/README.md b/README.md index 4e0cb6d79d..69e83d5442 100644 --- a/README.md +++ b/README.md @@ -266,14 +266,19 @@ Building the extensions from source needs the Visual Studio Build Tools ### Developing -The development requirements are: - -- Cython (3.1+), meson-python and ninja, unless building without the binary - modules -- pytest (9+, for tests) -- sphinx (to build docs) -- sphinx-immaterial (to build docs) -- jupyter, notebook and nbsphinx (to build docs) +The development requirements are dependency groups in `pyproject.toml`, +which pip 25.1 or later installs. From a clone of the repository, + +```shell +python -m pip install --group dev +python -m pip install -e . --no-build-isolation +``` + +installs the tools to build (Cython 3.1+, meson-python and ninja), test +(pytest 9+) and lint arch, and then arch itself. Adding `--group doc` to the +first command also installs what the documentation needs (sphinx, +sphinx-immaterial and nbsphinx). `doc/source/contributing.rst` lists the +commands that check the code. ### Installation Notes diff --git a/arch/unitroot/critical_values/simulation/requirements.txt b/arch/unitroot/critical_values/simulation/requirements.txt deleted file mode 100644 index 2322d57dd7..0000000000 --- a/arch/unitroot/critical_values/simulation/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -joblib -colorama -psutil diff --git a/ci/azure/azure_template_windows.yml b/ci/azure/azure_template_windows.yml index cdadb1edfd..3441b492a0 100644 --- a/ci/azure/azure_template_windows.yml +++ b/ci/azure/azure_template_windows.yml @@ -18,11 +18,14 @@ jobs: strategy: # The newest Python with the newest packages, and the oldest Python with numpy 1.x # (the default integer is 32 bits on Windows) and pandas 2.1. PACKAGES is installed - # in a single pip command with requirements.txt, so that pip also picks versions - # of the other packages that work with the pins. + # in a single pip command with the build and test dependency groups in + # pyproject.toml, so that pip also picks versions of the other packages that work + # with the pins. pip installs scipy, pandas and statsmodels with arch when PACKAGES + # does not list them. matrix: python314_win_latest: python.version: '3.14' + PACKAGES: 'matplotlib seaborn' python310_win_numpy126: python.version: '3.10' PACKAGES: 'numpy==1.26.4 scipy==1.11.4 pandas==2.1.4 statsmodels==0.14.1 matplotlib seaborn numba build' @@ -40,9 +43,8 @@ jobs: - script: | python -m venv arch-test call arch-test\Scripts\activate.bat - python -m pip install --upgrade pip wheel - python -m pip install -r requirements-dev.txt -U - python -m pip install %PACKAGES% -r requirements.txt -U || exit /b 1 + python -m pip install --upgrade pip + python -m pip install --group build --group test %PACKAGES% -U || exit /b 1 python -m pip list displayName: 'Create Venv and Install dependencies' diff --git a/ci/azure/install-posix.sh b/ci/azure/install-posix.sh index 8620605079..df52d7d6dc 100644 --- a/ci/azure/install-posix.sh +++ b/ci/azure/install-posix.sh @@ -1,5 +1,9 @@ #!/usr/bin/env bash +# The build tools, the test requirements and the packages that the example notebooks +# need are dependency groups in pyproject.toml, which pip 25.1 or later installs +DEP_GROUPS="--group build --group test --group notebooks" + if [[ ${USE_CONDA} == "true" ]]; then # Miniforge (conda-forge only) is installed by the pipeline and the env's bin # directory is on PATH, so no activation is needed. @@ -13,16 +17,15 @@ if [[ ${USE_CONDA} == "true" ]]; then fi CMD="mamba install -n arch-test -y -c conda-forge numpy" else - CMD="python -m pip install numpy" + CMD="python -m pip install ${DEP_GROUPS} numpy" fi -python -m pip install --upgrade pip "setuptools>=61" wheel -python -m pip install cython "pytest>=9,<10" pytest-xdist "coverage[toml]" pytest-cov ipython jupyter notebook nbconvert "property_cached>=1.6.3" nbconvert setuptools_scm colorama "meson-python>=0.18.0" meson ninja "numpydoc>=1.10" - +python -m pip install --upgrade pip # Versions are exact so that the job tests what its matrix entry says, and all of -# the packages are installed in a single command so that the installer picks -# versions of matplotlib, seaborn, ... that work with them +# the packages (with pip, also the dependency groups) are installed in a single +# command so that the installer picks versions of matplotlib, seaborn, ... that work +# with them if [[ -n ${NUMPY} ]]; then CMD="$CMD==${NUMPY}"; fi; CMD="$CMD scipy" if [[ -n ${SCIPY} ]]; then CMD="$CMD==${SCIPY}"; fi; @@ -47,6 +50,12 @@ CMD="$CMD $EXTRA" echo $CMD eval $CMD || exit 1 +if [[ ${USE_CONDA} == "true" ]]; then + # After the conda packages, so that pip keeps the numpy from conda-forge + echo python -m pip install ${DEP_GROUPS} + python -m pip install ${DEP_GROUPS} || exit 1 +fi + if [[ ${NO_MATPLOTLIB,,} == true ]]; then # Fail if another package installed matplotlib, so that the job really tests without it if python -c "import importlib.util, sys; sys.exit(importlib.util.find_spec('matplotlib') is None)"; then diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index 9258b8671b..0000000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,25 +0,0 @@ -wheel -meson-python -ninja -setuptools_scm[toml]>=9.2,<10 -cython>=3.1.0 -numpy >=2 -scipy >=1.15.0 -ipython >=8.0.1 -matplotlib >=3.9 -pandas >=2.3.0 -statsmodels >=0.14.5 -jinja2 -sphinx -seaborn -numpydoc>=1.0.0 -nbsphinx -sphinx-immaterial -jupyter -notebook -sphinx-autodoc-typehints -fonttools>=4.62.0 # not directly required, pinned by Snyk to avoid a vulnerability -jupyterlab>=4.4.8 # not directly required, pinned by Snyk to avoid a vulnerability -nbconvert>=7.17.0 # not directly required, pinned by Snyk to avoid a vulnerability -jupyter-server>=2.20.0 # not directly required, pinned by Snyk to avoid a vulnerability -tornado>=6.5.7 # not directly required, pinned by Snyk to avoid a vulnerability diff --git a/doc/source/contributing.rst b/doc/source/contributing.rst index 5646f58e3c..7a3f4e1a6d 100644 --- a/doc/source/contributing.rst +++ b/doc/source/contributing.rst @@ -1,6 +1,47 @@ Contributing ============ +Development environment +----------------------- + +The development requirements are dependency groups (PEP 735) in ``pyproject.toml``, +which pip 25.1 or later installs. From the root of a clone of the repository, + +.. code-block:: bash + + python -m pip install --group dev + python -m pip install -e . --no-build-isolation + +installs the build tools, the test runner, the linters and the packages that the example +notebooks need, and then builds and installs arch in place. Add ``--group doc`` to the +first command to also build the documentation. The groups are: + +* ``build``: what ``python -m pip install -e . --no-build-isolation`` needs (Cython, + meson, meson-python, ninja, NumPy and setuptools-scm). +* ``test``: pytest, pytest-xdist, pytest-cov and numpydoc. +* ``notebooks``: jupyter and nbconvert, which the slow tests use to run the example + notebooks. +* ``lint``: ruff, black, isort, numpydoc, mypy and the pandas and SciPy stubs. +* ``docstrings``: numpydoc, which ``test`` and ``lint`` include. +* ``dev``: ``build``, ``test``, ``lint`` and ``notebooks``, with matplotlib, seaborn and + pytest-randomly. +* ``doc``: Sphinx, sphinx-immaterial and nbsphinx, in addition to ``dev``. +* ``simulation``: the packages that the scripts in + ``arch/unitroot/critical_values/simulation`` need in addition to ``dev``. + +The groups do not include the dependencies of arch, which pip installs with arch. The +tests and the checks that CI runs are + +.. code-block:: bash + + python -m pytest arch/tests -n auto -m "not slow" + ruff check arch + black --check arch + isort --check arch + python -m numpydoc lint $(git ls-files "arch/*.py") + +and the settings of all of these tools are in ``pyproject.toml``. + Docstrings ---------- @@ -115,8 +156,8 @@ The rules are configured in the ``[tool.numpydoc_validation]`` table of python -m numpydoc lint $(git ls-files "arch/*.py") python -m pytest arch/tests/test_docstrings.py -Both need numpydoc 1.10 or later, which ``requirements-dev.txt`` and the ``dev`` extra -install. The Lint workflow runs the first command, and the second is skipped when +Both need numpydoc 1.10 or later, which the ``test``, ``lint`` and ``dev`` dependency +groups install. The Lint workflow runs the first command, and the second is skipped when numpydoc is not installed. ``numpydoc lint`` reads the source files. It cannot see a docstring that a class diff --git a/pyproject.toml b/pyproject.toml index 9d8f32b3b6..827b7df61f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,17 @@ [build-system] build-backend = 'mesonpy' +# The build dependency group below repeats these pins (other than NumPy's) for builds +# without build isolation, since a dependency group cannot include this table. +# meson.build also checks the Cython floor. requires = [ - 'meson-python', - "cython>=3.1.0,<4", # Sync with the doc and dev extras and requirements-dev.txt + "meson-python>=0.18.0", + "cython>=3.1.0,<4", "numpy>=2.0.0,<3", - "setuptools_scm>=9.2.0,<10", + "setuptools-scm>=9.2.0,<10", ] [project] name = "arch" -# Keep synced with requirements.txt dependencies = [ "numpy>=1.22.3,<3", "pandas>=1.4.0", @@ -67,85 +69,90 @@ maintainers = [ readme = "README.md" requires-python = ">=3.10" -[project.optional-dependencies] -test = [ - # test - "pytest>=9,<10", - "pytest-randomly", - "pytest-xdist", - "pytest-cov", - "coverage[toml]", - "meson", +[project.urls] +homepage = "https://github.com/bashtage/arch" +documentation = "https://bashtage.github.io/arch/" +repository = "https://github.com/bashtage/arch" +changelog = "https://bashtage.github.io/arch/changes.html" + +# Development dependencies (PEP 735), installed with pip 25.1 or later. For example, +# python -m pip install --group dev +# python -m pip install -e . --no-build-isolation +# installs everything needed to build, test and lint arch, and adding "--group doc" to +# the first command also installs what the documentation needs. The groups do not +# include the dependencies of arch, which pip installs with arch. +[dependency-groups] +# Everything that "python -m pip install -e . --no-build-isolation" needs +build = [ + "cython>=3.1.0,<4", + "meson>=1.9.0", # meson_version in meson.build + "meson-python>=0.18.0", "ninja", + "numpy", # Its range is in the dependencies of arch + "setuptools-scm>=9.2.0,<10", ] -doc = [ - # Documentation - "setuptools>=61", - "wheel", - "setuptools_scm[toml]>=9.2.0,<10", - "cython>=3.1.0,<4", # Sync with the doc and dev extras and requirements-dev.txt - "numpy >=2.3.4", - "scipy >=1.16.0", - "ipython >=8.0.1", - "matplotlib >=3.10", - "patsy >=0.5.3", - "statsmodels >=0.13.5", - "jinja2", - "sphinx>=7", - "seaborn", +# numpydoc checks the docstrings, in "python -m numpydoc lint" and in +# arch/tests/test_docstrings.py +docstrings = [ "numpydoc>=1.10", - "nbsphinx", - "sphinx-immaterial", +] +# The test runner and the docstring checks. Without matplotlib and seaborn, the tests of +# the plots are skipped, and CI tests both with and without them. numba runs the +# recursions only when arch is built without the Cython extensions. +test = [ + "pytest>=9", # minversion in [tool.pytest] + "pytest-cov", + "pytest-xdist", + "coverage[toml]", # Python 3.10 needs the extra to read [tool.coverage] + { include-group = "docstrings" }, +] +# The example notebooks, which the slow tests in arch/tests/test_examples.py run and the +# documentation shows +notebooks = [ + "ipython>=8", "jupyter", + "nbconvert>=7.17.0", "notebook", - "sphinx-autodoc-typehints", - "fonttools>=4.43.0", # not directly required, pinned by Snyk to avoid a vulnerability - "jupyterlab>=4.4.8", # not directly required, pinned by Snyk to avoid a vulnerability - "ipython>=7", - "sphinx_immaterial", - "nbconvert", - "pickleshare", - # Requirements for doc build, in addition to requirements.txt - "pandas~=2.3.3", + "jupyter-server>=2.20.0", # not directly required, pinned by Snyk to avoid a vulnerability + "jupyterlab>=4.4.8", # not directly required, pinned by Snyk to avoid a vulnerability + "tornado>=6.5.7", # not directly required, pinned by Snyk to avoid a vulnerability +] +lint = [ + "black[jupyter]~=26.10.1", + "isort~=9.0", + "mypy>=1.3", + "pandas-stubs", + "ruff>=0.17.4", + "scipy-stubs", + { include-group = "docstrings" }, ] dev = [ - # versioning - "setuptools_scm[toml]>=9.2.0,<10", - "packaging", - # Performance - "cython>=3.1.0", - "numba>=0.55", - # Graphics + { include-group = "build" }, + { include-group = "test" }, + { include-group = "lint" }, + { include-group = "notebooks" }, "matplotlib>=3", "seaborn", - # Tests - "pytest>=9,<10", "pytest-randomly", - "pytest-xdist", - "pytest-cov", - # docstrings: the numpydoc linter and arch/tests/test_docstrings.py - "numpydoc>=1.10", - # formatting - "black[jupyter]~=25.9.0", - "isort~=6.0", + "fonttools>=4.62.0", # not directly required, pinned by Snyk to avoid a vulnerability + "urllib3>=2.8.0", # not directly required, pinned by Snyk to avoid a vulnerability + "zipp>=3.19.1", # not directly required, pinned by Snyk to avoid a vulnerability +] +# The documentation, in addition to the dev group +doc = [ + "nbsphinx", + "pickleshare", + "sphinx>=7", + "sphinx-immaterial", +] +# The scripts in arch/unitroot/critical_values/simulation that simulate the critical +# values, in addition to the dev group +simulation = [ "colorama", - "mypy>=1.3", - "pandas-stubs", - "scipy-stubs", - "ruff>=0.8.6", - "pyupgrade>=3.4.0", - "jupyterlab-code-formatter", - "jupyterlab>=4.4.8", # not directly required, pinned by Snyk to avoid a vulnerability - "zipp>=3.19.1", # not directly required, pinned by Snyk to avoid a vulnerability + "joblib", + "psutil", ] - -[project.urls] -homepage = "https://github.com/bashtage/arch" -documentation = "https://bashtage.github.io/arch/" -repository = "https://github.com/bashtage/arch" -changelog = "https://bashtage.github.io/arch/changes.html" - [tool.meson-python.args] setup = ['--vsenv'] diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index 8ebf69469f..0000000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,54 +0,0 @@ -# versioning -meson-python>=0.18.0 -meson -ninja -setuptools_scm[toml]>=9.2.0,<10 -packaging - -# Performance -cython>=3.1.0 -numba>=0.49,!=0.50.*;python_version<"3.12" - -# Graphics -matplotlib>=3 -seaborn - -# Tests -pytest>=9,<10 -pytest-xdist -pytest-cov -pytest-randomly - -# docstrings: the numpydoc linter and arch/tests/test_docstrings.py -numpydoc>=1.10 - -# formatting -black[jupyter]~=25.1.0 -isort~=5.12 -colorama -mypy -ruff>=0.8.6 -pyupgrade>=3.4.0 -jupyterlab-code-formatter - -# Documentation -ipython>=7 -sphinx>=7 -sphinx_immaterial -nbsphinx -jupyter -notebook -nbconvert -sphinx-autodoc-typehints -pickleshare -jupyterlab>=4.4.8 # not directly required, pinned by Snyk to avoid a vulnerability -zipp>=3.19.1 # not directly required, pinned by Snyk to avoid a vulnerability -urllib3>=2.8.0 # not directly required, pinned by Snyk to avoid a vulnerability -fonttools>=4.62.0 # not directly required, pinned by Snyk to avoid a vulnerability -jupyter-server>=2.20.0 # not directly required, pinned by Snyk to avoid a vulnerability -tornado>=6.5.7 # not directly required, pinned by Snyk to avoid a vulnerability - - -# typing -pandas-stubs -scipy-stubs diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 4dba3fa5f2..0000000000 --- a/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -# Keep synced with pyproject.toml -numpy>=1.22.3 -scipy>=1.8 -pandas>=1.4 -statsmodels>=0.13.1 -packaging \ No newline at end of file From 1753c448374d797c1a77f58360b91d8b768191a3 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 11 Nov 2026 16:43:11 +0000 Subject: [PATCH 3/7] MAINT: Move the coverage settings into pyproject.toml coverage reads .coveragerc before pyproject.toml, so the [tool.coverage] tables were never used, and CI passed --cov-config=.coveragerc. The two copies had drifted apart. Remove .coveragerc and keep [tool.coverage], which coverage and pytest-cov now read. Compared with .coveragerc, [tool.coverage] also - omits conftest.py from the measurement; - adds to coverage's default exclusions instead of replacing them, and also excludes "def __repr__", "if self.debug", "raise AssertionError", "raise ImportError", "if 0:" and the __main__ guard; - shows the missing lines in the terminal report. The coverage numbers can therefore move up slightly. ignore_errors is now true, as it was in .coveragerc, so that a file that coverage cannot read does not fail the report in CI. Python 3.10 reads the TOML file through the coverage[toml] extra in the test dependency group. --- .coveragerc | 45 ------------------------------- ci/azure/azure_template_posix.yml | 4 +-- pyproject.toml | 3 ++- 3 files changed, 4 insertions(+), 48 deletions(-) delete mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index c1d6ccd3e6..0000000000 --- a/.coveragerc +++ /dev/null @@ -1,45 +0,0 @@ -[run] -source = arch -branch = True -omit = - */_version.py - */compat/* - # Scripts that simulate and fit the critical values - */critical_values/simulation/* -plugins = Cython.Coverage - -[report] -# Regexes for lines to exclude from consideration -exclude_lines = - # Have to re-enable the standard pragma - pragma: no cover - - # Don't complain if tests don't hit defensive assertion code: - raise NotImplementedError - except NotImplementedError - # Ignore pass - pass - # Ignore failure messages - pytest.xfail - # Ignore ImportError protection - except ImportError - # Ignore type checking code - if TYPE_CHECKING - elif TYPE_CHECKING - # Cython function declarations - cdef - # Cython functions with void - cdef void - # Numba jit decorators - @jit - - -include = */arch/* -omit = - */_version.py - */compat/* - # Scripts that simulate and fit the critical values - */critical_values/simulation/* - *recursions.py - *samplers.py -ignore_errors = True diff --git a/ci/azure/azure_template_posix.yml b/ci/azure/azure_template_posix.yml index a708e9e1b8..9c252848ac 100644 --- a/ci/azure/azure_template_posix.yml +++ b/ci/azure/azure_template_posix.yml @@ -212,7 +212,7 @@ jobs: - script: | echo "Testing editable install" - export COVERAGE_OPTS="--cov-config=.coveragerc --cov=arch --cov-branch --cov-report xml:coverage.xml --cov-report term" + export COVERAGE_OPTS="--cov=arch --cov-branch --cov-report xml:coverage.xml --cov-report term" echo pytest -m "${PYTEST_PATTERN}" --junitxml=junit/test-results.xml -n auto --durations=25 ${COVERAGE_OPTS} arch/tests pytest -m "${PYTEST_PATTERN}" --junitxml=junit/test-results.xml -n auto --durations=25 ${COVERAGE_OPTS} arch/tests displayName: 'Run tests (editable)' @@ -230,7 +230,7 @@ jobs: echo "Testing with Cython coverage" # Uninstall xdist to avoid issues with coverage and Cython python -m pip uninstall pytest-xdist -y || true - export COVERAGE_OPTS="--cov-config=.coveragerc --cov=arch --cov-branch --cov-report xml:coverage.xml --cov-report term" + export COVERAGE_OPTS="--cov=arch --cov-branch --cov-report xml:coverage.xml --cov-report term" echo pytest --junitxml=junit/test-results.xml --durations=25 ${COVERAGE_OPTS} arch/tests/univariate/test_recursions.py arch/tests/bootstrap/test_samplers.py arch/tests/univariate/test_arch_in_mean.py pytest --junitxml=junit/test-results.xml --durations=25 ${COVERAGE_OPTS} arch/tests/univariate/test_recursions.py arch/tests/bootstrap/test_samplers.py arch/tests/univariate/test_arch_in_mean.py displayName: 'Run tests (cython coverage)' diff --git a/pyproject.toml b/pyproject.toml index 827b7df61f..777f01b3c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -397,7 +397,8 @@ omit = [ [tool.coverage.report] show_missing = true -ignore_errors = false +# Report on the other files when one cannot be read +ignore_errors = true # Regexes for lines to exclude from consideration exclude_also = [ # Have to re-enable the standard pragma From ee4ae6b4bcd8d2e7b1d6ec03296bd991811645b4 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 11 Nov 2026 16:44:06 +0000 Subject: [PATCH 4/7] MAINT: Clean up the tool settings in pyproject.toml - black and ruff take their target versions from requires-python (black infers py310 to py315 and ruff 3.10, as before), so the target-version settings are removed and cannot fall behind requires-python. - The [tool.mypy-arch.conftest] and [tool.mypy-arch._version] tables use the setup.cfg section names, which mypy ignores in pyproject.toml. arch.conftest already had an override, and arch._version joins it. [tool.pyrefly] moves after the mypy overrides. - Fix the .pytest_cache pattern in black's exclude, which was misspelled. - Add the "Python :: 3 :: Only" classifier and an issues URL. - Remove .gitattributes, whose only line applied export-subst to arch/_version.py, which git does not track (setuptools-scm writes it at build time), so git archive never used it. --- .gitattributes | 1 - pyproject.toml | 27 ++++++++++----------------- 2 files changed, 10 insertions(+), 18 deletions(-) delete mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index f5a58b76e9..0000000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -arch/_version.py export-subst diff --git a/pyproject.toml b/pyproject.toml index 777f01b3c1..d20f4293a3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ classifiers = [ "Operating System :: Microsoft :: Windows", "Operating System :: POSIX", "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", "Programming Language :: Cython", "Topic :: Scientific/Engineering", ] @@ -73,6 +74,7 @@ requires-python = ">=3.10" homepage = "https://github.com/bashtage/arch" documentation = "https://bashtage.github.io/arch/" repository = "https://github.com/bashtage/arch" +issues = "https://github.com/bashtage/arch/issues" changelog = "https://bashtage.github.io/arch/changes.html" # Development dependencies (PEP 735), installed with pip 25.1 or later. For example, @@ -159,14 +161,14 @@ setup = ['--vsenv'] [tool.setuptools_scm] version_file = "arch/_version.py" +# black and ruff take their target Python versions from requires-python [tool.black] -target-version = ['py310'] exclude = ''' ( \.egg | \.git | \.mypy_cache - | \.oytest_cache + | \.pytest_cache | buck-out | ^/build/ | ^/dist/ @@ -182,7 +184,6 @@ exclude = [ [tool.ruff] line-length = 88 fix = false -target-version = "py310" [tool.ruff.lint] typing-modules = ["arch._typing"] @@ -457,14 +458,6 @@ disallow_untyped_defs=true disallow_incomplete_defs=true show_error_context=true -[tool.mypy-arch.conftest] -check_untyped_defs=false -disallow_untyped_defs=false - -[tool.mypy-arch._version] -check_untyped_defs=false -disallow_untyped_defs=false - [[tool.mypy.overrides]] module = "arch.tests.*" check_untyped_defs=false @@ -472,16 +465,11 @@ disallow_untyped_defs=false disallow_incomplete_defs=false [[tool.mypy.overrides]] -module = ["conftest", "arch.conftest"] +module = ["conftest", "arch.conftest", "arch._version"] check_untyped_defs=false disallow_untyped_defs=false disallow_incomplete_defs=false -[tool.pyrefly] -project-excludes = ["**/tests*"] -preset = "legacy" -ignore-missing-imports = ["*"] - [[tool.mypy.overrides]] module = [ "unitroot.critical_values.simulation.*", @@ -491,6 +479,11 @@ check_untyped_defs=false disallow_untyped_defs=false disallow_incomplete_defs=false +[tool.pyrefly] +project-excludes = ["**/tests*"] +preset = "legacy" +ignore-missing-imports = ["*"] + [tool.numpydoc_validation] # Run with ``python -m numpydoc lint $(git ls-files "arch/*.py")``. "all" with other # codes listed is "everything except those codes". From d416cf76803558575263ced0b585e22d4596b826 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 11 Nov 2026 16:56:48 +0000 Subject: [PATCH 5/7] DOC: Add a release note for the dependency groups Add an entry to "Documentation and maintenance" in the 9.0 notes: the development requirements are dependency groups in pyproject.toml, which replace the requirements files and the test, doc and dev extras, the coverage settings are in pyproject.toml, and ruff replaces flake8. --- doc/source/changes/9.0.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/source/changes/9.0.rst b/doc/source/changes/9.0.rst index a43e00660a..f0e781ff3f 100644 --- a/doc/source/changes/9.0.rst +++ b/doc/source/changes/9.0.rst @@ -1314,6 +1314,13 @@ Documentation and maintenance test suite, including the slow tests, on Python 3.13 to 3.15. Unlike the other jobs, it does not limit the number of BLAS threads, because NumPy's OpenBLAS on this platform crashes with one thread (see "Compatibility") (:issue:`1003`). +- The development requirements are dependency groups in ``pyproject.toml``, which pip + 25.1 or later installs, for example with ``python -m pip install --group dev`` (see + the contributing guide). They replace ``requirements.txt``, ``requirements-dev.txt`` + and ``doc/requirements.txt``, and the ``test``, ``doc`` and ``dev`` extras, which have + been removed. The settings of coverage moved from ``.coveragerc`` to + ``pyproject.toml``, and ruff replaces flake8 in the style checks, with the same limit + of 99 characters on comments, docstrings and long strings. Deprecations and removals ~~~~~~~~~~~~~~~~~~~~~~~~~ From 84fc922ab4924471edb1a2a82b9964e35be18f78 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 11 Nov 2026 17:30:34 +0000 Subject: [PATCH 6/7] DOC: Add the PR number to the dependency groups note --- doc/source/changes/9.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/changes/9.0.rst b/doc/source/changes/9.0.rst index f0e781ff3f..868008eeb6 100644 --- a/doc/source/changes/9.0.rst +++ b/doc/source/changes/9.0.rst @@ -1320,7 +1320,7 @@ Documentation and maintenance and ``doc/requirements.txt``, and the ``test``, ``doc`` and ``dev`` extras, which have been removed. The settings of coverage moved from ``.coveragerc`` to ``pyproject.toml``, and ruff replaces flake8 in the style checks, with the same limit - of 99 characters on comments, docstrings and long strings. + of 99 characters on comments, docstrings and long strings (:issue:`1021`). Deprecations and removals ~~~~~~~~~~~~~~~~~~~~~~~~~ From 4ec3bc5fb93c759b5211fccf19d771197bf48292 Mon Sep 17 00:00:00 2001 From: Kevin Sheppard Date: Wed, 11 Nov 2026 17:37:06 +0000 Subject: [PATCH 7/7] CI: Keep the dependency group options in a bash array ShellCheck (SC2086, reported by Codacy) warns about the unquoted expansion of the group options in the conda job. Keep the options in an array and expand it quoted, so that the words are split by the array rather than by the shell. The commands that run are unchanged. --- ci/azure/install-posix.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ci/azure/install-posix.sh b/ci/azure/install-posix.sh index df52d7d6dc..416708f5d4 100644 --- a/ci/azure/install-posix.sh +++ b/ci/azure/install-posix.sh @@ -2,7 +2,7 @@ # The build tools, the test requirements and the packages that the example notebooks # need are dependency groups in pyproject.toml, which pip 25.1 or later installs -DEP_GROUPS="--group build --group test --group notebooks" +DEP_GROUPS=(--group build --group test --group notebooks) if [[ ${USE_CONDA} == "true" ]]; then # Miniforge (conda-forge only) is installed by the pipeline and the env's bin @@ -17,7 +17,7 @@ if [[ ${USE_CONDA} == "true" ]]; then fi CMD="mamba install -n arch-test -y -c conda-forge numpy" else - CMD="python -m pip install ${DEP_GROUPS} numpy" + CMD="python -m pip install ${DEP_GROUPS[*]} numpy" fi python -m pip install --upgrade pip @@ -52,8 +52,8 @@ eval $CMD || exit 1 if [[ ${USE_CONDA} == "true" ]]; then # After the conda packages, so that pip keeps the numpy from conda-forge - echo python -m pip install ${DEP_GROUPS} - python -m pip install ${DEP_GROUPS} || exit 1 + echo python -m pip install "${DEP_GROUPS[@]}" + python -m pip install "${DEP_GROUPS[@]}" || exit 1 fi if [[ ${NO_MATPLOTLIB,,} == true ]]; then