diff --git a/.circleci/config.yml b/.circleci/config.yml index 4987515d87..76557cbc23 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -346,64 +346,6 @@ jobs: file: /tmp/data/pytest_cov.xml flags: pytest - test_deploy_pypi: - <<: *python_defaults - steps: - - checkout - - run: - name: Update build tools - command: pip install --upgrade build twine hatch - - run: - name: Build sMRIPrep - command: python -m build - - run: - name: Twine check smriprep - command: twine check dist/* - - run: - name: Pre-run hatch version - command: hatch version - - store_artifacts: - path: /tmp/src/smriprep/dist - - run: - name: Check sdist distribution - command: | - THISVERSION=$( hatch version ) - THISVERSION=${CIRCLE_TAG:-$THISVERSION} - virtualenv --python=python sdist - source sdist/bin/activate - python -m pip install --upgrade pip - python -m pip install dist/smriprep*.tar.gz - which smriprep | grep sdist\\/bin - INSTALLED_VERSION=$(smriprep --version) - INSTALLED_VERSION=${INSTALLED_VERSION%$'\r'} - INSTALLED_VERSION=${INSTALLED_VERSION#*"smriprep v"} - echo "VERSION: \"$THISVERSION\"" - echo "INSTALLED: \"$INSTALLED_VERSION\"" - test "$INSTALLED_VERSION" = "$THISVERSION" - - run: - name: Check wheel distribution - command: | - THISVERSION=$( hatch version ) - THISVERSION=${CIRCLE_TAG:-$THISVERSION} - virtualenv --python=python wheel - source wheel/bin/activate - python -m pip install dist/smriprep*.whl - which smriprep | grep wheel\\/bin - INSTALLED_VERSION=$(smriprep --version) - INSTALLED_VERSION=${INSTALLED_VERSION%$'\r'} - INSTALLED_VERSION=${INSTALLED_VERSION#*"smriprep v"} - echo "VERSION: \"$THISVERSION\"" - echo "INSTALLED: \"$INSTALLED_VERSION\"" - test "$INSTALLED_VERSION" = "$THISVERSION" - - run: - name: Build smriprep-docker - command: python -m build wrapper - - run: - name: Twine check wrapper - command: twine check wrapper/dist/* - - store_artifacts: - path: /tmp/src/smriprep/wrapper/dist - ds005: <<: *machine_defaults working_directory: /tmp/ds005 @@ -743,23 +685,6 @@ jobs: path: ./docs/_build/html destination: versioned - deploy_pypi: - <<: *python_defaults - steps: - - checkout - - run: - name: Update build tools - command: pip install --upgrade build twine - - run: - name: Build sMRIPrep - command: python -m build - - run: - name: Build smriprep-docker - command: python -m build wrapper/ - - run: - name: Upload packages to PyPI - command: python -m twine upload dist/smriprep* wrapper/dist/smriprep* - deploy_docker: <<: *machine_defaults working_directory: *src @@ -826,17 +751,6 @@ workflows: tags: only: /.*/ - - test_deploy_pypi: - context: - - nipreps-common - filters: - branches: - only: - - /rel\/.*/ - - /maint\/.*/ - tags: - only: /.*/ - - test: context: - nipreps-common @@ -909,7 +823,6 @@ workflows: - build_docs - ds005 - ds054 - - test_deploy_pypi - test filters: branches: @@ -917,17 +830,6 @@ workflows: tags: only: /.*/ - - deploy_pypi: - context: - - nipreps-common - requires: - - deploy_docs_tag - filters: - branches: - ignore: /.*/ - tags: - only: /.*/ - - deploy_docker: context: - nipreps-common diff --git a/.dockerignore b/.dockerignore index 5dbcd18830..20494a3986 100644 --- a/.dockerignore +++ b/.dockerignore @@ -15,10 +15,6 @@ smriprep.egg-info pip-wheel-metadata/**/* pip-wheel-metadata -# pip installs -src/**/* -src/ - # other work/**/* work diff --git a/.github/workflows/build_test_deploy.yml b/.github/workflows/build_test_deploy.yml new file mode 100644 index 0000000000..5286ba6c6d --- /dev/null +++ b/.github/workflows/build_test_deploy.yml @@ -0,0 +1,273 @@ +name: Build-Test-Deploy + +on: + push: + branches: + - main + - master + - maint/* + tags: + - "*" + pull_request: + branches: + - main + - master + - maint/* + schedule: + # 8am EST / 9am EDT Mondays + - cron: "0 13 * * 1" + workflow_dispatch: + +defaults: + run: + shell: bash + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +env: + # Force tox and pytest to use color + FORCE_COLOR: true + TEMPLATEFLOW_HOME: /tmp/templateflow + +jobs: + build: + name: Build & verify package + runs-on: ubuntu-latest + permissions: + attestations: write + id-token: write + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + persist-credentials: false + ## Stuck on https://github.com/astral-sh/uv/issues/5450 + ## or https://github.com/hynek/build-and-inspect-python-package/issues/155 + # - uses: hynek/build-and-inspect-python-package@v2 + # with: + # upload-name-suffix: -main + # attest-build-provenance-github: ${{ github.event_name != 'pull_request' }} + # - uses: hynek/build-and-inspect-python-package@v2 + # with: + # path: wrapper + # upload-name-suffix: -wrapper + # attest-build-provenance-github: ${{ github.event_name != 'pull_request' }} + ## Manually reproducing with pyproject-build + ## Probably slightly slower + - name: Install the latest version of uv + uses: astral-sh/setup-uv@v4 + - name: Build smriprep + run: uvx --from=build pyproject-build --installer uv . + - name: Upload smriprep as Packages-main + uses: actions/upload-artifact@v4 + with: + name: Packages-main + path: dist/ + + - name: Show package contents hierarchically, including metadata. + shell: bash + run: | + echo -e '\n
SDist contents\n' >> $GITHUB_STEP_SUMMARY + tar -tvzf dist/*.tar.gz | sed 's/^/ /' | tee -a $GITHUB_STEP_SUMMARY + echo -e '\n
\n' >> $GITHUB_STEP_SUMMARY + + echo -e '\n
Wheel contents\n' >> $GITHUB_STEP_SUMMARY + unzip -l dist/*.whl | sed 's/^/ /' | tee -a $GITHUB_STEP_SUMMARY + echo -e '\n
\n' >> $GITHUB_STEP_SUMMARY + + echo ----- Metadata Follows ----- + echo -e '\n
Metadata\n' >> $GITHUB_STEP_SUMMARY + tar --wildcards -xOf dist/*.tar.gz "*/PKG-INFO" | sed 's/^/ /' | tee -a $GITHUB_STEP_SUMMARY + echo -e '\n
\n' >> $GITHUB_STEP_SUMMARY + echo ----- End of Metadata ----- + + - name: Report on smriprep packages + run: | + echo "name=Packages-main" >>${GITHUB_OUTPUT} + - name: Build smriprep-docker + run: uvx --from=build pyproject-build --installer uv ./wrapper + - name: Upload smriprep as Packages-wrapper + uses: actions/upload-artifact@v4 + with: + name: Packages-wrapper + path: wrapper/dist/ + + - name: Show package contents hierarchically, including metadata. + shell: bash + run: | + echo -e '\n
SDist contents\n' >> $GITHUB_STEP_SUMMARY + tar -tvzf wrapper/dist/*.tar.gz | sed 's/^/ /' | tee -a $GITHUB_STEP_SUMMARY + echo -e '\n
\n' >> $GITHUB_STEP_SUMMARY + + echo -e '\n
Wheel contents\n' >> $GITHUB_STEP_SUMMARY + unzip -l wrapper/dist/*.whl | sed 's/^/ /' | tee -a $GITHUB_STEP_SUMMARY + echo -e '\n
\n' >> $GITHUB_STEP_SUMMARY + + echo ----- Metadata Follows ----- + echo -e '\n
Metadata\n' >> $GITHUB_STEP_SUMMARY + tar --wildcards -xOf wrapper/dist/*.tar.gz "*/PKG-INFO" | sed 's/^/ /' | tee -a $GITHUB_STEP_SUMMARY + echo -e '\n
\n' >> $GITHUB_STEP_SUMMARY + echo ----- End of Metadata ----- + + test: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: ["ubuntu-latest"] + python-version: ["3.10", "3.11", "3.12", "3.13"] + dependencies: [latest] # , pre] + architecture: ["x64"] + include: + # Test minimum dependencies on oldest supported Python + - os: ubuntu-latest + python-version: "3.10" + dependencies: min + exclude: + # Do not test pre-releases for versions out of SPEC0 + - os: ubuntu-latest + python-version: "3.10" + dependencies: pre + + env: + DEPENDS: ${{ matrix.dependencies }} + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Install the latest version of uv + uses: astral-sh/setup-uv@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + architecture: ${{ matrix.architecture }} + - name: Display Python version + run: python -c "import sys; print(sys.version)" + + - name: Restore cached templateflow + id: tf-cache-restore + uses: actions/cache@v4 + with: + path: /tmp/templateflow + key: templateflow-v0 + # Use the following to fall back to and build on v0 when bumping to v1 + # If the cache need to be cleared, remove this when bumping key version + # restore-keys: | + # templateflow-v0 + - name: Initialize templateflow + if: steps.tf-cache-restore.outputs.cache-hit != 'true' + run: | + uvx templateflow update --no-overwrite + + - name: Install tox + run: | + uv tool install tox --with=tox-uv --with=tox-gh-actions + - name: Show tox config + run: tox c + - name: Run tox + run: tox -v --exit-and-dump-after 1200 + - uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + if: ${{ always() }} + + test-packages: + runs-on: ${{ matrix.os }} + needs: [build] + strategy: + matrix: + os: ["ubuntu-latest"] + python-version: ["3.12"] + + env: + DEPENDS: ${{ matrix.dependencies }} + + steps: + - name: Download packages built by build-and-inspect-python-package + uses: actions/download-artifact@v4 + with: + pattern: Packages-* + path: dist + - run: ls -lR + + - name: Install the latest version of uv + uses: astral-sh/setup-uv@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Restore cached templateflow + id: tf-cache-restore + uses: actions/cache@v4 + with: + path: /tmp/templateflow + key: templateflow-v0 + # Use the following to fall back to and build on v0 when bumping to v1 + # If the cache need to be cleared, remove this when bumping key version + # restore-keys: | + # templateflow-v0 + - name: Check wrapper version + run: | + echo n | uvx --from=$( ls dist/*/smriprep_docker*.whl ) smriprep-docker --version + + - name: Unpack sdist + run: | + tar --strip-components=1 -xzf dist/*/smriprep-*.tar.gz + + - name: Install tox + run: | + uv tool install tox --with=tox-uv --with=tox-gh-actions + - name: Show tox config + run: tox c + - name: Run tox + run: tox -v --exit-and-dump-after 1200 + - uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + if: ${{ always() }} + + publish: + name: Publish released package to pypi.org + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + runs-on: ubuntu-latest + environment: PyPI + needs: [test, test-packages] + permissions: + attestations: write + id-token: write + + steps: + - name: Download packages built by build-and-inspect-python-package + uses: actions/download-artifact@v4 + with: + name: Packages + path: dist + + - name: Upload package to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + checks: + runs-on: "ubuntu-latest" + continue-on-error: true + strategy: + matrix: + check: ["style", "spellcheck"] + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Install the latest version of uv + uses: astral-sh/setup-uv@v4 + - name: Install tox + run: uv tool install tox --with=tox-uv + - name: Show tox config + run: tox c -e ${{ matrix.check }} + - name: Run check + run: tox -e ${{ matrix.check }} diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml deleted file mode 100644 index 2e37dd8637..0000000000 --- a/.github/workflows/pythonpackage.yml +++ /dev/null @@ -1,126 +0,0 @@ -name: Stable tests - -on: - push: - branches: [ '*' ] - tags: [ '*' ] - pull_request: - branches: [ master, 'maint/*', 'next' ] - schedule: - - cron: '0 0 * * *' - -defaults: - run: - shell: bash - -concurrency: - group: python-${{ github.ref }} - cancel-in-progress: true - -permissions: - contents: read - -jobs: - check_if_skip: - runs-on: ubuntu-latest - outputs: - commit_message: ${{ steps.get_commit_message.outputs.commit_message }} - steps: - - name: Get repo - uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - - name: Print head git commit message - id: get_commit_message - run: | - if [[ -z "$COMMIT_MSG" ]]; then - COMMIT_MSG=$(git show -s --format=%s) - else - COMMIT_MSG=$(echo $COMMIT_MSG | head -n 1) - fi - echo $COMMIT_MSG - echo "commit_message=$COMMIT_MSG" >> $GITHUB_OUTPUT - env: - COMMIT_MSG: ${{ github.event.head_commit.message }} - - build: - needs: check_if_skip - if: "!contains(needs.check_if_skip.outputs.commit_message, '[skip ci]')" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Display Python version - run: python -c "import sys; print(sys.version)" - - name: Build smriprep - run: pipx run build - - name: Check distributions - run: pipx run twine check dist/* - - uses: actions/upload-artifact@v4 - with: - name: dist - path: dist/ - - test: - needs: [build] - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10", "3.11", "3.12"] - install: [repo] - include: - - python-version: "3.11" - install: sdist - - python-version: "3.11" - install: wheel - - python-version: "3.11" - install: editable - - env: - INSTALL_TYPE: ${{ matrix.install }} - FSLOUTPUTTYPE: NIFTI_GZ - - steps: - - uses: actions/checkout@v4 - if: matrix.install == 'repo' || matrix.install == 'editable' - - name: Fetch packages - uses: actions/download-artifact@v4 - with: - name: dist - path: dist/ - if: matrix.install == 'sdist' || matrix.install == 'wheel' - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - name: Select archive - run: | - if [ "$INSTALL_TYPE" = "sdist" ]; then - ARCHIVE=$( ls dist/*.tar.gz ) - elif [ "$INSTALL_TYPE" = "wheel" ]; then - ARCHIVE=$( ls dist/*.whl ) - elif [ "$INSTALL_TYPE" = "repo" ]; then - ARCHIVE="." - elif [ "$INSTALL_TYPE" = "editable" ]; then - ARCHIVE="-e ." - fi - echo "ARCHIVE=$ARCHIVE" >> $GITHUB_ENV - - name: Install package - run: python -m pip install $ARCHIVE - - name: Install test dependencies - run: python -m pip install "smriprep[tests]" - - name: Run tests - run: pytest -sv --doctest-modules --cov smriprep --pyargs smriprep - - uses: codecov/codecov-action@v4 - name: Submit to CodeCov - with: - token: ${{ secrets.CODECOV_TOKEN }} - - style: - if: "!contains(github.event.head_commit.message, '[skip ci]')" - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - run: pipx run ruff check smriprep - - run: pipx run ruff format --diff smriprep diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ef5b3fb099..df6970d67a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: trailing-whitespace exclude: '.gitignore|.*\.gii$' @@ -11,10 +11,14 @@ repos: - id: check-toml - id: check-json - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.5.3 + rev: v0.8.2 hooks: - id: ruff - args: [ --fix ] + args: [--fix] - id: ruff-format - id: ruff - args: [ --select, ISC001, --fix ] + args: [--select, ISC001, --fix] + - repo: https://github.com/woodruffw/zizmor-pre-commit + rev: v0.8.0 + hooks: + - id: zizmor diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index d36f61b080..261a99c6d5 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -6,7 +6,7 @@ In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal +level of experience, education, socioeconomic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards diff --git a/Dockerfile b/Dockerfile index 986380a701..3435815579 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,12 +28,10 @@ ARG BASE_IMAGE=ubuntu:jammy-20240125 # # Build wheel # -FROM python:slim AS src -RUN pip install build -RUN apt-get update && \ - apt-get install -y --no-install-recommends git +FROM ghcr.io/astral-sh/uv:python3.13-alpine AS src +RUN apk add --no-cache git COPY . /src -RUN python -m build /src +RUN uvx --from=build pyproject-build --installer=uv /src # # Download stages diff --git a/docs/conf.py b/docs/conf.py index eb98e418c1..262ec9f09c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -229,7 +229,7 @@ # -- Extension configuration ------------------------------------------------- -apidoc_module_dir = '../smriprep' +apidoc_module_dir = '../src/smriprep' apidoc_output_dir = 'api' apidoc_excluded_paths = [ 'conftest.py', @@ -254,7 +254,7 @@ 'python': ('https://docs.python.org/3/', None), 'numpy': ('https://numpy.org/doc/stable/', None), 'scipy': ('https://docs.scipy.org/doc/scipy/', None), - 'matplotlib': ('https://matplotlib.org/', None), + 'matplotlib': ('https://matplotlib.org/stable/', None), 'bids': ('https://bids-standard.github.io/pybids/', None), 'nibabel': ('https://nipy.org/nibabel/', None), 'nipype': ('https://nipype.readthedocs.io/en/latest/', None), diff --git a/pyproject.toml b/pyproject.toml index 9d2fccb28c..9b9a0c1b01 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,19 +19,19 @@ classifiers = [ license = {file = "LICENSE"} requires-python = ">=3.10" dependencies = [ - "acres", - "indexed_gzip >= 0.8.8", - "lockfile", - "looseversion", - "matplotlib >= 2.2.0", + "acres >= 0.2", + "indexed_gzip >= 1.7", + "lockfile >= 0.12.2", + "looseversion >= 1.3.0", + "matplotlib >= 3.5", "nibabel >= 4.0.1", - "nipype >= 1.7.0", - "niworkflows >= 1.11.0", - "numpy", - "packaging", - "pybids >= 0.11.1", - "pyyaml", - "templateflow >= 24.1", + "nipype >= 1.8.5", + "niworkflows >= 1.12.0", + "numpy >= 1.24", + "packaging >= 24", + "pybids >= 0.16", + "pyyaml >= 6.0", + "templateflow >= 24.2", ] dynamic = ["version"] @@ -56,10 +56,11 @@ doc = [ ] duecredit = ["duecredit"] test = [ - "coverage", - "pytest", - "pytest-cov", + "coverage[toml] >= 5.2.1", + "pytest >= 8.1", + "pytest-cov >= 2.11", "pytest-env", + "pytest-xdist >= 2.5", ] style = ["flake8"] # Aliases @@ -81,9 +82,9 @@ allow-direct-references = true exclude = [".git_archival.txt"] # No longer needed in sdist [tool.hatch.build.targets.wheel] -packages = ["smriprep"] +packages = ["src/smriprep"] exclude = [ - "smriprep/data/tests/work", # Large test data directory + "src/smriprep/data/tests/work", # Large test data directory ] ## The following two sections configure setuptools_scm in the hatch way @@ -92,7 +93,7 @@ exclude = [ source = "vcs" [tool.hatch.build.hooks.vcs] -version-file = "smriprep/_version.py" +version-file = "src/smriprep/_version.py" # # Developer tool configurations @@ -116,11 +117,22 @@ per-file-ignores = [ ] [tool.pytest.ini_options] -minversion = "7" +minversion = "8" +testpaths = ["src"] log_cli_level = "INFO" xfail_strict = true norecursedirs = [".git"] -addopts = ["-svx", "--doctest-modules", "-ra", "--strict-config", "--strict-markers"] +addopts = [ + "-svx", + "-ra", + "--strict-config", + "--strict-markers", + "--doctest-modules", + # Config pytest-cov + "--cov=src/smriprep", + "--cov-report=xml", + "--cov-config=pyproject.toml", +] doctest_optionflags = "ALLOW_UNICODE NORMALIZE_WHITESPACE ELLIPSIS" env = "PYTHONHASHSEED=0" filterwarnings = ["ignore::DeprecationWarning"] @@ -186,3 +198,6 @@ inline-quotes = "single" [tool.ruff.format] quote-style = "single" + +[tool.codespell] +skip = "*/data/*,*/docs/_build/*,*.svg,*/docs/_static/*" diff --git a/smriprep/__about__.py b/src/smriprep/__about__.py similarity index 100% rename from smriprep/__about__.py rename to src/smriprep/__about__.py diff --git a/smriprep/__init__.py b/src/smriprep/__init__.py similarity index 100% rename from smriprep/__init__.py rename to src/smriprep/__init__.py diff --git a/smriprep/__main__.py b/src/smriprep/__main__.py similarity index 100% rename from smriprep/__main__.py rename to src/smriprep/__main__.py diff --git a/smriprep/cli/__init__.py b/src/smriprep/cli/__init__.py similarity index 100% rename from smriprep/cli/__init__.py rename to src/smriprep/cli/__init__.py diff --git a/smriprep/cli/run.py b/src/smriprep/cli/run.py similarity index 100% rename from smriprep/cli/run.py rename to src/smriprep/cli/run.py diff --git a/smriprep/conf/__init__.py b/src/smriprep/conf/__init__.py similarity index 100% rename from smriprep/conf/__init__.py rename to src/smriprep/conf/__init__.py diff --git a/smriprep/conftest.py b/src/smriprep/conftest.py similarity index 100% rename from smriprep/conftest.py rename to src/smriprep/conftest.py diff --git a/smriprep/data/__init__.py b/src/smriprep/data/__init__.py similarity index 100% rename from smriprep/data/__init__.py rename to src/smriprep/data/__init__.py diff --git a/smriprep/data/atlases/L.atlasroi.32k_fs_LR.shape.gii b/src/smriprep/data/atlases/L.atlasroi.32k_fs_LR.shape.gii similarity index 100% rename from smriprep/data/atlases/L.atlasroi.32k_fs_LR.shape.gii rename to src/smriprep/data/atlases/L.atlasroi.32k_fs_LR.shape.gii diff --git a/smriprep/data/atlases/L.atlasroi.59k_fs_LR.shape.gii b/src/smriprep/data/atlases/L.atlasroi.59k_fs_LR.shape.gii similarity index 100% rename from smriprep/data/atlases/L.atlasroi.59k_fs_LR.shape.gii rename to src/smriprep/data/atlases/L.atlasroi.59k_fs_LR.shape.gii diff --git a/smriprep/data/atlases/L.refsulc.164k_fs_LR.shape.gii b/src/smriprep/data/atlases/L.refsulc.164k_fs_LR.shape.gii similarity index 100% rename from smriprep/data/atlases/L.refsulc.164k_fs_LR.shape.gii rename to src/smriprep/data/atlases/L.refsulc.164k_fs_LR.shape.gii diff --git a/smriprep/data/atlases/R.atlasroi.32k_fs_LR.shape.gii b/src/smriprep/data/atlases/R.atlasroi.32k_fs_LR.shape.gii similarity index 100% rename from smriprep/data/atlases/R.atlasroi.32k_fs_LR.shape.gii rename to src/smriprep/data/atlases/R.atlasroi.32k_fs_LR.shape.gii diff --git a/smriprep/data/atlases/R.atlasroi.59k_fs_LR.shape.gii b/src/smriprep/data/atlases/R.atlasroi.59k_fs_LR.shape.gii similarity index 100% rename from smriprep/data/atlases/R.atlasroi.59k_fs_LR.shape.gii rename to src/smriprep/data/atlases/R.atlasroi.59k_fs_LR.shape.gii diff --git a/smriprep/data/atlases/R.refsulc.164k_fs_LR.shape.gii b/src/smriprep/data/atlases/R.refsulc.164k_fs_LR.shape.gii similarity index 100% rename from smriprep/data/atlases/R.refsulc.164k_fs_LR.shape.gii rename to src/smriprep/data/atlases/R.refsulc.164k_fs_LR.shape.gii diff --git a/smriprep/data/atlases/fs_L/fs_L-to-fs_LR_fsaverage.L_LR.spherical_std.164k_fs_L.surf.gii b/src/smriprep/data/atlases/fs_L/fs_L-to-fs_LR_fsaverage.L_LR.spherical_std.164k_fs_L.surf.gii similarity index 100% rename from smriprep/data/atlases/fs_L/fs_L-to-fs_LR_fsaverage.L_LR.spherical_std.164k_fs_L.surf.gii rename to src/smriprep/data/atlases/fs_L/fs_L-to-fs_LR_fsaverage.L_LR.spherical_std.164k_fs_L.surf.gii diff --git a/smriprep/data/atlases/fs_L/fsaverage.L.sphere.164k_fs_L.surf.gii b/src/smriprep/data/atlases/fs_L/fsaverage.L.sphere.164k_fs_L.surf.gii similarity index 100% rename from smriprep/data/atlases/fs_L/fsaverage.L.sphere.164k_fs_L.surf.gii rename to src/smriprep/data/atlases/fs_L/fsaverage.L.sphere.164k_fs_L.surf.gii diff --git a/smriprep/data/atlases/fs_R/fs_R-to-fs_LR_fsaverage.R_LR.spherical_std.164k_fs_R.surf.gii b/src/smriprep/data/atlases/fs_R/fs_R-to-fs_LR_fsaverage.R_LR.spherical_std.164k_fs_R.surf.gii similarity index 100% rename from smriprep/data/atlases/fs_R/fs_R-to-fs_LR_fsaverage.R_LR.spherical_std.164k_fs_R.surf.gii rename to src/smriprep/data/atlases/fs_R/fs_R-to-fs_LR_fsaverage.R_LR.spherical_std.164k_fs_R.surf.gii diff --git a/smriprep/data/atlases/fs_R/fsaverage.R.sphere.164k_fs_R.surf.gii b/src/smriprep/data/atlases/fs_R/fsaverage.R.sphere.164k_fs_R.surf.gii similarity index 100% rename from smriprep/data/atlases/fs_R/fsaverage.R.sphere.164k_fs_R.surf.gii rename to src/smriprep/data/atlases/fs_R/fsaverage.R.sphere.164k_fs_R.surf.gii diff --git a/smriprep/data/atlases/fsaverage.L_LR.spherical_std.164k_fs_LR.surf.gii b/src/smriprep/data/atlases/fsaverage.L_LR.spherical_std.164k_fs_LR.surf.gii similarity index 100% rename from smriprep/data/atlases/fsaverage.L_LR.spherical_std.164k_fs_LR.surf.gii rename to src/smriprep/data/atlases/fsaverage.L_LR.spherical_std.164k_fs_LR.surf.gii diff --git a/smriprep/data/atlases/fsaverage.R_LR.spherical_std.164k_fs_LR.surf.gii b/src/smriprep/data/atlases/fsaverage.R_LR.spherical_std.164k_fs_LR.surf.gii similarity index 100% rename from smriprep/data/atlases/fsaverage.R_LR.spherical_std.164k_fs_LR.surf.gii rename to src/smriprep/data/atlases/fsaverage.R_LR.spherical_std.164k_fs_LR.surf.gii diff --git a/smriprep/data/boilerplate.bib b/src/smriprep/data/boilerplate.bib similarity index 100% rename from smriprep/data/boilerplate.bib rename to src/smriprep/data/boilerplate.bib diff --git a/smriprep/data/io_spec.json b/src/smriprep/data/io_spec.json similarity index 100% rename from smriprep/data/io_spec.json rename to src/smriprep/data/io_spec.json diff --git a/smriprep/data/itkIdentityTransform.txt b/src/smriprep/data/itkIdentityTransform.txt similarity index 100% rename from smriprep/data/itkIdentityTransform.txt rename to src/smriprep/data/itkIdentityTransform.txt diff --git a/smriprep/data/msm/MSMSulcStrainFinalconf b/src/smriprep/data/msm/MSMSulcStrainFinalconf similarity index 100% rename from smriprep/data/msm/MSMSulcStrainFinalconf rename to src/smriprep/data/msm/MSMSulcStrainFinalconf diff --git a/smriprep/data/msm/MSMSulcStrainSloppyconf b/src/smriprep/data/msm/MSMSulcStrainSloppyconf similarity index 100% rename from smriprep/data/msm/MSMSulcStrainSloppyconf rename to src/smriprep/data/msm/MSMSulcStrainSloppyconf diff --git a/smriprep/data/tests/dataset_description.json b/src/smriprep/data/tests/dataset_description.json similarity index 100% rename from smriprep/data/tests/dataset_description.json rename to src/smriprep/data/tests/dataset_description.json diff --git a/smriprep/interfaces/__init__.py b/src/smriprep/interfaces/__init__.py similarity index 100% rename from smriprep/interfaces/__init__.py rename to src/smriprep/interfaces/__init__.py diff --git a/smriprep/interfaces/cifti.py b/src/smriprep/interfaces/cifti.py similarity index 100% rename from smriprep/interfaces/cifti.py rename to src/smriprep/interfaces/cifti.py diff --git a/smriprep/interfaces/conftest.py b/src/smriprep/interfaces/conftest.py similarity index 100% rename from smriprep/interfaces/conftest.py rename to src/smriprep/interfaces/conftest.py diff --git a/smriprep/interfaces/freesurfer.py b/src/smriprep/interfaces/freesurfer.py similarity index 100% rename from smriprep/interfaces/freesurfer.py rename to src/smriprep/interfaces/freesurfer.py diff --git a/smriprep/interfaces/gifti.py b/src/smriprep/interfaces/gifti.py similarity index 100% rename from smriprep/interfaces/gifti.py rename to src/smriprep/interfaces/gifti.py diff --git a/smriprep/interfaces/msm.py b/src/smriprep/interfaces/msm.py similarity index 100% rename from smriprep/interfaces/msm.py rename to src/smriprep/interfaces/msm.py diff --git a/smriprep/interfaces/reports.py b/src/smriprep/interfaces/reports.py similarity index 100% rename from smriprep/interfaces/reports.py rename to src/smriprep/interfaces/reports.py diff --git a/smriprep/interfaces/surf.py b/src/smriprep/interfaces/surf.py similarity index 100% rename from smriprep/interfaces/surf.py rename to src/smriprep/interfaces/surf.py diff --git a/smriprep/interfaces/templateflow.py b/src/smriprep/interfaces/templateflow.py similarity index 97% rename from smriprep/interfaces/templateflow.py rename to src/smriprep/interfaces/templateflow.py index 7bb41b12f8..48bf1b65b7 100644 --- a/smriprep/interfaces/templateflow.py +++ b/src/smriprep/interfaces/templateflow.py @@ -44,8 +44,11 @@ class _TemplateFlowSelectInputSpec(BaseInterfaceInputSpec): atlas = InputMultiObject(traits.Str, desc='Specify an atlas') cohort = InputMultiObject(traits.Either(traits.Str, traits.Int), desc='Specify a cohort') resolution = InputMultiObject(traits.Int, desc='Specify a template resolution index') - template_spec = traits.DictStrAny( - {'atlas': None, 'cohort': None}, usedefault=True, desc='Template specifications' + template_spec = traits.Dict( + traits.Str, + value={'atlas': None, 'cohort': None}, + usedefault=True, + desc='Template specifications', ) diff --git a/smriprep/interfaces/tests/__init__.py b/src/smriprep/interfaces/tests/__init__.py similarity index 100% rename from smriprep/interfaces/tests/__init__.py rename to src/smriprep/interfaces/tests/__init__.py diff --git a/smriprep/interfaces/tests/data/__init__.py b/src/smriprep/interfaces/tests/data/__init__.py similarity index 100% rename from smriprep/interfaces/tests/data/__init__.py rename to src/smriprep/interfaces/tests/data/__init__.py diff --git a/smriprep/interfaces/tests/data/lh.sphere.reg.surf.gii b/src/smriprep/interfaces/tests/data/lh.sphere.reg.surf.gii similarity index 100% rename from smriprep/interfaces/tests/data/lh.sphere.reg.surf.gii rename to src/smriprep/interfaces/tests/data/lh.sphere.reg.surf.gii diff --git a/smriprep/interfaces/tests/data/lh.white b/src/smriprep/interfaces/tests/data/lh.white similarity index 100% rename from smriprep/interfaces/tests/data/lh.white rename to src/smriprep/interfaces/tests/data/lh.white diff --git a/smriprep/interfaces/tests/data/sub-01_desc-warped_T1w.nii.gz b/src/smriprep/interfaces/tests/data/sub-01_desc-warped_T1w.nii.gz similarity index 100% rename from smriprep/interfaces/tests/data/sub-01_desc-warped_T1w.nii.gz rename to src/smriprep/interfaces/tests/data/sub-01_desc-warped_T1w.nii.gz diff --git a/smriprep/interfaces/tests/data/sub-01_hemi-L_midthickness.surf.gii b/src/smriprep/interfaces/tests/data/sub-01_hemi-L_midthickness.surf.gii similarity index 100% rename from smriprep/interfaces/tests/data/sub-01_hemi-L_midthickness.surf.gii rename to src/smriprep/interfaces/tests/data/sub-01_hemi-L_midthickness.surf.gii diff --git a/smriprep/interfaces/tests/data/sub-01_hemi-L_sphere.surf.gii b/src/smriprep/interfaces/tests/data/sub-01_hemi-L_sphere.surf.gii similarity index 100% rename from smriprep/interfaces/tests/data/sub-01_hemi-L_sphere.surf.gii rename to src/smriprep/interfaces/tests/data/sub-01_hemi-L_sphere.surf.gii diff --git a/smriprep/interfaces/tests/data/sub-01_hemi-L_sulc.shape.gii b/src/smriprep/interfaces/tests/data/sub-01_hemi-L_sulc.shape.gii similarity index 100% rename from smriprep/interfaces/tests/data/sub-01_hemi-L_sulc.shape.gii rename to src/smriprep/interfaces/tests/data/sub-01_hemi-L_sulc.shape.gii diff --git a/smriprep/interfaces/tests/data/sub-fsaverage_res-4_desc-cropped_ribbon.nii.gz b/src/smriprep/interfaces/tests/data/sub-fsaverage_res-4_desc-cropped_ribbon.nii.gz similarity index 100% rename from smriprep/interfaces/tests/data/sub-fsaverage_res-4_desc-cropped_ribbon.nii.gz rename to src/smriprep/interfaces/tests/data/sub-fsaverage_res-4_desc-cropped_ribbon.nii.gz diff --git a/smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-L_desc-cropped_pialdist.nii.gz b/src/smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-L_desc-cropped_pialdist.nii.gz similarity index 100% rename from smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-L_desc-cropped_pialdist.nii.gz rename to src/smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-L_desc-cropped_pialdist.nii.gz diff --git a/smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-L_desc-cropped_wmdist.nii.gz b/src/smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-L_desc-cropped_wmdist.nii.gz similarity index 100% rename from smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-L_desc-cropped_wmdist.nii.gz rename to src/smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-L_desc-cropped_wmdist.nii.gz diff --git a/smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-R_desc-cropped_pialdist.nii.gz b/src/smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-R_desc-cropped_pialdist.nii.gz similarity index 100% rename from smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-R_desc-cropped_pialdist.nii.gz rename to src/smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-R_desc-cropped_pialdist.nii.gz diff --git a/smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-R_desc-cropped_wmdist.nii.gz b/src/smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-R_desc-cropped_wmdist.nii.gz similarity index 100% rename from smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-R_desc-cropped_wmdist.nii.gz rename to src/smriprep/interfaces/tests/data/sub-fsaverage_res-4_hemi-R_desc-cropped_wmdist.nii.gz diff --git a/smriprep/interfaces/tests/data/tpl-fsLR_hemi-L_den-32k_sphere.surf.gii b/src/smriprep/interfaces/tests/data/tpl-fsLR_hemi-L_den-32k_sphere.surf.gii similarity index 100% rename from smriprep/interfaces/tests/data/tpl-fsLR_hemi-L_den-32k_sphere.surf.gii rename to src/smriprep/interfaces/tests/data/tpl-fsLR_hemi-L_den-32k_sphere.surf.gii diff --git a/smriprep/interfaces/tests/data/tpl-fsaverage_hemi-L_den-164k_desc-std_sphere.surf.gii b/src/smriprep/interfaces/tests/data/tpl-fsaverage_hemi-L_den-164k_desc-std_sphere.surf.gii similarity index 100% rename from smriprep/interfaces/tests/data/tpl-fsaverage_hemi-L_den-164k_desc-std_sphere.surf.gii rename to src/smriprep/interfaces/tests/data/tpl-fsaverage_hemi-L_den-164k_desc-std_sphere.surf.gii diff --git a/smriprep/interfaces/tests/data/tpl-fsaverage_hemi-L_den-164k_sulc.shape.gii b/src/smriprep/interfaces/tests/data/tpl-fsaverage_hemi-L_den-164k_sulc.shape.gii similarity index 100% rename from smriprep/interfaces/tests/data/tpl-fsaverage_hemi-L_den-164k_sulc.shape.gii rename to src/smriprep/interfaces/tests/data/tpl-fsaverage_hemi-L_den-164k_sulc.shape.gii diff --git a/smriprep/interfaces/tests/test_surf.py b/src/smriprep/interfaces/tests/test_surf.py similarity index 100% rename from smriprep/interfaces/tests/test_surf.py rename to src/smriprep/interfaces/tests/test_surf.py diff --git a/smriprep/interfaces/workbench.py b/src/smriprep/interfaces/workbench.py similarity index 100% rename from smriprep/interfaces/workbench.py rename to src/smriprep/interfaces/workbench.py diff --git a/smriprep/utils/__init__.py b/src/smriprep/utils/__init__.py similarity index 100% rename from smriprep/utils/__init__.py rename to src/smriprep/utils/__init__.py diff --git a/smriprep/utils/bids.py b/src/smriprep/utils/bids.py similarity index 100% rename from smriprep/utils/bids.py rename to src/smriprep/utils/bids.py diff --git a/smriprep/utils/misc.py b/src/smriprep/utils/misc.py similarity index 100% rename from smriprep/utils/misc.py rename to src/smriprep/utils/misc.py diff --git a/smriprep/utils/tests/__init__.py b/src/smriprep/utils/tests/__init__.py similarity index 100% rename from smriprep/utils/tests/__init__.py rename to src/smriprep/utils/tests/__init__.py diff --git a/smriprep/utils/tests/derivatives.yml b/src/smriprep/utils/tests/derivatives.yml similarity index 98% rename from smriprep/utils/tests/derivatives.yml rename to src/smriprep/utils/tests/derivatives.yml index 97cda9e19c..35330385ab 100644 --- a/smriprep/utils/tests/derivatives.yml +++ b/src/smriprep/utils/tests/derivatives.yml @@ -98,4 +98,4 @@ dataset_description: extension: .shape.gii - suffix: sulc hemi: R - extension: .shape.gii \ No newline at end of file + extension: .shape.gii diff --git a/smriprep/utils/tests/test_bids.py b/src/smriprep/utils/tests/test_bids.py similarity index 100% rename from smriprep/utils/tests/test_bids.py rename to src/smriprep/utils/tests/test_bids.py diff --git a/smriprep/utils/tests/test_misc.py b/src/smriprep/utils/tests/test_misc.py similarity index 100% rename from smriprep/utils/tests/test_misc.py rename to src/smriprep/utils/tests/test_misc.py diff --git a/smriprep/workflows/__init__.py b/src/smriprep/workflows/__init__.py similarity index 100% rename from smriprep/workflows/__init__.py rename to src/smriprep/workflows/__init__.py diff --git a/smriprep/workflows/anatomical.py b/src/smriprep/workflows/anatomical.py similarity index 100% rename from smriprep/workflows/anatomical.py rename to src/smriprep/workflows/anatomical.py diff --git a/smriprep/workflows/base.py b/src/smriprep/workflows/base.py similarity index 100% rename from smriprep/workflows/base.py rename to src/smriprep/workflows/base.py diff --git a/smriprep/workflows/fit/__init__.py b/src/smriprep/workflows/fit/__init__.py similarity index 100% rename from smriprep/workflows/fit/__init__.py rename to src/smriprep/workflows/fit/__init__.py diff --git a/smriprep/workflows/fit/registration.py b/src/smriprep/workflows/fit/registration.py similarity index 100% rename from smriprep/workflows/fit/registration.py rename to src/smriprep/workflows/fit/registration.py diff --git a/smriprep/workflows/outputs.py b/src/smriprep/workflows/outputs.py similarity index 100% rename from smriprep/workflows/outputs.py rename to src/smriprep/workflows/outputs.py diff --git a/smriprep/workflows/surfaces.py b/src/smriprep/workflows/surfaces.py similarity index 100% rename from smriprep/workflows/surfaces.py rename to src/smriprep/workflows/surfaces.py diff --git a/smriprep/workflows/tests/__init__.py b/src/smriprep/workflows/tests/__init__.py similarity index 100% rename from smriprep/workflows/tests/__init__.py rename to src/smriprep/workflows/tests/__init__.py diff --git a/smriprep/workflows/tests/test_anatomical.py b/src/smriprep/workflows/tests/test_anatomical.py similarity index 100% rename from smriprep/workflows/tests/test_anatomical.py rename to src/smriprep/workflows/tests/test_anatomical.py diff --git a/smriprep/workflows/tests/test_surfaces.py b/src/smriprep/workflows/tests/test_surfaces.py similarity index 100% rename from smriprep/workflows/tests/test_surfaces.py rename to src/smriprep/workflows/tests/test_surfaces.py diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000000..d240fb4f28 --- /dev/null +++ b/tox.ini @@ -0,0 +1,125 @@ +[tox] +requires = + tox>=4 + tox-uv +envlist = + py3{10,11,12,13}-latest + py310-min + py3{11,12,13}-pre +skip_missing_interpreters = true + +# Configuration that allows us to split tests across GitHub runners effectively +[gh-actions] +python = + 3.10: py310 + 3.11: py311 + 3.12: py312 + 3.13: py313 + +[gh-actions:env] +DEPENDS = + min: min + latest: latest + pre: pre + +[testenv] +description = Pytest with coverage +labels = test +pip_pre = + pre: true +pass_env = + TEMPLATEFLOW_HOME + NO_ET + # Freesurfer variables searched for + FREESURFER_HOME + SUBJECTS_DIR + FS_LICENSE + # CI variables + TEST_DATA_HOME + TEST_OUTPUT_DIR + TEST_WORK_DIR + FMRIPREP_REGRESSION_SOURCE + CACHED_WORK_DIRECTORY + # CircleCI-specific + CIRCLE_NPROCS + SAVE_CIRCLE_ARTIFACTS + # getpass.getuser() sources for Windows: + LOGNAME + USER + LNAME + USERNAME + # Pass user color preferences through + PY_COLORS + FORCE_COLOR + NO_COLOR + CLICOLOR + CLICOLOR_FORCE + PYTHON_GIL +deps = + py313: traits @ git+https://github.com/enthought/traits.git@10954eb +extras = tests +setenv = + pre: PIP_EXTRA_INDEX_URL=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple + pre: UV_EXTRA_INDEX_URL=https://pypi.anaconda.org/scientific-python-nightly-wheels/simple + FSLOUTPUTTYPE=NIFTI_GZ +uv_resolution = + min: lowest-direct + +commands = + pytest --durations=20 --durations-min=1.0 --cov-report term-missing {posargs:-n auto} + +[testenv:style] +description = Check our style guide +labels = check +deps = + ruff +skip_install = true +commands = + ruff check --diff + ruff format --diff + +[testenv:style-fix] +description = Auto-apply style guide to the extent possible +labels = pre-release +deps = + ruff +skip_install = true +commands = + ruff check --fix + ruff format + ruff check --select ISC001 + +[testenv:spellcheck] +description = Check spelling +labels = check +deps = + codespell[toml] +skip_install = true +commands = + codespell . {posargs} + +[testenv:build{,-strict}] +labels = + check + pre-release +deps = + build + twine +skip_install = true +set_env = + # Ignore specific known warnings: + # https://github.com/pypa/pip/issues/11684 + # https://github.com/pypa/pip/issues/12243 + strict: PYTHONWARNINGS=error,once:pkg_resources is deprecated as an API.:DeprecationWarning:pip._internal.metadata.importlib._envs,once:Unimplemented abstract methods {'locate_file'}:DeprecationWarning:pip._internal.metadata.importlib._dists +commands = + python -m build + python -m twine check dist/* + +[testenv:publish] +depends = build +labels = release +deps = + twine +skip_install = true +commands = + python -m twine upload dist/* diff --git a/wrapper/setup.cfg b/wrapper/setup.cfg index fd17c74b00..65a188cd05 100644 --- a/wrapper/setup.cfg +++ b/wrapper/setup.cfg @@ -7,15 +7,13 @@ maintainer_email = nipreps@gmail.com license = 3-clause BSD description = A wrapper for generating Docker commands using regular sMRIPrep syntax long_description = file:README.rst -long_description_content_type = text/x-rst; charset=UTF-8 +long_description_content_type = text/x-rst classifiers = Development Status :: 4 - Beta Intended Audience :: Science/Research License :: OSI Approved :: BSD License - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3.5 - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 + Programming Language :: Python :: 2 + Programming Language :: Python :: 3 [options] py_modules = smriprep_docker