diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 1d7a08699..87361445d 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -68,6 +68,9 @@ jobs: - os: ubuntu-latest python: '3.11' mode: nfs + - os: ubuntu-latest + python: '3.11' + mode: lowest-deps steps: - name: Set up environment @@ -83,10 +86,17 @@ jobs: python-version: ${{ matrix.python }} - name: Install dependencies + if: matrix.mode != 'lowest-deps' run: | python -m pip install --upgrade pip wheel pip install ".[extras,test]" + - name: Install tox for lowest-deps mode + if: matrix.mode == 'lowest-deps' + run: | + python -m pip install --upgrade pip + pip install "tox>=4" "tox-uv>=1.11" + # Set only if matrix.instance_name is defined - name: Set DANDI_TESTS_INSTANCE_NAME if: ${{ matrix.instance_name }} @@ -129,10 +139,15 @@ jobs: run: echo PYTEST_ADDOPTS=--scheduled >> "$GITHUB_ENV" - name: Run all tests except those involving obolibrary - if: matrix.mode != 'dandi-api' && matrix.mode != 'obolibrary-only' + if: matrix.mode != 'dandi-api' && matrix.mode != 'obolibrary-only' && matrix.mode != 'lowest-deps' run: | python -m pytest -s -v -m "not obolibrary" --cov=dandi --cov-report=xml dandi + - name: Run tests against minimum declared dependency versions + if: matrix.mode == 'lowest-deps' + run: | + tox -e py3-lowest -- -s -m "not obolibrary" + - name: Run only tests related to obolibrary if: matrix.mode == 'obolibrary-only' run: | diff --git a/.gitignore b/.gitignore index b39d66477..e2d2dab22 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ sandbox/ venv/ venvs/ .DS_Store +.duct diff --git a/pyproject.toml b/pyproject.toml index 03d9f0d62..bc00d6ac6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,36 +46,43 @@ dependencies = [ "bidsschematools ~= 1.0", "bids-validator-deno >= 2.0.5", "click >= 8.2", - "click-didyoumean", + "click-didyoumean >= 0.3.1", "dandischema ~= 0.12.0", "etelemetry >= 0.2.2", - "fasteners", + "fasteners >= 0.19", "fscacher >= 0.3.0", - # 3.14.4: https://github.com/hdmf-dev/hdmf/issues/1186 - "hdmf != 3.5.0,!=3.14.4", - "humanize", + # Floor raised to what `py3-lowest` actually resolves: modern pynwb pins + # hdmf >= 4, so declared floor is now the tested floor. + "hdmf >= 4.1.0", + "humanize >= 4.5.0", "interleave ~= 0.3", - "joblib", - "keyring != 23.9.0", - "keyrings.alt", - "packaging", - "platformdirs", - "pycryptodomex", # for EncryptedKeyring backend in keyrings.alt - "pydantic ~= 2.0", - "pynwb >= 1.0.3,!=1.1.0,!=2.3.0", - "numcodecs", + "joblib >= 1.3.0", + "keyring >= 23.10.0", + "keyrings.alt >= 5.0.0", + "packaging >= 22.0", + # Floor raised: keyring 23.10 chain (jaraco.classes) transitively requires >= 4. + "platformdirs >= 4.1.0", + "pycryptodomex >= 3.16.0", # for EncryptedKeyring backend in keyrings.alt + "pydantic ~= 2.9", + # Floor raised: dandischema 0.12 / nwbinspector 0.7 require modern pynwb. + "pynwb >= 3.1.0", + "numcodecs >= 0.11.0", "nwbinspector >= 0.7.0", - "pyout >=0.5, !=0.6.0", - "python-dateutil", - "requests ~= 2.20", - "ruamel.yaml >=0.15, <1", - "semantic-version", - "tenacity", - "tensorstore", + "pyout >= 0.7.3", + "python-dateutil >= 2.9.0", + # Floor raised: urllib3 2.x requires requests >= 2.30. + "requests ~= 2.30", + # Floor raised: modern hdmf/pynwb chain requires >= 0.16. + "ruamel.yaml >= 0.16.0, < 1", + "semantic-version >= 2.10.0", + "tenacity >= 8.2.0", + # 0.1.62 first release built for numpy 2.x + "tensorstore >= 0.1.62", # possibly silently incomplete downloads: https://github.com/dandi/dandi-cli/issues/1500 - "urllib3 >= 2.0.0", - "yarl ~= 1.9", - "zarr >= 2.10, <= 3.1.5", + "urllib3 >= 2.0.2", + "yarl >= 1.9.1, < 2", + # Floor raised: numcodecs 0.11 / hdmf-zarr chain requires >= 2.18. + "zarr >= 2.18.0, <= 3.1.5", "zarr_checksum ~= 0.4.0", ] dynamic = ["version"] @@ -89,23 +96,25 @@ extensions = [ "ndx-events", ] extras = [ - "duecredit >= 0.6.0", - "fsspec[http]", + "duecredit >= 0.9.2", + "fsspec[http] >= 2022.11.0", ] test = [ - "aiohttp < 3.14", # See https://github.com/kevin1024/vcrpy/issues/995 - "anys ~= 0.2", - "coverage", + "aiohttp >= 3.8.4, < 3.14", # See https://github.com/kevin1024/vcrpy/issues/995 + "anys ~= 0.3", + "coverage >= 7.0.0", + # 4.10.0.84 first built for numpy 2.x ABI (older wheels segfault under numpy 2) # Workaround for VideoWriter regression in 4.13.0.90 on Intel macOS - "opencv-python < 4.13 ; sys_platform == 'darwin' and platform_machine != 'arm64'", - "opencv-python ; sys_platform != 'darwin' or platform_machine == 'arm64'", - "pytest", - "pytest-cov", - "pytest-mock", - "pytest-rerunfailures", - "pytest-timeout", - "responses != 0.24.0, != 0.25.5", - "vcrpy", + "opencv-python >= 4.10.0.84, < 4.13 ; sys_platform == 'darwin' and platform_machine != 'arm64'", + "opencv-python >= 4.10.0.84 ; sys_platform != 'darwin' or platform_machine == 'arm64'", + "pytest >= 7.2.0", + "pytest-cov >= 4.1.0", + "pytest-mock >= 3.11.0", + "pytest-rerunfailures >= 10.3", + "pytest-timeout >= 2.2.0", + "responses >= 0.23.0, != 0.24.0, != 0.25.5", + # 5.0 switched to urllib3.connection.VerifiedHTTPSConnection (urllib3 2.x compat) + "vcrpy >= 5.0.0", ] tools = [ "boto3", diff --git a/tox.ini b/tox.ini index b71a3efcf..97cf30772 100644 --- a/tox.ini +++ b/tox.ini @@ -1,4 +1,6 @@ [tox] +requires = + tox-uv >= 1.11 envlist = lint,typing,py3 [testenv] @@ -16,6 +18,19 @@ commands = coverage combine coverage report +# Install the lowest declared-compatible version of every direct dependency +# (via uv's `lowest-direct` resolution) on the minimum supported Python. +# Purpose: verify that the lower bounds in pyproject.toml are actually valid. +# Any direct dep without a lower bound will resolve to its oldest release and +# will almost certainly break; that failure is a signal to add a real bound. +[testenv:py3-lowest] +basepython = python3.11 +uv_resolution = lowest-direct +setenv = {[testenv]setenv} +passenv = {[testenv]passenv} +extras = {[testenv]extras} +commands = {[testenv]commands} + [testenv:lint] skip_install = true deps =