diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml new file mode 100644 index 0000000..e7bed7c --- /dev/null +++ b/.github/workflows/python-app.yml @@ -0,0 +1,76 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python application + +on: + push: + branches: [ "master", "dev", "CuPy"] + pull_request: + branches: [ "master" ] + workflow_dispatch: + +permissions: + contents: read + +env: + CURSES: False + TERM: xterm + ECLIPSE: ECLIPSE + # TESTINPUTPATH: ${{ github.workspace }}/testdata + # TESTOUTPUTPATH: ${{ github.workspace }}/testdata_output + +jobs: + build: + + # runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v3 + - name: Set up Python 3.10 + uses: actions/setup-python@v3 + with: + python-version: "3.10" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install . + + - name: Create test data folders (Mac and linux) + if: runner.os != 'Windows' + run: | + echo ${{ github.workspace }} + mkdir -p ${{ github.workspace }}/testdata ${{ github.workspace }}/testdata_output + echo "TESTINPUTPATH=${{ github.workspace }}/testdata" >> $GITHUB_ENV + echo "TESTOUTPUTPATH=${{ github.workspace }}/testdata_output" >> $GITHUB_ENV + + - name: Create test data folders for Windows + if: runner.os == 'Windows' + run: | + echo ${{ github.workspace }} + mkdir -p ${{ github.workspace }}\testdata + mkdir -p ${{ github.workspace }}\testdata_output + echo "TESTINPUTPATH=${{ github.workspace }}\testdata" >> $env:GITHUB_ENV + echo "TESTOUTPUTPATH=${{ github.workspace }}\testdata_output" >> $env:GITHUB_ENV + + - name: Echo test data folders (Mac and linux) + if: runner.os != 'Windows' + run: | + echo $TESTINPUTPATH + echo $TESTOUTPUTPATH + + - name: Echo test data folders for Windows + if: runner.os == 'Windows' + run: | + echo $env:TESTINPUTPATH + echo $env:TESTOUTPUTPATH + + - name: Test with unittest + run: | + python -m unittest discover -s ./test -p 'test_grid_division*.py' diff --git a/ez_setup.py b/ez_setup.py deleted file mode 100644 index eab51bc..0000000 --- a/ez_setup.py +++ /dev/null @@ -1,353 +0,0 @@ -#!/usr/bin/env python -"""Bootstrap setuptools installation - -To use setuptools in your package's setup.py, include this -file in the same directory and add this to the top of your setup.py:: - - from ez_setup import use_setuptools - use_setuptools() - -To require a specific version of setuptools, set a download -mirror, or use an alternate download directory, simply supply -the appropriate options to ``use_setuptools()``. - -This file can also be run as a script to install or upgrade setuptools. -""" -import contextlib -import optparse -import os -import platform -import shutil -import subprocess -import sys -import tempfile -import textwrap -import zipfile -from distutils import log - -try: - from site import USER_SITE -except ImportError: - USER_SITE = None - -DEFAULT_VERSION = "3.4.4" -DEFAULT_URL = "https://pypi.python.org/packages/source/s/setuptools/" - - -def _python_cmd(*args): - """ - Return True if the command succeeded. - """ - args = (sys.executable,) + args - return subprocess.call(args) == 0 - - -def _install(archive_filename, install_args=()): - with archive_context(archive_filename): - # installing - log.warn('Installing Setuptools') - if not _python_cmd('setup.py', 'install', *install_args): - log.warn('Something went wrong during the installation.') - log.warn('See the error message above.') - # exitcode will be 2 - return 2 - - -def _build_egg(egg, archive_filename, to_dir): - with archive_context(archive_filename): - # building an egg - log.warn('Building a Setuptools egg in %s', to_dir) - _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) - # returning the result - log.warn(egg) - if not os.path.exists(egg): - raise IOError('Could not build the egg.') - - -def get_zip_class(): - """ - Supplement ZipFile class to support context manager for Python 2.6 - """ - - class ContextualZipFile(zipfile.ZipFile): - def __enter__(self): - return self - - def __exit__(self, type, value, traceback): - self.close - - return zipfile.ZipFile if hasattr(zipfile.ZipFile, '__exit__') else \ - ContextualZipFile - - -@contextlib.contextmanager -def archive_context(filename): - # extracting the archive - tmpdir = tempfile.mkdtemp() - log.warn('Extracting in %s', tmpdir) - old_wd = os.getcwd() - try: - os.chdir(tmpdir) - with get_zip_class()(filename) as archive: - archive.extractall() - - # going in the directory - subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) - os.chdir(subdir) - log.warn('Now working in %s', subdir) - yield - - finally: - os.chdir(old_wd) - shutil.rmtree(tmpdir) - - -def _do_download(version, download_base, to_dir, download_delay): - egg = os.path.join(to_dir, 'setuptools-%s-py%d.%d.egg' - % (version, sys.version_info[0], sys.version_info[1])) - if not os.path.exists(egg): - archive = download_setuptools(version, download_base, - to_dir, download_delay) - _build_egg(egg, archive, to_dir) - sys.path.insert(0, egg) - - # Remove previously-imported pkg_resources if present (see - # https://bitbucket.org/pypa/setuptools/pull-request/7/ for details). - if 'pkg_resources' in sys.modules: - del sys.modules['pkg_resources'] - - import setuptools - setuptools.bootstrap_install_from = egg - - -def use_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, - to_dir=os.curdir, download_delay=15): - to_dir = os.path.abspath(to_dir) - rep_modules = 'pkg_resources', 'setuptools' - imported = set(sys.modules).intersection(rep_modules) - try: - import pkg_resources - except ImportError: - return _do_download(version, download_base, to_dir, download_delay) - try: - pkg_resources.require("setuptools>=" + version) - return - except pkg_resources.DistributionNotFound: - return _do_download(version, download_base, to_dir, download_delay) - except pkg_resources.VersionConflict as VC_err: - if imported: - msg = textwrap.dedent(""" - The required version of setuptools (>={version}) is not available, - and can't be installed while this script is running. Please - install a more recent version first, using - 'easy_install -U setuptools'. - - (Currently using {VC_err.args[0]!r}) - """).format(VC_err=VC_err, version=version) - sys.stderr.write(msg) - sys.exit(2) - - # otherwise, reload ok - del pkg_resources, sys.modules['pkg_resources'] - return _do_download(version, download_base, to_dir, download_delay) - - -def _clean_check(cmd, target): - """ - Run the command to download target. If the command fails, clean up before - re-raising the error. - """ - try: - subprocess.check_call(cmd) - except subprocess.CalledProcessError: - if os.access(target, os.F_OK): - os.unlink(target) - raise - - -def download_file_powershell(url, target): - """ - Download the file at url to target using Powershell (which will validate - trust). Raise an exception if the command cannot complete. - """ - target = os.path.abspath(target) - cmd = [ - 'powershell', - '-Command', - "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)" % vars(), - ] - _clean_check(cmd, target) - - -def has_powershell(): - if platform.system() != 'Windows': - return False - cmd = ['powershell', '-Command', 'echo test'] - devnull = open(os.path.devnull, 'wb') - try: - try: - subprocess.check_call(cmd, stdout=devnull, stderr=devnull) - except Exception: - return False - finally: - devnull.close() - return True - - -download_file_powershell.viable = has_powershell - - -def download_file_curl(url, target): - cmd = ['curl', url, '--silent', '--output', target] - _clean_check(cmd, target) - - -def has_curl(): - cmd = ['curl', '--version'] - devnull = open(os.path.devnull, 'wb') - try: - try: - subprocess.check_call(cmd, stdout=devnull, stderr=devnull) - except Exception: - return False - finally: - devnull.close() - return True - - -download_file_curl.viable = has_curl - - -def download_file_wget(url, target): - cmd = ['wget', url, '--quiet', '--output-document', target] - _clean_check(cmd, target) - - -def has_wget(): - cmd = ['wget', '--version'] - devnull = open(os.path.devnull, 'wb') - try: - try: - subprocess.check_call(cmd, stdout=devnull, stderr=devnull) - except Exception: - return False - finally: - devnull.close() - return True - - -download_file_wget.viable = has_wget - - -def download_file_insecure(url, target): - """ - Use Python to download the file, even though it cannot authenticate the - connection. - """ - try: - from urllib.request import urlopen - except ImportError: - from urllib2 import urlopen - src = dst = None - try: - src = urlopen(url) - # Read/write all in one block, so we don't create a corrupt file - # if the download is interrupted. - data = src.read() - dst = open(target, "wb") - dst.write(data) - finally: - if src: - src.close() - if dst: - dst.close() - - -download_file_insecure.viable = lambda: True - - -def get_best_downloader(): - downloaders = [ - download_file_powershell, - download_file_curl, - download_file_wget, - download_file_insecure, - ] - - for dl in downloaders: - if dl.viable(): - return dl - - -def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, - to_dir=os.curdir, delay=15, downloader_factory=get_best_downloader): - """ - Download setuptools from a specified location and return its filename - - `version` should be a valid setuptools version number that is available - as an egg for download under the `download_base` URL (which should end - with a '/'). `to_dir` is the directory where the egg will be downloaded. - `delay` is the number of seconds to pause before an actual download - attempt. - - ``downloader_factory`` should be a function taking no arguments and - returning a function for downloading a URL to a target. - """ - # making sure we use the absolute path - to_dir = os.path.abspath(to_dir) - zip_name = "setuptools-%s.zip" % version - url = download_base + zip_name - saveto = os.path.join(to_dir, zip_name) - if not os.path.exists(saveto): # Avoid repeated downloads - log.warn("Downloading %s", url) - downloader = downloader_factory() - downloader(url, saveto) - return os.path.realpath(saveto) - - -def _build_install_args(options): - """ - Build the arguments to 'python setup.py install' on the setuptools package - """ - return ['--user'] if options.user_install else [] - - -def _parse_args(): - """ - Parse the command line for options - """ - parser = optparse.OptionParser() - parser.add_option( - '--user', dest='user_install', action='store_true', default=False, - help='install in user site package (requires Python 2.6 or later)') - parser.add_option( - '--download-base', dest='download_base', metavar="URL", - default=DEFAULT_URL, - help='alternative URL from where to download the setuptools package') - parser.add_option( - '--insecure', dest='downloader_factory', action='store_const', - const=lambda: download_file_insecure, default=get_best_downloader, - help='Use internal, non-validating downloader' - ) - parser.add_option( - '--version', help="Specify which version to download", - default=DEFAULT_VERSION, - ) - options, args = parser.parse_args() - # positional arguments are ignored - return options - - -def main(): - """Install or upgrade setuptools and EasyInstall""" - options = _parse_args() - archive = download_setuptools( - version=options.version, - download_base=options.download_base, - downloader_factory=options.downloader_factory, - ) - return _install(archive, _build_install_args(options)) - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..2a5cb69 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,51 @@ +[build-system] +requires = ["setuptools >= 61.0"] +build-backend = 'setuptools.build_meta' + +[tool.setuptools.packages.find] +where = ["."] +include = ["nornir_imageregistration*"] + +[project] +name = "nornir_imageregistration" +version = "1.6.0" +authors = [ + { name="James Anderson", email="James.R.Anderson@utah.edu" }, +] +description = "Contains the core image registration algorithms for aligning 2d images into larger mosaics and 3D volumes" +readme = "README.md" +license = {file = "LICENSE"} +requires-python = ">=3.10" +dependencies = [ + "numpy >= 1.26", + "scipy >= 1.11", + "matplotlib >= 3.8", + "Pillow >= 10.2", + "six >= 1.16", + "hypothesis >= 6.96", + "nornir_pools @ git+https://github.com/clementsan/nornir-pools.git@dev", + "nornir_shared @ git+https://github.com/clementsan/nornir-shared.git@dev", +] +classifiers = [ + "Programming Language :: Python :: 3.10", + "Operating System :: OS Independent", + "Topic :: Scientific/Engineering", +] + +[project.scripts] +nornir-addtransforms = "nornir_imageregistration.scripts.nornir_addtransforms:Execute" +nornir-assemble-tiles = "nornir_imageregistration.scripts.nornir_assemble_tiles:Execute" +nornir-assemble = "nornir_imageregistration.scripts.nornir_assemble:Execute" +nornir-rotate-transalate = "nornir_imageregistration.scripts.nornir_rotate_translate:Execute" +nornir-slice-to-mosaic = "nornir_imageregistration.scripts.nornir_slicetomosaic:Execute" +nornir-translatemosaic = "nornir_imageregistration.scripts.nornir_translatemosaic:Execute" +nornir-scaletransform = "nornir_imageregistration.scripts.nornir_scaletransform:Execute" +nornir-stos-grid-refinement = "nornir_imageregistration.scripts.nornir_stos_grid_refinement:Execute" +nornir-show-mosaic-layout = "nornir_imageregistration.scripts.nornir_show_mosaic_layout:Execute" + +[project.optional-dependencies] +gpu = ["cupy >= 13.0"] + +[project.urls] +Homepage = "https://github.com/jamesra/nornir-imageregistration" +Issues = "https://github.com/jamesra/nornir-imageregistration/issues" diff --git a/setup.py b/setup.py deleted file mode 100644 index c0c8d4c..0000000 --- a/setup.py +++ /dev/null @@ -1,71 +0,0 @@ -""" -Created on Aug 30, 2013 - -@author: u0490822 -""" - -from ez_setup import use_setuptools - -# from setuptools import setup, find_packages -if __name__ == '__main__': - use_setuptools() - - from setuptools import setup, find_packages - - packages = find_packages() - - # OK to use pools v1.3.1, no changes made for v1.3.2 - - # Starting with 1.3.4 Image Magick 7 is required - - install_requires = ["nornir_pools>=1.5.0", - "nornir_shared>=1.5.0", - "numpy>=1.9.1", - "scipy>=0.13.2", - "matplotlib>=1.3.0", - "pillow>=9.0", - "six", - "hypothesis"] - - optional_requires = ["cupy>=12.0"] - - dependency_links = ["git+https://github.com/nornir/nornir-pools#egg=nornir_pools-1.5.0", - "git+https://github.com/nornir/nornir-shared#egg=nornir_shared-1.5.0"] - - scripts = ['nornir-addtransforms = nornir_imageregistration.scripts.nornir_addtransforms:Execute', - 'nornir-assemble-tiles = nornir_imageregistration.scripts.nornir_assemble_tiles:Execute', - 'nornir-assemble = nornir_imageregistration.scripts.nornir_assemble:Execute', - 'nornir-rotate-transalate = nornir_imageregistration.scripts.nornir_rotate_translate:Execute', - 'nornir-slice-to-mosaic = nornir_imageregistration.scripts.nornir_slicetomosaic:Execute', - 'nornir-translatemosaic = nornir_imageregistration.scripts.nornir_translatemosaic:Execute', - 'nornir-scaletransform = nornir_imageregistration.scripts.nornir_scaletransform:Execute', - 'nornir-stos-grid-refinement = nornir_imageregistration.scripts.nornir_stos_grid_refinement:Execute', - 'nornir-show-mosaic-layout = nornir_imageregistration.scripts.nornir_show_mosaic_layout:Execute' - ] - - # named_scripts = [] - - # script_template = '%s = %s' - # for script_path in scripts: - # renamed = get_script_name(script_path) - # entry = script_template % (renamed, script_path) - # named_scripts.append(entry) - - entry_points = {'console_scripts': scripts} - - classifiers = ['Programming Language :: Python :: 3.7', - 'Topic :: Scientific/Engineering'] - - setup(name='nornir_imageregistration', - zip_safe=False, - classifiers=classifiers, - version='1.5.0', - description="Contains the core image registration algorithms for aligning 2d images into larger mosaics and 3D volumes", - author="James Anderson", - author_email="James.R.Anderson@utah.edu", - url="https://github.com/nornir/nornir-imageregistration", - packages=packages, - entry_points=entry_points, - test_suite='test', - install_requires=install_requires, - dependency_links=dependency_links)