From ee1879b1a13e3c5ce058ce988714af624549f5e6 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Tue, 8 Mar 2022 15:21:57 +0100 Subject: [PATCH 01/38] STYL: Fix flake8 errors --- labs/pyradiomics-dcm/pyradiomics-dcm.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/labs/pyradiomics-dcm/pyradiomics-dcm.py b/labs/pyradiomics-dcm/pyradiomics-dcm.py index 8b459e97..e27eaca6 100644 --- a/labs/pyradiomics-dcm/pyradiomics-dcm.py +++ b/labs/pyradiomics-dcm/pyradiomics-dcm.py @@ -319,17 +319,18 @@ def saveJSONToFile(self, fileName): def main(): parser = argparse.ArgumentParser( - usage="%(prog)s --input-image --input-seg --output-sr \n\n" - + "Warning: This is a \"pyradiomics labs\" script, which means it is an experimental feature in development!\n" - + "The intent of this helper script is to enable pyradiomics feature extraction directly from/to DICOM data.\n" - + "The segmentation defining the region of interest must be defined as a DICOM Segmentation image.\n" - + "Support for DICOM Radiotherapy Structure Sets for defining region of interest may be added in the future.\n") + usage="""%(prog)s --input-image --input-seg --output-sr \n\n + +Warning: This is a \"pyradiomics labs\" script, which means it is an experimental feature in development! +The intent of this helper script is to enable pyradiomics feature extraction directly from/to DICOM data. +The segmentation defining the region of interest must be defined as a DICOM Segmentation image. +Support for DICOM Radiotherapy Structure Sets for defining region of interest may be added in the future.""") parser.add_argument( '--input-image-dir', dest="inputDICOMImageDir", metavar="", help="Path to the directory with the input DICOM series." - + " It is expected that a single series is corresponding to a single scalar volume.", + " It is expected that a single series is corresponding to a single scalar volume.", required=True) parser.add_argument( '--input-seg-file', @@ -363,8 +364,8 @@ def main(): dest="volumeReconstructor", metavar="", help="Choose the tool to be used for reconstructing image volume from the DICOM image series." - + " Allowed options are plastimatch or dcm2niix (should be installed on the system). plastimatch" - + " will be used by default.", + " Allowed options are plastimatch or dcm2niix (should be installed on the system). plastimatch" + " will be used by default.", choices=['plastimatch', 'dcm2niix'], default="plastimatch") parser.add_argument( @@ -377,7 +378,7 @@ def main(): '--correct-mask', dest="correctMask", help="Boolean flag argument. If present, PyRadiomics will attempt to resample the mask to the image" - + " geometry if the mask check fails.", + " geometry if the mask check fails.", action='store_true', default=False) From c4553fd74b5150f1dbe136cc07950672524cf224 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Tue, 8 Mar 2022 12:22:05 +0100 Subject: [PATCH 02/38] ENH: Add Python 3.8 and 3.9 support --- .circleci/config.yml | 34 ++++++++++++++++++++++++++++------ .travis.yml | 26 ++++++++++++++++++++------ appveyor.yml | 12 ++++++++++++ 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2b69d2dd..54b2e562 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -62,19 +62,31 @@ jobs: build-3.6: <<: *build_template docker: - - image: circleci/python:3.6-jessie + - image: cimg/python:3.6 user: root build-3.7: <<: *build_template docker: - - image: circleci/python:3.7 - user: root + - image: cimg/python:3.7 + user: root + + build-3.8: + <<: *build_template + docker: + - image: cimg/python:3.8 + user: root + + build-3.9: + <<: *build_template + docker: + - image: cimg/python:3.9 + user: root deploy: working_directory: /pyradiomics docker: - - image: circleci/python:3.6-jessie + - image: cimg/python:3.6 user: root steps: - run: @@ -84,7 +96,7 @@ jobs: - run: name: Setup SciKit-CI command: | - pip install scikit-ci==0.13.0 scikit-ci-addons==0.11.0 + pip install scikit-ci scikit-ci-addons ci_addons --install ../addons - run: name: Install @@ -118,7 +130,7 @@ jobs: deploy_conda: working_directory: /pyradiomics docker: - - image: circleci/python:3.6-jessie + - image: cimg/python:3.8 user: root steps: - run: @@ -144,6 +156,8 @@ jobs: conda build ./conda --python=3.5 --croot /conda-bld conda build ./conda --python=3.6 --croot /conda-bld conda build ./conda --python=3.7 --croot /conda-bld + conda build ./conda --python=3.8 --croot /conda-bld + conda build ./conda --python=3.9 --croot /conda-bld - run: name: Deploy Conda packages command: | @@ -162,16 +176,24 @@ workflows: <<: *build_job_template - build-3.7: <<: *build_job_template + - build-3.8: + <<: *build_job_template + - build-3.9: + <<: *build_job_template - test-notebooks: requires: - build-3.5 - build-3.6 - build-3.7 + - build-3.8 + - build-3.9 - deploy: &deploy_template requires: - build-3.5 - build-3.6 - build-3.7 + - build-3.8 + - build-3.9 filters: branches: ignore: diff --git a/.travis.yml b/.travis.yml index 3a0c0929..a078fcd5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,21 +8,33 @@ matrix: - os: osx language: generic env: - - PYTHON_VERSION=3.5.5 + - PYTHON_VERSION=3.5 - PYTHON_SHORT_VERSION=3.5 - os: osx language: generic env: - - PYTHON_VERSION=3.6.5 + - PYTHON_VERSION=3.6 - PYTHON_SHORT_VERSION=3.6 - os: osx language: generic env: - - PYTHON_VERSION=3.7.8 + - PYTHON_VERSION=3.7 - PYTHON_SHORT_VERSION=3.7 + - os: osx + language: generic + env: + - PYTHON_VERSION=3.8 + - PYTHON_SHORT_VERSI8ON=3.8 + + - os: osx + language: generic + env: + - PYTHON_VERSION=3.9 + - PYTHON_SHORT_VERSION=3.9 + before_cache: # Cleanup to avoid the cache to grow indefinitely as new package versions are released # see https://stackoverflow.com/questions/39930171/cache-brew-builds-with-travis-ci @@ -34,9 +46,11 @@ cache: - $HOME/Library/Caches/Homebrew # pyenv - $HOME/.pyenv_cache - - $HOME/.pyenv/versions/3.7.8 - - $HOME/.pyenv/versions/3.6.5 - - $HOME/.pyenv/versions/3.5.5 + - $HOME/.pyenv/versions/3.9 + - $HOME/.pyenv/versions/3.8 + - $HOME/.pyenv/versions/3.7 + - $HOME/.pyenv/versions/3.6 + - $HOME/.pyenv/versions/3.5 # scikit-ci-addons - $HOME/downloads diff --git a/appveyor.yml b/appveyor.yml index 39c7c1ab..0c443e67 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,6 +23,18 @@ environment: PYTHON_ARCH: "64" BLOCK: "0" + - PYTHON_DIR: "C:\\Python38-x64" + PYTHON_VERSION: "3.8.x" + PYTHON_SHORT_VERSION: "3.8" + PYTHON_ARCH: "64" + BLOCK: "0" + + - PYTHON_DIR: "C:\\Python38-x64" + PYTHON_VERSION: "3.8.x" + PYTHON_SHORT_VERSION: "3.8" + PYTHON_ARCH: "64" + BLOCK: "0" + init: - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - python -m pip install scikit-ci==0.13.0 scikit-ci-addons==0.11.0 From f769e3e5a565b7dab47d5990142a22fcad46a36d Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Tue, 8 Mar 2022 15:43:42 +0100 Subject: [PATCH 03/38] ENH: Fix Appveyor config --- appveyor.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 0c443e67..cc5c9481 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: "0.0.1.{build}" +version: "3.0.{build}" environment: matrix: @@ -30,14 +30,14 @@ environment: BLOCK: "0" - PYTHON_DIR: "C:\\Python38-x64" - PYTHON_VERSION: "3.8.x" - PYTHON_SHORT_VERSION: "3.8" + PYTHON_VERSION: "3.9.x" + PYTHON_SHORT_VERSION: "3.9" PYTHON_ARCH: "64" BLOCK: "0" init: - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - - python -m pip install scikit-ci==0.13.0 scikit-ci-addons==0.11.0 + - python -m pip install scikit-ci scikit-ci-addons - python -m ci_addons --install ../addons - python -m pip install twine @@ -70,6 +70,7 @@ deploy_script: - twine upload dist/*.whl -u %PYPI_USER% -p %PYPI_PASSWORD% - echo starting Anaconda deployment - SET PATH=C:\Miniconda-x64\Scripts;%PATH% + - conda config --set always_yes yes - ./conda/configure_conda.bat && conda build ./conda --python=%PYTHON_SHORT_VERSION% --croot C:/conda-bld - anaconda -t %ANACONDA_TOKEN% upload -u Radiomics C:/conda-bld/win-64/pyradiomics-*.tar.bz2 --force - echo finished deployment From 5751a1f3494526348bd2e9f14f9534719419b2d2 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Tue, 8 Mar 2022 18:08:43 +0100 Subject: [PATCH 04/38] BUG: Fix error in CircleCI config.yml Use quotes to ensure correct installation of version-constrained pip installs. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 54b2e562..18d45a5b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -105,7 +105,7 @@ jobs: name: Install patchelf auditwheel, twine command: | apt-get install patchelf # needed to run auditwheel - python -m pip install auditwheel + python -m pip install "auditwheel<3.2.0" python -m pip install twine # only attach the workspace at this point to prevent the removal of source distributions - attach_workspace: From f663a2e2ff24e8878608d44396b5f41864080268 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Wed, 23 Mar 2022 11:04:06 +0100 Subject: [PATCH 05/38] ENH: Build and test Mac OS on CircleCI --- .circleci/config.yml | 49 ++++++++++++++++++++- .travis.yml | 102 ------------------------------------------- 2 files changed, 47 insertions(+), 104 deletions(-) delete mode 100644 .travis.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 18d45a5b..20b39746 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,10 +32,53 @@ jobs: command: | jupyter nbconvert --ExecutePreprocessor.kernel_name=python3 --ExecutePreprocessor.timeout=-1 --to notebook --output-dir /tmp --execute notebooks/helloRadiomics.ipynb notebooks/helloFeatureClass.ipynb notebooks/PyRadiomicsExample.ipynb + build-mac: + working_directory: /pyradiomics + macos: + xcode: 12.5.1 + environment: + PYTHON_VERSION: 3.5 + PYTHON_SHORT_VERSION: 3.5 + PATH: $/.pyenv/versions/$/bin:$ + steps: + - checkout + - attach_workspace: + at: /pyradiomics + - run: + name: Setup MAC OS environment + # Workaround the following error occurring because python installation is cached but gettext dependency is not + # dyld: Library not loaded: /usr/local/opt/gettext/lib/libintl.8.dylib + # Referenced from: /Users/travis/.pyenv/versions/3.7.2/bin/python + # Reason: Incompatible library version: python requires version 11.0.0 or later, but libintl.8.dylib provides version 10.0.0 + # See https://github.com/scikit-build/cmake-python-distributions/issues/112 and + # https://github.com/scikit-build/cmake-python-distributions/pull/113 + command: | + brew update + brew install gettext + mkdir $HOME/bin + ln -s $(which pip3) $HOME/bin/pip + - run: + name: Setup SciKit-CI + command: | + pip install scikit-ci scikit-ci-addons + ci_addons --install ../addons + - run: + name: Setup PyEnv + command: | + python3 ../addons/travis/install_pyenv.py + - run: + name: Install + command: ci install + - run: + name: Test + command: ci test + - run: + name: Build Distribution + command: ci after_test build-3.5: &build_template working_directory: /pyradiomics docker: - - image: circleci/python:3.5-jessie + - image: cimg/python:3.5 user: root steps: - checkout @@ -167,11 +210,13 @@ workflows: version: 2 build_and_deploy: jobs: - - build-3.5: &build_job_template + - build-mac: &build_job_template filters: tags: only: - /^v?[0-9]+(\.[0-9]+)*(rc[0-9]+)?/ + - build-3.5: + <<: *build_job_template - build-3.6: <<: *build_job_template - build-3.7: diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a078fcd5..00000000 --- a/.travis.yml +++ /dev/null @@ -1,102 +0,0 @@ -# Config file for automatic testing at travis-ci.org - -language: python - -matrix: - include: - - - os: osx - language: generic - env: - - PYTHON_VERSION=3.5 - - PYTHON_SHORT_VERSION=3.5 - - - os: osx - language: generic - env: - - PYTHON_VERSION=3.6 - - PYTHON_SHORT_VERSION=3.6 - - - os: osx - language: generic - env: - - PYTHON_VERSION=3.7 - - PYTHON_SHORT_VERSION=3.7 - - - os: osx - language: generic - env: - - PYTHON_VERSION=3.8 - - PYTHON_SHORT_VERSI8ON=3.8 - - - os: osx - language: generic - env: - - PYTHON_VERSION=3.9 - - PYTHON_SHORT_VERSION=3.9 - -before_cache: - # Cleanup to avoid the cache to grow indefinitely as new package versions are released - # see https://stackoverflow.com/questions/39930171/cache-brew-builds-with-travis-ci - - brew cleanup - -cache: - directories: - # Cache downloaded bottles - - $HOME/Library/Caches/Homebrew - # pyenv - - $HOME/.pyenv_cache - - $HOME/.pyenv/versions/3.9 - - $HOME/.pyenv/versions/3.8 - - $HOME/.pyenv/versions/3.7 - - $HOME/.pyenv/versions/3.6 - - $HOME/.pyenv/versions/3.5 - # scikit-ci-addons - - $HOME/downloads - -before_install: - # Workaround the following error occuring because python installation is cached but gettext dependency is not - # dyld: Library not loaded: /usr/local/opt/gettext/lib/libintl.8.dylib - # Referenced from: /Users/travis/.pyenv/versions/3.7.2/bin/python - # Reason: Incompatible library version: python requires version 11.0.0 or later, but libintl.8.dylib provides version 10.0.0 - # See https://github.com/scikit-build/cmake-python-distributions/issues/112 and - # https://github.com/scikit-build/cmake-python-distributions/pull/113 - - brew update - - brew install gettext - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then mkdir $HOME/bin; ln -s $(which pip2) $HOME/bin/pip; fi - - pip install scikit-ci scikit-ci-addons - - ci_addons --install ../addons - -install: - - ci install - -script: - - ci test - -after_success: - - ci after_test - -before_deploy: - - sudo pip install twine # Twine installation requires sudo to get access to /usr/local/man - -deploy: - - provider: script - skip_cleanup: true - script: twine upload dist/*.whl -u $PYPI_USER -p $PYPI_PASSWORD - on: - tags: true - condition: $TRAVIS_TAG =~ ^v?[0-9]+(\.[0-9]+)*(rc[0-9]+)?$ && $TRAVIS_REPO_SLUG == Radiomics/pyradiomics - - provider: script - script: - wget https://repo.continuum.io/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -O miniconda.sh; - bash miniconda.sh -b -p $HOME/miniconda; - hash -r; - export PATH=$HOME/miniconda/bin:$PATH; - conda config --set always_yes yes; - conda install gcc libgcc; - bash ./conda/configure_conda.sh; - conda build ./conda --python=$PYTHON_SHORT_VERSION --croot $HOME/conda-bld; - anaconda -t $ANACONDA_TOKEN upload -u Radiomics $HOME/conda-bld/osx-64/pyradiomics-*.tar.bz2 --force - on: - tags: true - condition: $TRAVIS_TAG =~ ^v?[0-9]+(\.[0-9]+)*(rc[0-9]+)?$ && $TRAVIS_REPO_SLUG == Radiomics/pyradiomics From a8b63c87c0c5f8d6c312967cb7f8487dc38b9e83 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Wed, 23 Mar 2022 11:11:14 +0100 Subject: [PATCH 06/38] BUG: Build in home dir on Mac --- .circleci/config.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 20b39746..1d40cafb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -33,17 +33,17 @@ jobs: jupyter nbconvert --ExecutePreprocessor.kernel_name=python3 --ExecutePreprocessor.timeout=-1 --to notebook --output-dir /tmp --execute notebooks/helloRadiomics.ipynb notebooks/helloFeatureClass.ipynb notebooks/PyRadiomicsExample.ipynb build-mac: - working_directory: /pyradiomics + working_directory: ~/pyradiomics macos: xcode: 12.5.1 - environment: - PYTHON_VERSION: 3.5 - PYTHON_SHORT_VERSION: 3.5 - PATH: $/.pyenv/versions/$/bin:$ + environment: + PYTHON_VERSION: 3.5 + PYTHON_SHORT_VERSION: 3.5 + PATH: $/.pyenv/versions/$/bin:$ steps: - checkout - attach_workspace: - at: /pyradiomics + at: ~/pyradiomics - run: name: Setup MAC OS environment # Workaround the following error occurring because python installation is cached but gettext dependency is not From 9b4f71a6b8e76d6ec1a6c704c84de6d7657799af Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Wed, 23 Mar 2022 11:15:35 +0100 Subject: [PATCH 07/38] BUG: Update config Periods are not allowed in job name. --- .circleci/config.yml | 44 ++++++++++++++++++++++---------------------- README.md | 14 +++++++------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1d40cafb..590a213f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ # docker pull circleci/picard # docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock -v $(pwd):$(pwd) -v ~/.circleci/:/root/.circleci --workdir $(pwd) circleci/picard circleci build -version: 2 +version: 2.1 jobs: test-notebooks: working_directory: /pyradiomics @@ -75,7 +75,7 @@ jobs: - run: name: Build Distribution command: ci after_test - build-3.5: &build_template + build-35: &build_template working_directory: /pyradiomics docker: - image: cimg/python:3.5 @@ -100,27 +100,27 @@ jobs: command: ci after_test - persist_to_workspace: root: . - paths: dist + paths: [dist] - build-3.6: + build-36: <<: *build_template docker: - image: cimg/python:3.6 user: root - build-3.7: + build-37: <<: *build_template docker: - image: cimg/python:3.7 user: root - build-3.8: + build-38: <<: *build_template docker: - image: cimg/python:3.8 user: root - build-3.9: + build-39: <<: *build_template docker: - image: cimg/python:3.9 @@ -215,30 +215,30 @@ workflows: tags: only: - /^v?[0-9]+(\.[0-9]+)*(rc[0-9]+)?/ - - build-3.5: + - build-35: <<: *build_job_template - - build-3.6: + - build-36: <<: *build_job_template - - build-3.7: + - build-37: <<: *build_job_template - - build-3.8: + - build-38: <<: *build_job_template - - build-3.9: + - build-39: <<: *build_job_template - test-notebooks: requires: - - build-3.5 - - build-3.6 - - build-3.7 - - build-3.8 - - build-3.9 + - build-35 + - build-36 + - build-37 + - build-38 + - build-39 - deploy: &deploy_template requires: - - build-3.5 - - build-3.6 - - build-3.7 - - build-3.8 - - build-3.9 + - build-35 + - build-36 + - build-37 + - build-38 + - build-39 filters: branches: ignore: diff --git a/README.md b/README.md index 53449639..fddca725 100644 --- a/README.md +++ b/README.md @@ -3,18 +3,18 @@ ## Build Status | Linux | macOS | Windows | -|--------------------------------|-------------------------------|-------------------------------| +| ------------------------------ | ----------------------------- | ----------------------------- | | [![][circleci]][circleci-lnk] | [![][travisci]][travisci-lnk] | [![][appveyor]][appveyor-lnk] | -[appveyor]: https://ci.appveyor.com/api/projects/status/tw69xbbeyluk7fl7/branch/master?svg=true -[appveyor-lnk]: https://ci.appveyor.com/project/Radiomics/pyradiomics/branch/master +[appveyor]: https://ci.appveyor.com/api/projects/status/kvu7897q0v4imwdc?svg=true +[appveyor-lnk]: https://ci.appveyor.com/project/AIM-Harvard/pyradiomics-k4sto -[circleci]: https://circleci.com/gh/Radiomics/pyradiomics.svg?style=svg&circle-token=a4748cf0de5fad2c12bc93a485282378551c3584 -[circleci-lnk]: https://circleci.com/gh/Radiomics/pyradiomics +[circleci]: https://circleci.com/gh/AIM-Harvard/pyradiomics.svg?style=svg&circle-token=a4748cf0de5fad2c12bc93a485282378551c3584 +[circleci-lnk]: https://circleci.com/gh/AIM-Harvard/pyradiomics -[travisci]: https://travis-ci.org/Radiomics/pyradiomics.svg?branch=master -[travisci-lnk]: https://travis-ci.org/Radiomics/pyradiomics +[travisci]: https://travis-ci.com/AIM-Harvard/pyradiomics.svg?branch=master +[travisci-lnk]: https://travis-ci.com/AIM-Harvard/pyradiomics ## Radiomics feature extraction in Python This is an open-source python package for the extraction of Radiomics features from medical imaging. From 2140f0c8fb3511db8337330e7c1703f57e6e2325 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Wed, 23 Mar 2022 11:24:34 +0100 Subject: [PATCH 08/38] BUG: Install git on MacOS image --- .circleci/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 590a213f..de030879 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -41,6 +41,9 @@ jobs: PYTHON_SHORT_VERSION: 3.5 PATH: $/.pyenv/versions/$/bin:$ steps: + - run: + name: install git + command: brew install git - checkout - attach_workspace: at: ~/pyradiomics From a7495661b200c4ee972a0ae72026bab7c5c91e5e Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Wed, 23 Mar 2022 11:50:27 +0100 Subject: [PATCH 09/38] BUG: Fix errors in MacOS image --- .circleci/config.yml | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index de030879..883f6b30 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -37,13 +37,10 @@ jobs: macos: xcode: 12.5.1 environment: - PYTHON_VERSION: 3.5 - PYTHON_SHORT_VERSION: 3.5 - PATH: $/.pyenv/versions/$/bin:$ + PYTHON_VERSION: 3.9.11 + PYTHON_SHORT_VERSION: 3.9 + PATH: $HOME/.pyenv/versions/$PYTHON_VERSION/bin:$PATH steps: - - run: - name: install git - command: brew install git - checkout - attach_workspace: at: ~/pyradiomics @@ -58,8 +55,10 @@ jobs: command: | brew update brew install gettext + brew install pyenv mkdir $HOME/bin ln -s $(which pip3) $HOME/bin/pip + ln -s $(which python3) $HOME/bin/python - run: name: Setup SciKit-CI command: | @@ -68,7 +67,7 @@ jobs: - run: name: Setup PyEnv command: | - python3 ../addons/travis/install_pyenv.py + python ../addons/travis/install_pyenv.py - run: name: Install command: ci install @@ -220,14 +219,24 @@ workflows: - /^v?[0-9]+(\.[0-9]+)*(rc[0-9]+)?/ - build-35: <<: *build_job_template + requires: + - build-mac - build-36: <<: *build_job_template + requires: + - build-mac - build-37: <<: *build_job_template + requires: + - build-mac - build-38: <<: *build_job_template + requires: + - build-mac - build-39: <<: *build_job_template + requires: + - build-mac - test-notebooks: requires: - build-35 From b0ea347911fb84616dbd123c727815ccd9fb61d2 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Thu, 31 Mar 2022 23:07:41 +0200 Subject: [PATCH 10/38] CI: Setup MacOS environment prior to code checkout --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 883f6b30..82f7aea6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -41,9 +41,6 @@ jobs: PYTHON_SHORT_VERSION: 3.9 PATH: $HOME/.pyenv/versions/$PYTHON_VERSION/bin:$PATH steps: - - checkout - - attach_workspace: - at: ~/pyradiomics - run: name: Setup MAC OS environment # Workaround the following error occurring because python installation is cached but gettext dependency is not @@ -68,6 +65,9 @@ jobs: name: Setup PyEnv command: | python ../addons/travis/install_pyenv.py + - checkout + - attach_workspace: + at: ~/pyradiomics - run: name: Install command: ci install From 4754faeb6a75d9ade83c100d44958bb66cb89aff Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Thu, 31 Mar 2022 23:23:06 +0200 Subject: [PATCH 11/38] BUG: Add -p on mkdir command ensures it does not fail if the directory already exists --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 82f7aea6..7899e31d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -53,7 +53,7 @@ jobs: brew update brew install gettext brew install pyenv - mkdir $HOME/bin + mkdir -p $HOME/bin ln -s $(which pip3) $HOME/bin/pip ln -s $(which python3) $HOME/bin/python - run: From c57f28d8f45cb75bdf498123a6669278c13c58de Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Sun, 3 Apr 2022 14:19:32 +0200 Subject: [PATCH 12/38] BUG: Add HOME bin folder to PATH --- .circleci/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7899e31d..4b88534d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,7 +39,7 @@ jobs: environment: PYTHON_VERSION: 3.9.11 PYTHON_SHORT_VERSION: 3.9 - PATH: $HOME/.pyenv/versions/$PYTHON_VERSION/bin:$PATH + PATH: $HOME/.pyenv/versions/$PYTHON_VERSION/bin:$HOME/bin:$PATH steps: - run: name: Setup MAC OS environment @@ -59,6 +59,7 @@ jobs: - run: name: Setup SciKit-CI command: | + echo $PATH pip install scikit-ci scikit-ci-addons ci_addons --install ../addons - run: From d53d40a9bc70d3bb202e10b05a9c77b9cd62fbb2 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Sun, 3 Apr 2022 14:35:45 +0200 Subject: [PATCH 13/38] BUG: Dynamically set PATH --- .circleci/config.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4b88534d..2cab29f1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -39,7 +39,6 @@ jobs: environment: PYTHON_VERSION: 3.9.11 PYTHON_SHORT_VERSION: 3.9 - PATH: $HOME/.pyenv/versions/$PYTHON_VERSION/bin:$HOME/bin:$PATH steps: - run: name: Setup MAC OS environment @@ -53,6 +52,9 @@ jobs: brew update brew install gettext brew install pyenv + echo $PATH + echo 'export PATH=$HOME/.pyenv/versions/$PYTHON_VERSION/bin:$HOME/bin:$PATH' >> $BASH_ENV + echo $PATH mkdir -p $HOME/bin ln -s $(which pip3) $HOME/bin/pip ln -s $(which python3) $HOME/bin/python @@ -65,6 +67,7 @@ jobs: - run: name: Setup PyEnv command: | + echo $PATH python ../addons/travis/install_pyenv.py - checkout - attach_workspace: From 4a2e26b1926dc5af139f88fb57d90e02b856e843 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Sun, 3 Apr 2022 16:01:22 +0200 Subject: [PATCH 14/38] CI: Update MacOS config in Circle CI --- .circleci/config.yml | 64 +++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2cab29f1..b4c6f6ca 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,13 +32,13 @@ jobs: command: | jupyter nbconvert --ExecutePreprocessor.kernel_name=python3 --ExecutePreprocessor.timeout=-1 --to notebook --output-dir /tmp --execute notebooks/helloRadiomics.ipynb notebooks/helloFeatureClass.ipynb notebooks/PyRadiomicsExample.ipynb - build-mac: + build-mac-35: &build_mac_template working_directory: ~/pyradiomics macos: xcode: 12.5.1 environment: - PYTHON_VERSION: 3.9.11 - PYTHON_SHORT_VERSION: 3.9 + PYTHON_VERSION: 3.5.10 + PYTHON_SHORT_VERSION: 3.5 steps: - run: name: Setup MAC OS environment @@ -49,26 +49,22 @@ jobs: # See https://github.com/scikit-build/cmake-python-distributions/issues/112 and # https://github.com/scikit-build/cmake-python-distributions/pull/113 command: | - brew update + echo "HOMEBREW_NO_AUTO_UPDATE=1" >> $BASH_ENV brew install gettext brew install pyenv - echo $PATH echo 'export PATH=$HOME/.pyenv/versions/$PYTHON_VERSION/bin:$HOME/bin:$PATH' >> $BASH_ENV - echo $PATH mkdir -p $HOME/bin ln -s $(which pip3) $HOME/bin/pip ln -s $(which python3) $HOME/bin/python + pyenv install --list - run: name: Setup SciKit-CI command: | - echo $PATH pip install scikit-ci scikit-ci-addons ci_addons --install ../addons - run: name: Setup PyEnv - command: | - echo $PATH - python ../addons/travis/install_pyenv.py + command: python ../addons/travis/install_pyenv.py - checkout - attach_workspace: at: ~/pyradiomics @@ -81,6 +77,34 @@ jobs: - run: name: Build Distribution command: ci after_test + - persist_to_workspace: + root: . + paths: [dist] + + build-mac-36: + <<: *build_mac_template + environment: + PYTHON_VERSION: 3.6.13 + PYTHON_SHORT_VERSION: 3.6 + + build-mac-37: + <<: *build_mac_template + environment: + PYTHON_VERSION: 3.7.10 + PYTHON_SHORT_VERSION: 3.7 + + build-mac-38: + <<: *build_mac_template + environment: + PYTHON_VERSION: 3.8.11 + PYTHON_SHORT_VERSION: 3.7 + + build-mac-39: + <<: *build_mac_template + environment: + PYTHON_VERSION: 3.9.11 + PYTHON_SHORT_VERSION: 3.9 + build-35: &build_template working_directory: /pyradiomics docker: @@ -216,31 +240,29 @@ workflows: version: 2 build_and_deploy: jobs: - - build-mac: &build_job_template + - build-mac-35: &build_job_template filters: tags: only: - /^v?[0-9]+(\.[0-9]+)*(rc[0-9]+)?/ + - build-mac-36: + <<: *build_job_template + - build-mac-37: + <<: *build_job_template + - build-mac-38: + <<: *build_job_template + - build-mac-39: + <<: *build_job_template - build-35: <<: *build_job_template - requires: - - build-mac - build-36: <<: *build_job_template - requires: - - build-mac - build-37: <<: *build_job_template - requires: - - build-mac - build-38: <<: *build_job_template - requires: - - build-mac - build-39: <<: *build_job_template - requires: - - build-mac - test-notebooks: requires: - build-35 From ae3fba517ee56770fbe5df7305126c7648770a48 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Sun, 3 Apr 2022 16:08:04 +0200 Subject: [PATCH 15/38] CI: Manually install python version for mac --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index b4c6f6ca..930968b1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -57,6 +57,7 @@ jobs: ln -s $(which pip3) $HOME/bin/pip ln -s $(which python3) $HOME/bin/python pyenv install --list + pyenv install $PYTHON_VERSION - run: name: Setup SciKit-CI command: | From 6bd59fa7802e0bf0b76f753e9d72590e7a4152db Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Sun, 3 Apr 2022 16:41:05 +0200 Subject: [PATCH 16/38] CI: Update MacOs Python versions --- .circleci/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 930968b1..f0d7d19b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -37,7 +37,7 @@ jobs: macos: xcode: 12.5.1 environment: - PYTHON_VERSION: 3.5.10 + PYTHON_VERSION: 3.5.9 PYTHON_SHORT_VERSION: 3.5 steps: - run: @@ -85,7 +85,7 @@ jobs: build-mac-36: <<: *build_mac_template environment: - PYTHON_VERSION: 3.6.13 + PYTHON_VERSION: 3.6.12 PYTHON_SHORT_VERSION: 3.6 build-mac-37: @@ -97,13 +97,13 @@ jobs: build-mac-38: <<: *build_mac_template environment: - PYTHON_VERSION: 3.8.11 + PYTHON_VERSION: 3.8.10 PYTHON_SHORT_VERSION: 3.7 build-mac-39: <<: *build_mac_template environment: - PYTHON_VERSION: 3.9.11 + PYTHON_VERSION: 3.9.5 PYTHON_SHORT_VERSION: 3.9 build-35: &build_template From aa6a1a32044898464a14c6bc812b8dcd77b6e575 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Sun, 3 Apr 2022 17:23:07 +0200 Subject: [PATCH 17/38] CI: Remove Mac OS support for python 3.5 and 3.6 These python distributions fail to build on CircleCI (failing during setup of python environment). --- .circleci/config.yml | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f0d7d19b..a425b0a9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,13 +32,13 @@ jobs: command: | jupyter nbconvert --ExecutePreprocessor.kernel_name=python3 --ExecutePreprocessor.timeout=-1 --to notebook --output-dir /tmp --execute notebooks/helloRadiomics.ipynb notebooks/helloFeatureClass.ipynb notebooks/PyRadiomicsExample.ipynb - build-mac-35: &build_mac_template + build-mac-37: &build_mac_template working_directory: ~/pyradiomics macos: xcode: 12.5.1 environment: - PYTHON_VERSION: 3.5.9 - PYTHON_SHORT_VERSION: 3.5 + PYTHON_VERSION: 3.7.10 + PYTHON_SHORT_VERSION: 3.7 steps: - run: name: Setup MAC OS environment @@ -82,18 +82,6 @@ jobs: root: . paths: [dist] - build-mac-36: - <<: *build_mac_template - environment: - PYTHON_VERSION: 3.6.12 - PYTHON_SHORT_VERSION: 3.6 - - build-mac-37: - <<: *build_mac_template - environment: - PYTHON_VERSION: 3.7.10 - PYTHON_SHORT_VERSION: 3.7 - build-mac-38: <<: *build_mac_template environment: @@ -241,15 +229,11 @@ workflows: version: 2 build_and_deploy: jobs: - - build-mac-35: &build_job_template + - build-mac-37: &build_job_template filters: tags: only: - /^v?[0-9]+(\.[0-9]+)*(rc[0-9]+)?/ - - build-mac-36: - <<: *build_job_template - - build-mac-37: - <<: *build_job_template - build-mac-38: <<: *build_job_template - build-mac-39: From e719901d316c2341a6f42cc621e5b2ce95e47022 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 13 Jun 2022 12:01:13 +0200 Subject: [PATCH 18/38] ENH: implement distribution to test pypi When tag version specifies alfa, beta or rc release, push to test pypi server. --- .circleci/config.yml | 78 +++++++++++++++++++++++++++++++++++++++++--- appveyor.yml | 3 +- scikit-ci.yml | 2 +- 3 files changed, 77 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a425b0a9..0482dfdd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -145,6 +145,50 @@ jobs: - image: cimg/python:3.9 user: root + test_deploy: + working_directory: /pyradiomics + docker: + - image: cimg/python:3.6 + user: root + steps: + - run: + name: Check Repo User + command: if [[ $CIRCLE_PROJECT_USERNAME != "Radiomics" ]]; then circleci step halt; fi + - checkout + - run: + name: Setup SciKit-CI + command: | + pip install scikit-ci scikit-ci-addons + ci_addons --install ../addons + - run: + name: Install + command: ci install + - run: + name: Install patchelf auditwheel, twine + command: | + apt-get install patchelf # needed to run auditwheel + python -m pip install "auditwheel<3.2.0" + python -m pip install twine + # only attach the workspace at this point to prevent the removal of source distributions + - attach_workspace: + at: /pyradiomics + - run: + name: Create sdist + command: python setup.py sdist + - run: + name: Fix Distribution Wheels + command: | + ls ./dist/*-linux_$(uname -m).whl # This will prevent further deployment if no wheels are found + # Since there are no external shared libraries to bundle into the wheels + # this step will fixup the wheel switching from 'linux' to 'manylinux1' tag + for whl in $(ls ./dist/*-linux_$(uname -m).whl); do + auditwheel repair $whl -w ./dist/ + rm $whl + done + - run: + name: Deploy source and linux wheels + command: twine upload ./dist/*.whl ./dist/*.tar.gz -u $PYPI_TEST_USER -p $PYPI_TEST_PASSWORD -r testpypi + deploy: working_directory: /pyradiomics docker: @@ -233,7 +277,7 @@ workflows: filters: tags: only: - - /^v?[0-9]+(\.[0-9]+)*(rc[0-9]+)?/ + - /^v?[0-9]+(\.[0-9]+)*((a|b|rc)[0-9]+)?/ - build-mac-38: <<: *build_job_template - build-mac-39: @@ -255,7 +299,7 @@ workflows: - build-37 - build-38 - build-39 - - deploy: &deploy_template + - test_deploy: requires: - build-35 - build-36 @@ -268,6 +312,32 @@ workflows: - /.*/ tags: only: - - /^v?[0-9]+(\.[0-9]+)*(rc[0-9]+)?/ + - /^v?[0-9]+(\.[0-9]+)*((a|b|rc)[0-9]+)/ + - deploy: + requires: + - build-35 + - build-36 + - build-37 + - build-38 + - build-39 + filters: + branches: + ignore: + - /.*/ + tags: + only: + - /^v?[0-9]+(\.[0-9]+)*/ - deploy_conda: - <<: *deploy_template + requires: + - build-35 + - build-36 + - build-37 + - build-38 + - build-39 + filters: + branches: + ignore: + - /.*/ + tags: + only: + - /^v?[0-9]+(\.[0-9]+)*((a|b|rc)[0-9]+)?/ diff --git a/appveyor.yml b/appveyor.yml index cc5c9481..3d89c4eb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -67,7 +67,8 @@ deploy_script: - ps: if ($env:APPVEYOR_REPO_NAME -notmatch 'Radiomics/pyradiomics') { appveyor exit } - ps: if ($env:APPVEYOR_REPO_TAG_NAME -notmatch '^v?[0-9]+(\.[0-9]+)*(rc\d+)?$') { appveyor exit } - echo starting PyPi deployment - - twine upload dist/*.whl -u %PYPI_USER% -p %PYPI_PASSWORD% + - ps: if ($env:APPVEYOR_REPO_TAG_NAME -match '^v?[0-9]+(\.[0-9]+)*$') { twine upload dist/*.whl -u %PYPI_USER% -p %PYPI_PASSWORD% } + - ps: if ($env:APPVEYOR_REPO_TAG_NAME -match '^v?[0-9]+(\.[0-9]+)*((a|b|rc)[0-9]+)$') { twine upload dist/*.whl -u %PYPI_TEST_USER% -p %PYPI_TEST_PASSWORD% -r testpypi } - echo starting Anaconda deployment - SET PATH=C:\Miniconda-x64\Scripts;%PATH% - conda config --set always_yes yes diff --git a/scikit-ci.yml b/scikit-ci.yml index fba7450a..ef36e50e 100644 --- a/scikit-ci.yml +++ b/scikit-ci.yml @@ -31,7 +31,7 @@ install: - $ pip install wheel>=0.29.0 - $ pip install setuptools>=38.6.0 - $ pip install numpy>=1.9.2 - - $ pip install --trusted-host www.itk.org -f https://itk.org/SimpleITKDoxygen/html/PyDownloadPage.html SimpleITK>=0.9.1 + - $ pip install SimpleITK>=0.9.1 - $ python -c "import SimpleITK; print('SimpleITK Version:' + SimpleITK.Version_VersionString())" - $ pip install -r requirements.txt - $ pip install -r requirements-dev.txt From 98cdd0f44ac780a2219a790414313ce1367421d2 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 13 Jun 2022 12:29:48 +0200 Subject: [PATCH 19/38] ENH: Remove Python 3.5 support No longer supported since September 13th, 2020 --- .circleci/config.yml | 37 ++++++------------------------------- appveyor.yml | 6 ------ 2 files changed, 6 insertions(+), 37 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0482dfdd..e437b780 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -94,10 +94,10 @@ jobs: PYTHON_VERSION: 3.9.5 PYTHON_SHORT_VERSION: 3.9 - build-35: &build_template + build-36: &build_template working_directory: /pyradiomics docker: - - image: cimg/python:3.5 + - image: cimg/python:3.6 user: root steps: - checkout @@ -121,12 +121,6 @@ jobs: root: . paths: [dist] - build-36: - <<: *build_template - docker: - - image: cimg/python:3.6 - user: root - build-37: <<: *build_template docker: @@ -259,7 +253,6 @@ jobs: name: Build Conda packages command: | mkdir /conda-bld - conda build ./conda --python=3.5 --croot /conda-bld conda build ./conda --python=3.6 --croot /conda-bld conda build ./conda --python=3.7 --croot /conda-bld conda build ./conda --python=3.8 --croot /conda-bld @@ -282,8 +275,6 @@ workflows: <<: *build_job_template - build-mac-39: <<: *build_job_template - - build-35: - <<: *build_job_template - build-36: <<: *build_job_template - build-37: @@ -292,20 +283,14 @@ workflows: <<: *build_job_template - build-39: <<: *build_job_template - - test-notebooks: + - test-notebooks: &requires_template requires: - - build-35 - build-36 - build-37 - build-38 - build-39 - test_deploy: - requires: - - build-35 - - build-36 - - build-37 - - build-38 - - build-39 + <<: *requires_template filters: branches: ignore: @@ -314,12 +299,7 @@ workflows: only: - /^v?[0-9]+(\.[0-9]+)*((a|b|rc)[0-9]+)/ - deploy: - requires: - - build-35 - - build-36 - - build-37 - - build-38 - - build-39 + <<: *requires_template filters: branches: ignore: @@ -328,12 +308,7 @@ workflows: only: - /^v?[0-9]+(\.[0-9]+)*/ - deploy_conda: - requires: - - build-35 - - build-36 - - build-37 - - build-38 - - build-39 + <<: *requires_template filters: branches: ignore: diff --git a/appveyor.yml b/appveyor.yml index 3d89c4eb..715eab88 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,12 +5,6 @@ environment: # Visual Studio (Python 3, 64 bit) - - PYTHON_DIR: "C:\\Python35-x64" - PYTHON_VERSION: "3.5.x" - PYTHON_SHORT_VERSION: "3.5" - PYTHON_ARCH: "64" - BLOCK: "0" - - PYTHON_DIR: "C:\\Python36-x64" PYTHON_VERSION: "3.6.x" PYTHON_SHORT_VERSION: "3.6" From 62c5577cb8a3e25dddbd9c3558788b080fe27749 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 13 Jun 2022 12:35:22 +0200 Subject: [PATCH 20/38] CI: Update Repo check Repo organization name has changed to AIM-Harvard, update the check to reflect this. --- .circleci/config.yml | 9 ++++++--- appveyor.yml | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e437b780..308e8696 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -147,7 +147,7 @@ jobs: steps: - run: name: Check Repo User - command: if [[ $CIRCLE_PROJECT_USERNAME != "Radiomics" ]]; then circleci step halt; fi + command: if [[ $CIRCLE_PROJECT_USERNAME != "AIM-Harvard" ]]; then circleci step halt; fi - checkout - run: name: Setup SciKit-CI @@ -191,7 +191,7 @@ jobs: steps: - run: name: Check Repo User - command: if [[ $CIRCLE_PROJECT_USERNAME != "Radiomics" ]]; then circleci step halt; fi + command: if [[ $CIRCLE_PROJECT_USERNAME != "AIM-Harvard" ]]; then circleci step halt; fi - checkout - run: name: Setup SciKit-CI @@ -235,7 +235,7 @@ jobs: steps: - run: name: Check Repo User - command: if [[ $CIRCLE_PROJECT_USERNAME != "Radiomics" ]]; then circleci step halt; fi + command: if [[ $CIRCLE_PROJECT_USERNAME != "AIM-Harvard" ]]; then circleci step halt; fi - checkout - run: name: Install Miniconda @@ -289,6 +289,9 @@ workflows: - build-37 - build-38 - build-39 + - build-mac-37 + - build-mac-38 + - build-mac-39 - test_deploy: <<: *requires_template filters: diff --git a/appveyor.yml b/appveyor.yml index 715eab88..7e365c5e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -58,7 +58,7 @@ on_finish: deploy_script: - echo checking deployment - - ps: if ($env:APPVEYOR_REPO_NAME -notmatch 'Radiomics/pyradiomics') { appveyor exit } + - ps: if ($env:APPVEYOR_REPO_NAME -notmatch 'AIM-Harvard/pyradiomics') { appveyor exit } - ps: if ($env:APPVEYOR_REPO_TAG_NAME -notmatch '^v?[0-9]+(\.[0-9]+)*(rc\d+)?$') { appveyor exit } - echo starting PyPi deployment - ps: if ($env:APPVEYOR_REPO_TAG_NAME -match '^v?[0-9]+(\.[0-9]+)*$') { twine upload dist/*.whl -u %PYPI_USER% -p %PYPI_PASSWORD% } From 9290e1743dd19b4a403594b736129eec0ae5dc97 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 13 Jun 2022 15:53:19 +0200 Subject: [PATCH 21/38] CI: Fix deployment bugs Ensure patchelf can be installed in linux Fix tag check in AppVeyor --- .circleci/config.yml | 2 ++ appveyor.yml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 308e8696..7db22750 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -160,6 +160,7 @@ jobs: - run: name: Install patchelf auditwheel, twine command: | + apt update apt-get install patchelf # needed to run auditwheel python -m pip install "auditwheel<3.2.0" python -m pip install twine @@ -204,6 +205,7 @@ jobs: - run: name: Install patchelf auditwheel, twine command: | + apt update apt-get install patchelf # needed to run auditwheel python -m pip install "auditwheel<3.2.0" python -m pip install twine diff --git a/appveyor.yml b/appveyor.yml index 7e365c5e..93138e7c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -59,7 +59,7 @@ on_finish: deploy_script: - echo checking deployment - ps: if ($env:APPVEYOR_REPO_NAME -notmatch 'AIM-Harvard/pyradiomics') { appveyor exit } - - ps: if ($env:APPVEYOR_REPO_TAG_NAME -notmatch '^v?[0-9]+(\.[0-9]+)*(rc\d+)?$') { appveyor exit } + - ps: if ($env:APPVEYOR_REPO_TAG_NAME -notmatch '^v?[0-9]+(\.[0-9]+)*((a|b|rc)[0-9]+)?$') { appveyor exit } - echo starting PyPi deployment - ps: if ($env:APPVEYOR_REPO_TAG_NAME -match '^v?[0-9]+(\.[0-9]+)*$') { twine upload dist/*.whl -u %PYPI_USER% -p %PYPI_PASSWORD% } - ps: if ($env:APPVEYOR_REPO_TAG_NAME -match '^v?[0-9]+(\.[0-9]+)*((a|b|rc)[0-9]+)$') { twine upload dist/*.whl -u %PYPI_TEST_USER% -p %PYPI_TEST_PASSWORD% -r testpypi } From 110aa14b6840a3e07a3ff9d1c810dfc0c1c77d60 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Mon, 13 Jun 2022 16:39:14 +0200 Subject: [PATCH 22/38] BUG: Fix error in passing PyPi credentials Twin upload is handled in powershell, requiring a different reference to environment variables. --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 93138e7c..819effd4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -61,8 +61,8 @@ deploy_script: - ps: if ($env:APPVEYOR_REPO_NAME -notmatch 'AIM-Harvard/pyradiomics') { appveyor exit } - ps: if ($env:APPVEYOR_REPO_TAG_NAME -notmatch '^v?[0-9]+(\.[0-9]+)*((a|b|rc)[0-9]+)?$') { appveyor exit } - echo starting PyPi deployment - - ps: if ($env:APPVEYOR_REPO_TAG_NAME -match '^v?[0-9]+(\.[0-9]+)*$') { twine upload dist/*.whl -u %PYPI_USER% -p %PYPI_PASSWORD% } - - ps: if ($env:APPVEYOR_REPO_TAG_NAME -match '^v?[0-9]+(\.[0-9]+)*((a|b|rc)[0-9]+)$') { twine upload dist/*.whl -u %PYPI_TEST_USER% -p %PYPI_TEST_PASSWORD% -r testpypi } + - ps: if ($env:APPVEYOR_REPO_TAG_NAME -match '^v?[0-9]+(\.[0-9]+)*$') { twine upload dist/*.whl -u $Env:PYPI_USER -p $Env:PYPI_PASSWORD } + - ps: if ($env:APPVEYOR_REPO_TAG_NAME -match '^v?[0-9]+(\.[0-9]+)*((a|b|rc)[0-9]+)$') { twine upload dist/*.whl -u $Env:PYPI_TEST_USER -p $Env:PYPI_TEST_PASSWORD -r testpypi } - echo starting Anaconda deployment - SET PATH=C:\Miniconda-x64\Scripts;%PATH% - conda config --set always_yes yes From be9f2b2c1e10c947f5845725152332a5ba1a2f7e Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Tue, 20 Sep 2022 17:45:58 +0200 Subject: [PATCH 23/38] STYL: Fix Flake8 error --- tests/test_matrices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_matrices.py b/tests/test_matrices.py index b4858307..d5865174 100644 --- a/tests/test_matrices.py +++ b/tests/test_matrices.py @@ -27,7 +27,7 @@ def generate_scenarios(): if testCase.startswith('test'): continue for className, featureClass in six.iteritems(featureClasses): - assert(featureClass is not None) + assert featureClass is not None if "_calculateMatrix" in dir(featureClass): logging.debug('generate_scenarios: featureClass = %s', className) yield testCase, className From 9e9b3eb137e9f1a040317d9db5aee3c94c6bad4e Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Tue, 11 Oct 2022 18:36:26 +0200 Subject: [PATCH 24/38] BUG: Fix label_channel selection bug When Label_channel column is present in the CSV input, it needs to be parsed as an int. However, due to a bug, the value for label was used instead. Related to 54a37822, but now for voxel-based extraction --- radiomics/scripts/voxel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radiomics/scripts/voxel.py b/radiomics/scripts/voxel.py index e35f2d5f..36d724b2 100644 --- a/radiomics/scripts/voxel.py +++ b/radiomics/scripts/voxel.py @@ -39,7 +39,7 @@ def extractVoxel(case_idx, case, extractor, **kwargs): label = int(label) label_channel = case.get('Label_channel', None) # Optional if isinstance(label_channel, six.string_types): - label_channel = int(label) + label_channel = int(label_channel) # Extract features result = extractor.execute(imageFilepath, maskFilepath, label, label_channel, voxelBased=True) From 0c573bc5430f0758b595c603de719411789f595b Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Tue, 13 Dec 2022 09:03:57 +0100 Subject: [PATCH 25/38] CI: Start auditwheel via python -m --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7db22750..1dad8e9e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -177,7 +177,7 @@ jobs: # Since there are no external shared libraries to bundle into the wheels # this step will fixup the wheel switching from 'linux' to 'manylinux1' tag for whl in $(ls ./dist/*-linux_$(uname -m).whl); do - auditwheel repair $whl -w ./dist/ + python -m auditwheel repair $whl -w ./dist/ rm $whl done - run: @@ -222,7 +222,7 @@ jobs: # Since there are no external shared libraries to bundle into the wheels # this step will fixup the wheel switching from 'linux' to 'manylinux1' tag for whl in $(ls ./dist/*-linux_$(uname -m).whl); do - auditwheel repair $whl -w ./dist/ + python -m auditwheel repair $whl -w ./dist/ rm $whl done - run: From 8911ea1e8a776b35642dd7c177152514a010a778 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Tue, 13 Dec 2022 09:15:58 +0100 Subject: [PATCH 26/38] CI: Fix Appveyor build Force scikit-ci to also use the configured python by first correcting the path. Removes support of python 3.6 build, also remove this from the linux build. --- .circleci/config.yml | 15 +++------------ appveyor.yml | 29 +++++++++++------------------ scikit-ci.yml | 1 - 3 files changed, 14 insertions(+), 31 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1dad8e9e..f479fa8e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -94,10 +94,10 @@ jobs: PYTHON_VERSION: 3.9.5 PYTHON_SHORT_VERSION: 3.9 - build-36: &build_template + build-37: &build_template working_directory: /pyradiomics docker: - - image: cimg/python:3.6 + - image: cimg/python:3.7 user: root steps: - checkout @@ -121,12 +121,6 @@ jobs: root: . paths: [dist] - build-37: - <<: *build_template - docker: - - image: cimg/python:3.7 - user: root - build-38: <<: *build_template docker: @@ -142,7 +136,7 @@ jobs: test_deploy: working_directory: /pyradiomics docker: - - image: cimg/python:3.6 + - image: cimg/python:3.8 user: root steps: - run: @@ -277,8 +271,6 @@ workflows: <<: *build_job_template - build-mac-39: <<: *build_job_template - - build-36: - <<: *build_job_template - build-37: <<: *build_job_template - build-38: @@ -287,7 +279,6 @@ workflows: <<: *build_job_template - test-notebooks: &requires_template requires: - - build-36 - build-37 - build-38 - build-39 diff --git a/appveyor.yml b/appveyor.yml index 819effd4..17e087c1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,35 +1,27 @@ version: "3.0.{build}" environment: + PYTHON_ARCH: "64" + BLOCK: "0" + matrix: # Visual Studio (Python 3, 64 bit) - - PYTHON_DIR: "C:\\Python36-x64" - PYTHON_VERSION: "3.6.x" - PYTHON_SHORT_VERSION: "3.6" - PYTHON_ARCH: "64" - BLOCK: "0" - - PYTHON_DIR: "C:\\Python37-x64" PYTHON_VERSION: "3.7.x" PYTHON_SHORT_VERSION: "3.7" - PYTHON_ARCH: "64" - BLOCK: "0" - PYTHON_DIR: "C:\\Python38-x64" PYTHON_VERSION: "3.8.x" PYTHON_SHORT_VERSION: "3.8" - PYTHON_ARCH: "64" - BLOCK: "0" - - PYTHON_DIR: "C:\\Python38-x64" + - PYTHON_DIR: "C:\\Python39-x64" PYTHON_VERSION: "3.9.x" PYTHON_SHORT_VERSION: "3.9" - PYTHON_ARCH: "64" - BLOCK: "0" init: + - ps: $env:PATH=$env:PYTHON_DIR + ";" + $env:PYTHON_DIR + "\\Scripts;" + $env:PATH - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - python -m pip install scikit-ci scikit-ci-addons - python -m ci_addons --install ../addons @@ -38,16 +30,16 @@ init: - ps: ../addons/appveyor/rolling-build.ps1 install: - - python -m ci install + - ci install build_script: - - python -m ci build + - ci build test_script: - - python -m ci test + - ci test after_test: - - python -m ci after_test + - ci after_test artifacts: - path: dist/* @@ -66,7 +58,8 @@ deploy_script: - echo starting Anaconda deployment - SET PATH=C:\Miniconda-x64\Scripts;%PATH% - conda config --set always_yes yes - - ./conda/configure_conda.bat && conda build ./conda --python=%PYTHON_SHORT_VERSION% --croot C:/conda-bld + - ./conda/configure_conda.bat + - conda build ./conda --python=%PYTHON_SHORT_VERSION% --croot C:/conda-bld - anaconda -t %ANACONDA_TOKEN% upload -u Radiomics C:/conda-bld/win-64/pyradiomics-*.tar.bz2 --force - echo finished deployment diff --git a/scikit-ci.yml b/scikit-ci.yml index ef36e50e..16157b43 100644 --- a/scikit-ci.yml +++ b/scikit-ci.yml @@ -4,7 +4,6 @@ before_install: appveyor: environment: - PATH: $;$\\Scripts;$ RUN_ENV: .\\..\\addons\\appveyor\\run-with-visual-studio.cmd commands: - python ../addons/appveyor/patch_vs2008.py From 2bbbb21cdfcda4e60e789f58bd8cd3e2dc11c8be Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Tue, 13 Dec 2022 11:27:36 +0100 Subject: [PATCH 27/38] CI: appveyor python version test --- appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 17e087c1..c11eef2e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,6 @@ version: "3.0.{build}" +image: Visual Studio 2019 environment: PYTHON_ARCH: "64" BLOCK: "0" @@ -23,6 +24,7 @@ environment: init: - ps: $env:PATH=$env:PYTHON_DIR + ";" + $env:PYTHON_DIR + "\\Scripts;" + $env:PATH - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + - ps: python -c "import sys;print(sys.version, sys.executable)" - python -m pip install scikit-ci scikit-ci-addons - python -m ci_addons --install ../addons - python -m pip install twine From 4f12d421feabcfc0f45e93e56c85643af681c4f6 Mon Sep 17 00:00:00 2001 From: Joost van Griethuysen Date: Tue, 13 Dec 2022 16:27:06 +0100 Subject: [PATCH 28/38] CI: Fix deployment steps - Call twine using python -m twine in Linux - Correctly setup miniconda environment in Appveyor. See also https://github.com/conda/conda/issues/8836 - Add compiler requirement conda meta.yaml --- .circleci/config.yml | 4 ++-- appveyor.yml | 11 +++++++---- conda/meta.yaml | 1 + 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f479fa8e..179f0312 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -176,7 +176,7 @@ jobs: done - run: name: Deploy source and linux wheels - command: twine upload ./dist/*.whl ./dist/*.tar.gz -u $PYPI_TEST_USER -p $PYPI_TEST_PASSWORD -r testpypi + command: python -m twine upload ./dist/*.whl ./dist/*.tar.gz -u $PYPI_TEST_USER -p $PYPI_TEST_PASSWORD -r testpypi deploy: working_directory: /pyradiomics @@ -221,7 +221,7 @@ jobs: done - run: name: Deploy source and linux wheels - command: twine upload ./dist/*.whl ./dist/*.tar.gz -u $PYPI_USER -p $PYPI_PASSWORD + command: python -m twine upload ./dist/*.whl ./dist/*.tar.gz -u $PYPI_USER -p $PYPI_PASSWORD deploy_conda: working_directory: /pyradiomics diff --git a/appveyor.yml b/appveyor.yml index c11eef2e..cfcda140 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,7 +23,7 @@ environment: init: - ps: $env:PATH=$env:PYTHON_DIR + ";" + $env:PYTHON_DIR + "\\Scripts;" + $env:PATH - - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + # - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) - ps: python -c "import sys;print(sys.version, sys.executable)" - python -m pip install scikit-ci scikit-ci-addons - python -m ci_addons --install ../addons @@ -58,9 +58,12 @@ deploy_script: - ps: if ($env:APPVEYOR_REPO_TAG_NAME -match '^v?[0-9]+(\.[0-9]+)*$') { twine upload dist/*.whl -u $Env:PYPI_USER -p $Env:PYPI_PASSWORD } - ps: if ($env:APPVEYOR_REPO_TAG_NAME -match '^v?[0-9]+(\.[0-9]+)*((a|b|rc)[0-9]+)$') { twine upload dist/*.whl -u $Env:PYPI_TEST_USER -p $Env:PYPI_TEST_PASSWORD -r testpypi } - echo starting Anaconda deployment - - SET PATH=C:\Miniconda-x64\Scripts;%PATH% - - conda config --set always_yes yes - - ./conda/configure_conda.bat + - CALL C:\Miniconda3-x64\condabin\conda.bat activate + - conda config --set always_yes yes --set changeps1 no --set anaconda_upload no + - conda config --add channels simpleitk --add channels conda-forge + - conda install conda-build + - conda install anaconda-client + - conda update -q conda - conda build ./conda --python=%PYTHON_SHORT_VERSION% --croot C:/conda-bld - anaconda -t %ANACONDA_TOKEN% upload -u Radiomics C:/conda-bld/win-64/pyradiomics-*.tar.bz2 --force - echo finished deployment diff --git a/conda/meta.yaml b/conda/meta.yaml index 1534c833..6872cc82 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -12,6 +12,7 @@ build: requirements: build: + - {{ compiler('c') }} - python - git host: From 7f49638416445728ae4c2b338a948173f80a5797 Mon Sep 17 00:00:00 2001 From: joostjm Date: Tue, 9 May 2023 13:23:43 +0200 Subject: [PATCH 29/38] DEP: Remove dependency versions Allow for newer versions to be used. Consistency in results is covered by testing. --- requirements.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/requirements.txt b/requirements.txt index 1d09b540..e533ab68 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -numpy>=1.9.2 -SimpleITK>=0.9.1 -PyWavelets>=0.4.0 -pykwalify>=1.6.0 -six>=1.10.0 +numpy +SimpleITK +PyWavelets +pykwalify +six From efb9756e4d5a27e1ccdc5a23f62950a028f57e54 Mon Sep 17 00:00:00 2001 From: joostjm Date: Tue, 9 May 2023 13:27:43 +0200 Subject: [PATCH 30/38] BUG: Force label and label_channel to int Both label and label_channel are used in SimpleITK, which is more sensitive to datatypes (i.e. will fail when either parameter is int64_t). Therefore, force these values to int. --- radiomics/generalinfo.py | 4 ++-- radiomics/imageoperations.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/radiomics/generalinfo.py b/radiomics/generalinfo.py index 0034d8cb..58c1c6e0 100644 --- a/radiomics/generalinfo.py +++ b/radiomics/generalinfo.py @@ -113,8 +113,8 @@ def addMaskElements(self, image, mask, label, prefix='original'): lssif = sitk.LabelShapeStatisticsImageFilter() lssif.Execute(mask) - self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_BoundingBox'] = lssif.GetBoundingBox(label) - self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_VoxelNum'] = lssif.GetNumberOfPixels(label) + self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_BoundingBox'] = lssif.GetBoundingBox(int(label)) + self.generalInfo[self.generalInfo_prefix + 'Mask-' + prefix + '_VoxelNum'] = lssif.GetNumberOfPixels(int(label)) labelMap = (mask == label) ccif = sitk.ConnectedComponentImageFilter() diff --git a/radiomics/imageoperations.py b/radiomics/imageoperations.py index 82a8e28a..db64f158 100644 --- a/radiomics/imageoperations.py +++ b/radiomics/imageoperations.py @@ -38,7 +38,7 @@ def getMask(mask, **kwargs): logger.info('Extracting mask at index %i', label_channel) selector = sitk.VectorIndexSelectionCastImageFilter() - selector.SetIndex(label_channel) + selector.SetIndex(int(label_channel)) mask = selector.Execute(mask) logger.debug('Force casting mask to UInt32 to ensure correct datatype.') @@ -216,7 +216,7 @@ def checkMask(imageNode, maskNode, **kwargs): correctedMask = None - label = kwargs.get('label', 1) + label = int(kwargs.get('label', 1)) minDims = kwargs.get('minimumROIDimensions', 2) minSize = kwargs.get('minimumROISize', None) @@ -316,7 +316,7 @@ def _checkROI(imageNode, maskNode, **kwargs): returned. Otherwise, a ValueError is raised. """ global logger - label = kwargs.get('label', 1) + label = int(kwargs.get('label', 1)) logger.debug('Checking ROI validity') @@ -442,7 +442,7 @@ def resampleImage(imageNode, maskNode, **kwargs): resampledPixelSpacing = kwargs['resampledPixelSpacing'] interpolator = kwargs.get('interpolator', sitk.sitkBSpline) padDistance = kwargs.get('padDistance', 5) - label = kwargs.get('label', 1) + label = int(kwargs.get('label', 1)) logger.debug('Resampling image and mask') From a52f2825fb86dba4e8b33e32cc4d8db498bc10c7 Mon Sep 17 00:00:00 2001 From: joostjm Date: Tue, 9 May 2023 13:29:27 +0200 Subject: [PATCH 31/38] DOCS: Add note on label and label_channel Label_channel was added to support 3D slicer's Segmentation format. However, with newer versions, Segmentations created in 3D slicer may be stored as labelmaps (more space efficient). Add a note to point users to this in `getMask` function. --- radiomics/imageoperations.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/radiomics/imageoperations.py b/radiomics/imageoperations.py index db64f158..621996d2 100644 --- a/radiomics/imageoperations.py +++ b/radiomics/imageoperations.py @@ -19,6 +19,13 @@ def getMask(mask, **kwargs): In this case, the mask at index ``label_channel`` is extracted. The resulting 3D volume is then treated as it were a scalar input volume (i.e. with the region of interest defined by voxels with value matching ``label``). + .. note:: + If only one or non-overlapping Segments are defined when using 3D Slicer, it may be the case that it is stored as a + labelmap (i.e. only 1 ``label_channel``, with different segmentations identified by different values for ``label``). + This is easy to check by loading the mask as a SimpleITK image and checking the `GetNumberOfComponentsPerPixel()`, + if the return value is ``1``, it is a label map (i.e. use ``label``), otherwise it is a VectorImage (i.e. use + ``label_channel``). + Finally, checks if the mask volume contains an ROI identified by ``label``. Raises a value error if the label is not present (including a list of valid labels found). From e889f944e4a2484b18534f144d547038ccac8e65 Mon Sep 17 00:00:00 2001 From: joostjm Date: Tue, 9 May 2023 15:35:09 +0200 Subject: [PATCH 32/38] TEST: Switch to pytest --- requirements-dev.txt | 3 +-- tests/testUtils.py | 34 --------------------------- tests/test_docstrings.py | 27 +++------------------- tests/test_exampleSettings.py | 24 +++++++++---------- tests/test_features.py | 19 ++++++++-------- tests/test_matrices.py | 21 ++++++++--------- tests/test_wavelet.py | 43 ++++------------------------------- 7 files changed, 40 insertions(+), 131 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 687f293d..d3315d69 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,4 @@ -nose>=1.3.7 -parameterized +pytest flake8 flake8-import-order sphinx>=1.4 diff --git a/tests/testUtils.py b/tests/testUtils.py index 3b885782..7e9d491b 100644 --- a/tests/testUtils.py +++ b/tests/testUtils.py @@ -1,11 +1,9 @@ - import ast import csv import logging import math import os -from nose_parameterized import parameterized import numpy import SimpleITK as sitk import six @@ -16,38 +14,6 @@ logger = logging.getLogger('radiomics.testing') -def custom_name_func(testcase_func, param_num, param): - """ - A custom test name function that will ensure that the tests are run such that they're batched with all tests for a - given data set are run together, avoiding re-reading the data more than necessary. Tests are run in alphabetical - order, so put the test case first. An alternate option is to right justify the test number (param_num) with zeroes - so that the numerical and alphabetical orders are the same. Not providing this method when there are more than 10 - tests results in tests running in an order similar to: - - test_*.test_scenario_0_* - - test_*.test_scenario_10_* - - test_*.test_scenario_11_* - - ... - - test_*.test_scenario_19_* - - test_*.test_scenario_1_* - - test_*.test_scenario_20_* - """ - global logger - - logger.debug('custom_name_func: function name = %s, param_num = {0:0>3}, param.args = %s'.format(param_num), - testcase_func.__name__, param.args) - return str("%s_%s" % ( - testcase_func.__name__, - parameterized.to_safe_name("_".join(str(x) for x in param.args)), - )) - - class RadiomicsTestUtils: """ This utility class reads in and stores the baseline files stored in 'data/baseline' (one per feature class) diff --git a/tests/test_docstrings.py b/tests/test_docstrings.py index 019f16c3..06be6364 100644 --- a/tests/test_docstrings.py +++ b/tests/test_docstrings.py @@ -1,39 +1,19 @@ -# to run this test, from directory above: -# setenv PYTHONPATH /path/to/pyradiomics/radiomics -# nosetests --nocapture -v tests/test_docstrings.py - import logging -from nose_parameterized import parameterized import six from radiomics import getFeatureClasses -from testUtils import custom_name_func featureClasses = getFeatureClasses() -def setup_module(module): - # runs before anything in this file - print("") # this is to get a newline after the dots - return +def pytest_generate_tests(metafunc): + metafunc.parametrize(["featureClassName", "featureName"], metafunc.cls.generate_scenarios()) class TestDocStrings: - def setup(self): - # setup before each test method - print("") # this is to get a newline after the dots - - @classmethod - def setup_class(cls): - # called before any methods in this class - print("") # this is to get a newline after the dots - - @classmethod - def teardown_class(cls): - # run after any methods in this class - print("") # this is to get a newline after the dots + @staticmethod def generate_scenarios(): global featureClasses for featureClassName, featureClass in six.iteritems(featureClasses): @@ -45,7 +25,6 @@ def generate_scenarios(): for f in featureNames: yield (featureClassName, f) - @parameterized.expand(generate_scenarios(), testcase_func_name=custom_name_func) def test_class(self, featureClassName, featureName): global featureClasses logging.info('%s', featureName) diff --git a/tests/test_exampleSettings.py b/tests/test_exampleSettings.py index eba2c226..ceeb3b0b 100644 --- a/tests/test_exampleSettings.py +++ b/tests/test_exampleSettings.py @@ -1,24 +1,24 @@ -# to run this test, from directory above: -# setenv PYTHONPATH /path/to/pyradiomics/radiomics -# nosetests --nocapture -v tests/test_exampleSettings.py - import os -from nose_parameterized import parameterized import pykwalify.core from radiomics import getParameterValidationFiles +schemaFile, schemaFuncs = getParameterValidationFiles() + +def pytest_generate_tests(metafunc): + metafunc.parametrize("settingsFile", metafunc.cls.generate_scenarios()) + + def exampleSettings_name_func(testcase_func, param_num, param): return '%s_%s' % (testcase_func.__name__, os.path.splitext(os.path.basename(param.args[0]))[0]) class TestExampleSettings: - def __init__(self): - self.schemaFile, self.schemaFuncs = getParameterValidationFiles() - def generateScenarios(): + @staticmethod + def generate_scenarios(): dataDir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'examples', 'exampleSettings') if os.path.isdir(dataDir): settingsFiles = [fname for fname in os.listdir(dataDir) if fname.endswith('.yaml') or fname.endswith('.yml')] @@ -26,10 +26,10 @@ def generateScenarios(): for fname in settingsFiles: yield os.path.join(dataDir, fname) - @parameterized.expand(generateScenarios(), testcase_func_name=exampleSettings_name_func) def test_scenarios(self, settingsFile): + global schemaFile, schemaFuncs - assert os.path.isfile(self.schemaFile) - assert os.path.isfile(self.schemaFuncs) - c = pykwalify.core.Core(source_file=settingsFile, schema_files=[self.schemaFile], extensions=[self.schemaFuncs]) + assert os.path.isfile(schemaFile) + assert os.path.isfile(schemaFuncs) + c = pykwalify.core.Core(source_file=settingsFile, schema_files=[schemaFile], extensions=[schemaFuncs]) c.validate() diff --git a/tests/test_features.py b/tests/test_features.py index 05e88d9b..29f94b78 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -1,15 +1,10 @@ -# to run this test, from directory above: -# setenv PYTHONPATH /path/to/pyradiomics/radiomics -# nosetests --nocapture -v tests/test_features.py - import logging import os -from nose_parameterized import parameterized import six from radiomics import getFeatureClasses -from testUtils import custom_name_func, RadiomicsTestUtils +from testUtils import RadiomicsTestUtils testUtils = RadiomicsTestUtils() tests = sorted(testUtils.getTests()) @@ -18,8 +13,13 @@ featureClasses = getFeatureClasses() +def pytest_generate_tests(metafunc): + metafunc.parametrize(["testCase", "featureName"], metafunc.cls.generate_scenarios()) + + class TestFeatures: + @staticmethod def generate_scenarios(): global tests, featureClasses @@ -51,17 +51,16 @@ def generate_scenarios(): for featureName in baselineFeatureNames: yield test, featureName - @parameterized.expand(generate_scenarios(), testcase_func_name=custom_name_func) - def test_scenario(self, test, featureName): + def test_scenario(self, testCase, featureName): print("") global testUtils, featureClass, featureClasses featureName = featureName.split('_') - logging.debug('test_scenario: test = %s, featureClassName = %s, featureName = %s', test, featureName[1], + logging.debug('test_scenario: test = %s, featureClassName = %s, featureName = %s', testCase, featureName[1], featureName[-1]) - testOrClassChanged = testUtils.setFeatureClassAndTestCase(featureName[1], test) + testOrClassChanged = testUtils.setFeatureClassAndTestCase(featureName[1], testCase) testImage = testUtils.getImage(featureName[0]) testMask = testUtils.getMask(featureName[0]) diff --git a/tests/test_matrices.py b/tests/test_matrices.py index b4858307..41ef07a7 100644 --- a/tests/test_matrices.py +++ b/tests/test_matrices.py @@ -1,16 +1,11 @@ -# to run this test, from directory above: -# setenv PYTHONPATH /path/to/pyradiomics/radiomics -# nosetests --nocapture -v tests/test_features.py - import logging import os -from nose_parameterized import parameterized import numpy import six from radiomics import getFeatureClasses, testCases -from testUtils import custom_name_func, RadiomicsTestUtils +from testUtils import RadiomicsTestUtils testUtils = RadiomicsTestUtils() @@ -18,8 +13,13 @@ featureClasses = getFeatureClasses() +def pytest_generate_tests(metafunc): + metafunc.parametrize(["testCase", "featureClassName"], metafunc.cls.generate_scenarios()) + + class TestMatrices: + @staticmethod def generate_scenarios(): global featureClasses @@ -32,18 +32,17 @@ def generate_scenarios(): logging.debug('generate_scenarios: featureClass = %s', className) yield testCase, className - @parameterized.expand(generate_scenarios(), testcase_func_name=custom_name_func) - def test_scenario(self, test, featureClassName): + def test_scenario(self, testCase, featureClassName): global testUtils, featureClasses - logging.debug('test_scenario: testCase = %s, featureClassName = %s', test, featureClassName) + logging.debug('test_scenario: testCase = %s, featureClassName = %s', testCase, featureClassName) - baselineFile = os.path.join(testUtils.getDataDir(), 'baseline', '%s_%s.npy' % (test, featureClassName)) + baselineFile = os.path.join(testUtils.getDataDir(), 'baseline', '%s_%s.npy' % (testCase, featureClassName)) assert os.path.isfile(baselineFile) baselineMatrix = numpy.load(baselineFile) - testUtils.setFeatureClassAndTestCase(featureClassName, test) + testUtils.setFeatureClassAndTestCase(featureClassName, testCase) testImage = testUtils.getImage('original') testMask = testUtils.getMask('original') diff --git a/tests/test_wavelet.py b/tests/test_wavelet.py index 149f2f9e..81a98a00 100644 --- a/tests/test_wavelet.py +++ b/tests/test_wavelet.py @@ -1,11 +1,6 @@ -# to run this test, from directory above: -# setenv PYTHONPATH /path/to/pyradiomics/radiomics -# nosetests --nocapture -v tests/test_features.py - import logging import os -from nose_parameterized import parameterized import numpy import SimpleITK as sitk @@ -16,40 +11,13 @@ baselineFile = '../data/baseline/wavelet.npy' -def custom_name_func(testcase_func, param_num, param): - """ - A custom test name function that will ensure that the tests are run such that they're batched with all tests for a - given data set are run together, avoiding re-reading the data more than necessary. Tests are run in alphabetical - order, so put the test case first. An alternate option is to right justify the test number (param_num) with zeroes - so that the numerical and alphabetical orders are the same. Not providing this method when there are more than 10 - tests results in tests running in an order similar to: - - test_*.test_scenario_0_* - - test_*.test_scenario_10_* - - test_*.test_scenario_11_* - - ... - - test_*.test_scenario_19_* - - test_*.test_scenario_1_* - - test_*.test_scenario_20_* - """ - global logger - - logger.debug('custom_name_func: function name = %s, param_num = {0:0>3}, param.args = %s'.format(param_num), - testcase_func.__name__, param.args) - return str("%s_%s" % ( - testcase_func.__name__, - parameterized.to_safe_name(param.args[0]), - )) +def pytest_generate_tests(metafunc): + metafunc.parametrize(["testCase", "image", "mask", "baseline"], metafunc.cls.generate_scenarios()) class TestWavelet: + @staticmethod def generate_scenarios(): global logger, testCases, baselineFile @@ -85,11 +53,10 @@ def generate_scenarios(): level = wavelet_name.split('-')[1] yield '_'.join((testCase, 'preCropped', wavelet_name)), image, mask, baselineDict[level] - @parameterized.expand(generate_scenarios(), testcase_func_name=custom_name_func) - def test_scenario(self, test, image, mask, baseline): + def test_scenario(self, testCase, image, mask, baseline): global logger, testUtils, featureClasses - logger.debug('test_scenario: testCase = %s,', test) + logger.debug('test_scenario: testCase = %s,', testCase) im_arr = sitk.GetArrayFromImage(image) ma_arr = sitk.GetArrayFromImage(mask) == 1 # Conver to boolean array, label = 1 From c341b31f76be6eb5b2247a333b27924f95a1fe30 Mon Sep 17 00:00:00 2001 From: joostjm Date: Tue, 9 May 2023 16:15:35 +0200 Subject: [PATCH 33/38] REFACTOR: Use pyproject.toml project definition --- MANIFEST.in | 3 +- pyproject.toml | 47 ++++++++++++++++++++++ scikit-ci.yml | 6 +-- setup.cfg | 22 +++++++++-- setup.py | 90 ------------------------------------------- tests/test_wavelet.py | 2 +- 6 files changed, 68 insertions(+), 102 deletions(-) create mode 100644 pyproject.toml diff --git a/MANIFEST.in b/MANIFEST.in index fb19cd77..f50e20be 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -6,7 +6,7 @@ include requirements-dev.txt include requirements-setup.txt include versioneer.py -recursive-include radiomics * +recursive-include src/radiomics * recursive-include data/baseline * recursive-include data *_image.nrrd @@ -24,4 +24,3 @@ recursive-include bin *.py recursive-exclude * __pycache__ recursive-exclude * *.py[cod] -recursive-exclude * nosetests.xml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..40034f9b --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,47 @@ +[build-system] +requires = ["setuptools>=61.0", "numpy", "versioneer"] +build-backend = "setuptools.build_meta" + +[project] +name = "pyradiomics" +version = "3.0.1a1" +authors = [ + { name = "PyRadimiomics Community", email = "pyradiomics@googlegroups.com"} +] +description = "Radiomics features library for python" +readme = "README.md" +requires-python =">=3.5" +license = { file = "LICENSE.txt"} +keywords = [ "radiomics", "cancerimaging", "medicalresearch", "computationalimaging" ] +classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Environment :: Console', + 'Intended Audience :: Developers', + 'Intended Audience :: Science/Research', + 'License :: OSI Approved :: BSD License', + 'Operating System :: OS Independent', + 'Programming Language :: C', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Topic :: Scientific/Engineering :: Bio-Informatics' +] +dependencies = [ + "numpy", + "SimpleITK", + "PyWavelets", + "pykwalify", + "six" +] + +[project.scripts] +pyradiomics = "radiomics.scripts.__init__:parse_args" + +[project.urls] +"Homepaget" = "http://github.com/AIM-Harvard/pyradiomics#readme" +"Radiomics.io" = "https://www.radiomics.io/" +"Documentation" = "https://pyradiomics.readthedocs.io/en/latest/index.html" +"Docker" = "https://hub.docker.com/r/radiomics/pyradiomics/" +"Github" = "https://github.com/AIM-Harvard/pyradiomics" diff --git a/scikit-ci.yml b/scikit-ci.yml index fba7450a..cb1b6db3 100644 --- a/scikit-ci.yml +++ b/scikit-ci.yml @@ -46,11 +46,7 @@ build: test: commands: - - $ python setup.py test --args="--with-xunit --logging-level=DEBUG" - - circleci: - commands: - - cp nosetests.xml $CIRCLE_TEST_REPORTS + - $ pytest after_test: commands: diff --git a/setup.cfg b/setup.cfg index d973f4c7..4d7af05d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,9 +1,23 @@ [metadata] -description-file = README.md +description_file = README.md -[nosetests] -verbosity=3 -where=tests +[options] +install_requires = + numpy + SimpleITK + PyWavelets + pykwalify + six +include_package_data=False + +[options.packages.find] +include=radiomics* +exclude=radiomics.schemas + +[options.package_data] +radiomics = + schemas/paramSchema.yaml + schemas/schemaFuncs.py [versioneer] VCS = git diff --git a/setup.py b/setup.py index d922a42d..eed0c4d2 100644 --- a/setup.py +++ b/setup.py @@ -2,59 +2,15 @@ from distutils import sysconfig import platform -import sys import numpy from setuptools import Extension, setup -from setuptools.command.test import test as TestCommand import versioneer -# Check if current PyRadiomics is compatible with current python installation (> 2.6, 64 bits) -if sys.version_info < (2, 6, 0): - raise Exception("pyradiomics > 0.9.7 requires python 2.6 or later") - if platform.architecture()[0].startswith('32'): raise Exception('PyRadiomics requires 64 bits python') -with open('requirements.txt', 'r') as fp: - requirements = list(filter(bool, (line.strip() for line in fp))) - -with open('requirements-dev.txt', 'r') as fp: - dev_requirements = list(filter(bool, (line.strip() for line in fp))) - -with open('requirements-setup.txt', 'r') as fp: - setup_requirements = list(filter(bool, (line.strip() for line in fp))) - -with open('README.md', 'rb') as fp: - long_description = fp.read().decode('utf-8') - - -class NoseTestCommand(TestCommand): - """Command to run unit tests using nose driver after in-place build""" - - user_options = TestCommand.user_options + [ - ("args=", None, "Arguments to pass to nose"), - ] - - def initialize_options(self): - self.args = [] - TestCommand.initialize_options(self) - - def finalize_options(self): - TestCommand.finalize_options(self) - if self.args: - self.args = __import__('shlex').split(self.args) - - def run_tests(self): - # Run nose ensuring that argv simulates running nosetests directly - nose_args = ['nosetests'] - nose_args.extend(self.args) - __import__('nose').run_exit(argv=nose_args) - - commands = versioneer.get_cmdclass() -commands['test'] = NoseTestCommand - incDirs = [sysconfig.get_python_inc(), numpy.get_include()] ext = [Extension("radiomics._cmatrices", ["radiomics/src/_cmatrices.c", "radiomics/src/cmatrices.c"], @@ -65,56 +21,10 @@ def run_tests(self): setup( name='pyradiomics', - url='http://github.com/Radiomics/pyradiomics#readme', - project_urls={ - 'Radiomics.io': 'https://www.radiomics.io/', - 'Documentation': 'https://pyradiomics.readthedocs.io/en/latest/index.html', - 'Docker': 'https://hub.docker.com/r/radiomics/pyradiomics/', - 'Github': 'https://github.com/Radiomics/pyradiomics' - }, - - author='pyradiomics community', - author_email='pyradiomics@googlegroups.com', - version=versioneer.get_version(), cmdclass=commands, packages=['radiomics', 'radiomics.scripts'], ext_modules=ext, zip_safe=False, - package_data={'radiomics': ['schemas/paramSchema.yaml', 'schemas/schemaFuncs.py']}, - - entry_points={ - 'console_scripts': [ - 'pyradiomics=radiomics.scripts.__init__:parse_args' - ]}, - - description='Radiomics features library for python', - long_description=long_description, - long_description_content_type='text/markdown', - - license='BSD License', - - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Environment :: Console', - 'Intended Audience :: Developers', - 'Intended Audience :: Science/Research', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: C', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Topic :: Scientific/Engineering :: Bio-Informatics', - ], - - keywords='radiomics cancerimaging medicalresearch computationalimaging', - - install_requires=requirements, - test_suite='nose.collector', - tests_require=dev_requirements, - setup_requires=setup_requirements ) diff --git a/tests/test_wavelet.py b/tests/test_wavelet.py index 81a98a00..2d2c71aa 100644 --- a/tests/test_wavelet.py +++ b/tests/test_wavelet.py @@ -8,7 +8,7 @@ logger = logging.getLogger('radiomics.testing') testCases = ('test_wavelet_64x64x64', 'test_wavelet_37x37x37') -baselineFile = '../data/baseline/wavelet.npy' +baselineFile = os.path.join(os.path.dirname(__file__), '../data/baseline/wavelet.npy') def pytest_generate_tests(metafunc): From 51b64b151c2a9377c6dc71461094bef8acd19491 Mon Sep 17 00:00:00 2001 From: joostjm Date: Tue, 9 May 2023 16:16:59 +0200 Subject: [PATCH 34/38] ENH: Update imports in scripts --- radiomics/scripts/__init__.py | 1 + radiomics/scripts/segment.py | 2 +- radiomics/scripts/voxel.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/radiomics/scripts/__init__.py b/radiomics/scripts/__init__.py index a9d3c222..fa7d9730 100644 --- a/radiomics/scripts/__init__.py +++ b/radiomics/scripts/__init__.py @@ -15,6 +15,7 @@ import pykwalify.core import six.moves +import radiomics import radiomics.featureextractor from . import segment, voxel diff --git a/radiomics/scripts/segment.py b/radiomics/scripts/segment.py index 8de06a63..8afc56f4 100644 --- a/radiomics/scripts/segment.py +++ b/radiomics/scripts/segment.py @@ -8,7 +8,7 @@ import SimpleITK as sitk import six -import radiomics.featureextractor +import radiomics caseLogger = logging.getLogger('radiomics.script') _parallel_extraction_configured = False diff --git a/radiomics/scripts/voxel.py b/radiomics/scripts/voxel.py index e35f2d5f..c9a12d1e 100644 --- a/radiomics/scripts/voxel.py +++ b/radiomics/scripts/voxel.py @@ -7,7 +7,7 @@ import SimpleITK as sitk import six -import radiomics.featureextractor +import radiomics caseLogger = logging.getLogger('radiomics.script') _parallel_extraction_configured = False From 3144f52654ba82087dcf4c178f18897cada13729 Mon Sep 17 00:00:00 2001 From: joostjm Date: Tue, 9 May 2023 16:55:56 +0200 Subject: [PATCH 35/38] BUG: Fix build step --- scikit-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scikit-ci.yml b/scikit-ci.yml index a20956ff..8aabcda7 100644 --- a/scikit-ci.yml +++ b/scikit-ci.yml @@ -41,7 +41,7 @@ before_build: build: commands: - - $ python setup.py build_ext + - $ python setup.py develop test: commands: From fbccb99cc6941940bd9e031cb397b189783dcf74 Mon Sep 17 00:00:00 2001 From: JoostJM Date: Wed, 17 May 2023 08:41:06 +0200 Subject: [PATCH 36/38] CI: Fix long description Fix new definition of long description to ensure it is rendered on PyPi --- setup.cfg | 4 +++- setup.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index 4d7af05d..0e28a673 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,7 @@ [metadata] -description_file = README.md +description = Radiomics features library for python +long_description = file: README.md +license = 3-Clause BSD [options] install_requires = diff --git a/setup.py b/setup.py index eed0c4d2..300c1be6 100644 --- a/setup.py +++ b/setup.py @@ -26,5 +26,5 @@ packages=['radiomics', 'radiomics.scripts'], ext_modules=ext, - zip_safe=False, + zip_safe=False ) From 038f8a8ba4f70e4f610aba95e21270618306116b Mon Sep 17 00:00:00 2001 From: JoostJM Date: Wed, 17 May 2023 08:57:13 +0200 Subject: [PATCH 37/38] DOC: Update ReadMe Update status badges in readme to reflect new CI integration. --- README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fddca725..2ce45536 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,17 @@ ## Build Status -| Linux | macOS | Windows | -| ------------------------------ | ----------------------------- | ----------------------------- | -| [![][circleci]][circleci-lnk] | [![][travisci]][travisci-lnk] | [![][appveyor]][appveyor-lnk] | +| Linux / MacOS | Windows | +|-------------------------------| ----------------------------- | +| [![][circleci]][circleci-lnk] | [![][appveyor]][appveyor-lnk] | [appveyor]: https://ci.appveyor.com/api/projects/status/kvu7897q0v4imwdc?svg=true [appveyor-lnk]: https://ci.appveyor.com/project/AIM-Harvard/pyradiomics-k4sto -[circleci]: https://circleci.com/gh/AIM-Harvard/pyradiomics.svg?style=svg&circle-token=a4748cf0de5fad2c12bc93a485282378551c3584 +[circleci]: https://dl.circleci.com/status-badge/img/gh/AIM-Harvard/pyradiomics/tree/master.svg?style=shield [circleci-lnk]: https://circleci.com/gh/AIM-Harvard/pyradiomics -[travisci]: https://travis-ci.com/AIM-Harvard/pyradiomics.svg?branch=master -[travisci-lnk]: https://travis-ci.com/AIM-Harvard/pyradiomics - ## Radiomics feature extraction in Python This is an open-source python package for the extraction of Radiomics features from medical imaging. @@ -120,7 +117,7 @@ For more information on using docker, see PyRadiomics can be easily used in a Python script through the `featureextractor` module. Furthermore, PyRadiomics provides a commandline script, `pyradiomics`, for both single image extraction and batchprocessing. Finally, a convenient front-end interface is provided as the 'Radiomics' -extension for 3D Slicer, available [here](https://github.com/Radiomics/SlicerRadiomics). +extension for 3D Slicer, available [here](https://github.com/AIM-Harvard/SlicerRadiomics). ### 3rd-party packages used in pyradiomics: - SimpleITK (Image loading and preprocessing) @@ -135,7 +132,7 @@ extension for 3D Slicer, available [here](https://github.com/Radiomics/SlicerRad See also the [requirements file](requirements.txt). ### 3D Slicer -PyRadiomics is also available as an [extension](https://github.com/Radiomics/SlicerRadiomics) to [3D Slicer](slicer.org). +PyRadiomics is also available as an [extension](https://github.com/AIM-Harvard/SlicerRadiomics) to [3D Slicer](slicer.org). Download and install the 3D slicer [nightly build](http://download.slicer.org/), the extension is then available in the extension manager under "SlicerRadiomics". From 7c53bde67d69f146d1980001f19b3443a52ddc60 Mon Sep 17 00:00:00 2001 From: JoostJM Date: Wed, 17 May 2023 11:16:06 +0200 Subject: [PATCH 38/38] DOC: Add long_description_content_type --- setup.cfg | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.cfg b/setup.cfg index 0e28a673..d4b47dff 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,7 @@ [metadata] description = Radiomics features library for python long_description = file: README.md +long_description_content_type = text/markdown license = 3-Clause BSD [options]