diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index dc05d30..0000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: publish - -on: - # Trigger this workflow when a release is created. - release: - types: - - published - -permissions: - # Allow checkout of the project. - contents: read - -env: - # Default Python version on which jobs are run. - DEFAULT_PYTHON_VERSION: '3.9' - -jobs: - publish: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v4 - with: - python-version: ${{ env.DEFAULT_PYTHON_VERSION }} - - name: Install build frontend - run: python -m pip install build - - name: Build distribution package - run: python -m build - - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - password: ${{ secrets.PYPI_API_TOKEN }} diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml index 979871c..5d52a1d 100644 --- a/.github/workflows/pythonpackage.yml +++ b/.github/workflows/pythonpackage.yml @@ -6,28 +6,37 @@ name: Python package # Set once env: SUBPACKAGE: nipype1 + FSLCONDA: https://fsl.fmrib.ox.ac.uk/fsldownloads/fslconda/public/ on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +defaults: + run: + shell: bash -el {0} jobs: devcheck: runs-on: ubuntu-latest strategy: matrix: - python-version: [ '3.7', '3.11' ] # Check oldest and newest versions - pip-flags: [ '', '--editable' ] + python-version: ["3.8", "3.12"] # Check oldest and newest versions + pip-flags: ["", "--editable"] pydra: - - 'pydra' - - '--editable git+https://github.com/nipype/pydra.git#egg=pydra' + - "pydra" + - "--editable git+https://github.com/nipype/pydra.git#egg=pydra" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install build dependencies @@ -47,19 +56,24 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: [ '3.7', '3.8', '3.9', '3.10', '3.11' ] + python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + uses: conda-incubator/setup-miniconda@v3 with: python-version: ${{ matrix.python-version }} - - name: Set up NeuroDebian - run: bash <(wget -q -O- http://neuro.debian.net/_files/neurodebian-travis.sh) + mamba-version: "*" + channels: ${{ env.FSLCONDA }},conda-forge,defaults + channel-priority: true - name: Install FSL - run: sudo apt-get install -y fsl - - name: Install build dependencies + run: | + mamba install fsl-avwutils + mamba env config vars set FSLDIR="$CONDA_PREFIX" FSLOUTPUTTYPE="NIFTI_GZ" + # Hack because we're not doing a full FSL install + echo "6.0.7.9" > $CONDA_PREFIX/etc/fslversion + - name: Upgrade pip run: | python -m pip install --upgrade pip - name: Install task package @@ -69,34 +83,31 @@ jobs: python -c "import pydra as m; print(f'{m.__name__} {m.__version__} @ {m.__file__}')" - name: Test with pytest run: | - source /etc/fsl/fsl.sh pytest -sv --doctest-modules pydra/tasks/$SUBPACKAGE \ --cov pydra.tasks.$SUBPACKAGE --cov-report xml - - uses: codecov/codecov-action@v1 + - uses: codecov/codecov-action@v4 if: ${{ always() }} + with: + token: ${{ secrets.CODECOV_TOKEN }} - deploy: - needs: [ devcheck, test ] + build: runs-on: ubuntu-latest - strategy: - matrix: - python-version: [ '3.9' ] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: recursive fetch-depth: 0 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - name: Install build tools - run: python -m pip install build twine - - name: Build source and wheel distributions - run: python -m build - - name: Check distributions - run: twine check dist/* - - uses: actions/upload-artifact@v2 + - uses: hynek/build-and-inspect-python-package@v2 + + deploy: + needs: [build, devcheck, test] + runs-on: ubuntu-latest + permissions: + id-token: write + if: github.repository_owner == 'nipype' && github.event.action == 'published' + steps: + - uses: actions/download-artifact@v4 with: - name: distributions - path: dist/ + name: Packages + path: dist + - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.gitignore b/.gitignore index ef50f11..4dc2815 100644 --- a/.gitignore +++ b/.gitignore @@ -129,4 +129,4 @@ dmypy.json .pyre/ # Generated by flit_scm -_versions.py +_version.py diff --git a/pydra/tasks/nipype1/tests/__init__.py b/pydra/tasks/nipype1/tests/__init__.py index e69de29..6e98041 100644 --- a/pydra/tasks/nipype1/tests/__init__.py +++ b/pydra/tasks/nipype1/tests/__init__.py @@ -0,0 +1,18 @@ +import sys +from atexit import register +from contextlib import ExitStack +from functools import lru_cache + + +if sys.version_info < (3, 9): + from importlib_resources import as_file, files +else: + from importlib.resources import as_file, files + +_stack = ExitStack() +register(_stack.close) + + +@lru_cache +def load_resource(anchor, *parts) -> str: + return str(_stack.enter_context(as_file(files(anchor).joinpath(*parts)))) diff --git a/pydra/tasks/nipype1/tests/test_nipype1task.py b/pydra/tasks/nipype1/tests/test_nipype1task.py index 9a17c6e..5ceeb16 100644 --- a/pydra/tasks/nipype1/tests/test_nipype1task.py +++ b/pydra/tasks/nipype1/tests/test_nipype1task.py @@ -1,6 +1,6 @@ import pytest import shutil -from pkg_resources import resource_filename +from . import load_resource from nipype.interfaces import fsl import nipype.interfaces.utility as nutil @@ -12,7 +12,7 @@ def test_isolation(tmp_path): in_file = tmp_path / "orig/tpms_msk.nii.gz" in_file.parent.mkdir() - shutil.copyfile(resource_filename("nipype", "testing/data/tpms_msk.nii.gz"), in_file) + shutil.copyfile(load_resource("nipype", "testing/data/tpms_msk.nii.gz"), in_file) out_dir = tmp_path / "output" out_dir.mkdir() diff --git a/pydra/tasks/nipype1/utils.py b/pydra/tasks/nipype1/utils.py index 0be31c4..913403b 100644 --- a/pydra/tasks/nipype1/utils.py +++ b/pydra/tasks/nipype1/utils.py @@ -11,7 +11,7 @@ def traitedspec_to_specinfo(traitedspec): return pydra.specs.SpecInfo( name="Inputs", fields=[ - (name, attrs.field(metadata={"help_string": trait.desc})) + (name, attrs.field(metadata={"help_string": trait.desc}, type=ty.Any)) for name, trait in traitedspec.traits().items() if name in trait_names ], @@ -27,11 +27,11 @@ class Nipype1Task(pydra.engine.task.TaskBase): in Pydra Task outputs. >>> import pytest - >>> from pkg_resources import resource_filename + >>> from pydra.tasks.nipype1.tests import load_resource >>> from nipype.interfaces import fsl >>> if fsl.Info.version() is None: ... pytest.skip() - >>> img = resource_filename('nipype', 'testing/data/tpms_msk.nii.gz') + >>> img = load_resource('nipype', 'testing/data/tpms_msk.nii.gz') >>> from pydra.tasks.nipype1.utils import Nipype1Task >>> thresh = Nipype1Task(fsl.Threshold()) @@ -68,7 +68,7 @@ def __init__( ) self.output_spec = traitedspec_to_specinfo(interface._outputs()) - def _run_task(self): + def _run_task(self, environment=None): inputs = attrs.asdict(self.inputs, filter=lambda a, v: v is not attrs.NOTHING) node = nipype.Node(self._interface, base_dir=self.output_dir, name=self.name) node.inputs.trait_set(**inputs) diff --git a/pyproject.toml b/pyproject.toml index 7f97f7b..7fe2461 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "flit_scm:buildapi" name = "pydra-nipype1" description = "Tools for importing nipype 1.x interfaces into Pydra" readme = "README.md" -requires-python = ">=3.7" +requires-python = ">=3.8" dependencies = [ "pydra >=0.6.2", "nipype",