From d5bc4435ac49c6f9fa6e3ae8c200963b9fc07607 Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Sun, 25 Oct 2020 17:16:57 -0500 Subject: [PATCH 01/15] Added setup.py for pip install --- setup.py | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 setup.py diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..0085aba --- /dev/null +++ b/setup.py @@ -0,0 +1,140 @@ +import os +import platform +import subprocess +import sys +from pprint import pprint +import pathlib +import shutil + +from distutils.command.install_data import install_data +from distutils.command.install_headers import install_headers +from setuptools import setup, Extension +from setuptools.command.build_ext import build_ext +from setuptools.command.install_lib import install_lib +from setuptools.command.install_scripts import install_scripts + +# Filename for the C extension module library +c_module_name = 'galario' + +# Command line flags forwarded to CMake (for debug purpose) +cmake_cmd_args = [] +for f in sys.argv: + if f.startswith('-D'): + cmake_cmd_args.append(f) + +for f in cmake_cmd_args: + sys.argv.remove(f) + + +def _get_env_variable(name, default='OFF'): + if name not in os.environ.keys(): + return default + return os.environ[name] + + +class CMakeExtension(Extension): + def __init__(self, name, cmake_lists_dir='../..', sources=[], **kwa): + Extension.__init__(self, name, sources=sources, **kwa) + #self.cmake_lists_dir = os.path.abspath(cmake_lists_dir) + self.cmake_lists_dir = cmake_lists_dir + + +class CMakeBuild(build_ext): + + def build_extensions(self): + try: + out = subprocess.check_output(['cmake', '--version']) + except OSError: + raise RuntimeError('Cannot find CMake executable') + + for ext in self.extensions: + cmake_args = [ + '-DCMAKE_INSTALL_PREFIX=../../{}'.format(self.build_temp), + '-DGALARIO_CHECK_CUDA=0', + '-DPython_ADDITIONAL_VERSIONS={0:d}.{1:d}'.format( + sys.version_info[0], sys.version_info[1]), + ] + + cmake_args += cmake_cmd_args + + pprint(cmake_args) + + if not os.path.exists(self.build_temp): + os.makedirs(self.build_temp) + + extension_path = "{}".format(self.build_lib) + + if not os.path.exists(extension_path): + os.makedirs(extension_path) + + # Config and build the extension + subprocess.check_call(['cmake', ext.cmake_lists_dir] + cmake_args, + cwd=self.build_temp) + subprocess.check_call(['make'], cwd=self.build_temp) + subprocess.check_call(['make', 'install'], cwd=self.build_temp) + + # Copy files to the relevant location. + + bin_dir = self.build_temp + self.distribution.bin_dir = bin_dir + + pyd_path = os.path.join(bin_dir, "lib", "python{0:d}.{1:d}".format( + sys.version_info[0], sys.version_info[1]), "site-packages", + "galario") + + shutil.move(pyd_path, extension_path) + +class InstallCMakeHeaders(install_headers): + def run(self): + print(self.install_dir) + + headers = ["{0:s}/include/{1:s}".format(self.distribution.bin_dir, + header) for header in ["galario.h","galario_defs.h","galario_py.h"]] + + for header in headers: + dst = os.path.join(self.install_dir, os.path.dirname(header. + split("/")[-1])) + self.mkpath(dst) + (out, _) = self.copy_file(header, dst) + self.outfiles.append(out) + +class InstallCMakeLibsData(install_data): + def run(self): + print(self.install_dir) + + libs = ["{0:s}/lib/{1:s}".format(self.distribution.bin_dir, + lib) for lib in ["libgalario.dylib","libgalario_single.dylib"]] + + for lib in libs: + dst = os.path.join(self.install_dir, "lib", os.path.dirname(lib. + split("/")[-1])) + self.mkpath(dst) + (out, _) = self.copy_file(lib, dst) + self.outfiles.append(out) + +class InstallCMakeLibs(install_lib): + def run(self): + super().run() + + self.distribution.run_command("install_data") + self.distribution.run_command("install_headers") + +# The following line is parsed by Sphinx +version = '1.2.2' + +setup(name='galario', + version=version, + description='', + author='Marco Tazzari', + url='https://mtazzari.github.io/galario', + long_description=open('README.md').read(), + long_description_content_type='text/markdown', + install_requires=['numpy','pytest','cython'], + ext_modules=[CMakeExtension(c_module_name)], + cmdclass={ + 'build_ext': CMakeBuild, + 'install_headers': InstallCMakeHeaders, + 'install_data': InstallCMakeLibsData, + 'install_lib': InstallCMakeLibs}, + zip_safe=False, + ) From f8dd216a107dbad912f9edccd97fa538d4888dd3 Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Sun, 25 Oct 2020 22:02:59 -0500 Subject: [PATCH 02/15] Added pyproject.toml to make sure build system is set up properly. --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..0412da0 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[build-system] +requires = ["setuptools","wheel","Cython", "numpy","pytest"] From 6b8236a15a4fe9cc64fcafbbabeda0d9923b5c7c Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Sun, 25 Oct 2020 22:03:58 -0500 Subject: [PATCH 03/15] Update description in setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0085aba..b7cfd0f 100644 --- a/setup.py +++ b/setup.py @@ -124,7 +124,7 @@ def run(self): setup(name='galario', version=version, - description='', + description='Gpu Accelerated Library for Analysing Radio Interferometer Observations', author='Marco Tazzari', url='https://mtazzari.github.io/galario', long_description=open('README.md').read(), From 321443d318997358ef9d033ab5706c3e5e8c2aa5 Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Sun, 15 Nov 2020 21:15:25 -0600 Subject: [PATCH 04/15] Enable different extensions for MacOS and Linux. --- setup.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b7cfd0f..7c7f461 100644 --- a/setup.py +++ b/setup.py @@ -102,8 +102,13 @@ class InstallCMakeLibsData(install_data): def run(self): print(self.install_dir) + if sys.platform == 'darwin': + fileext = ".dylib" + else: + fileext = ".so" + libs = ["{0:s}/lib/{1:s}".format(self.distribution.bin_dir, - lib) for lib in ["libgalario.dylib","libgalario_single.dylib"]] + lib) for lib in ["libgalario"+fileext,"libgalario_single"+fileext]] for lib in libs: dst = os.path.join(self.install_dir, "lib", os.path.dirname(lib. From 56ea2546b515cd767b707e80cedb8687a571f5c1 Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Tue, 12 Jan 2021 13:55:41 -0600 Subject: [PATCH 05/15] Make sure sys.base_prefix/lib is in the RPATH for compiled libraries, as that is where they are installed to. --- setup.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 7c7f461..3202313 100644 --- a/setup.py +++ b/setup.py @@ -68,10 +68,13 @@ def build_extensions(self): os.makedirs(extension_path) # Config and build the extension - subprocess.check_call(['cmake', ext.cmake_lists_dir] + cmake_args, - cwd=self.build_temp) - subprocess.check_call(['make'], cwd=self.build_temp) - subprocess.check_call(['make', 'install'], cwd=self.build_temp) + subprocess.check_call(["env"]+ext.extra_compile_args+\ + ['cmake', ext.cmake_lists_dir] + cmake_args, + cwd=self.build_temp) + subprocess.check_call(["env"]+ext.extra_compile_args+\ + ['make'], cwd=self.build_temp) + subprocess.check_call(["env"]+ext.extra_compile_args+\ + ['make', 'install'], cwd=self.build_temp) # Copy files to the relevant location. @@ -124,6 +127,15 @@ def run(self): self.distribution.run_command("install_data") self.distribution.run_command("install_headers") +# Check which set of extra compile args are needed, based on OS. + +extra_compile_args = [] + +if sys.prefix == 'darwin': + extra_compile_args += ['LDFLAGS="-Wl,-rpath='+sys.base_prefix+'/lib"'] +else: + extra_compile_args += ['LDFLAGS="-Wl,-rpath,'+sys.base_prefix+'/lib"'] + # The following line is parsed by Sphinx version = '1.2.2' @@ -135,7 +147,8 @@ def run(self): long_description=open('README.md').read(), long_description_content_type='text/markdown', install_requires=['numpy','pytest','cython'], - ext_modules=[CMakeExtension(c_module_name)], + ext_modules=[CMakeExtension(c_module_name, + extra_compile_args=extra_compile_args)], cmdclass={ 'build_ext': CMakeBuild, 'install_headers': InstallCMakeHeaders, From 0b92b3e3d12f60d638325032a2ba8bf35ef78430 Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Mon, 18 Jan 2021 22:06:29 -0600 Subject: [PATCH 06/15] setup.py can now handle building with CUDA. --- setup.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/setup.py b/setup.py index 3202313..7a7f23e 100644 --- a/setup.py +++ b/setup.py @@ -50,7 +50,6 @@ def build_extensions(self): for ext in self.extensions: cmake_args = [ '-DCMAKE_INSTALL_PREFIX=../../{}'.format(self.build_temp), - '-DGALARIO_CHECK_CUDA=0', '-DPython_ADDITIONAL_VERSIONS={0:d}.{1:d}'.format( sys.version_info[0], sys.version_info[1]), ] @@ -111,14 +110,16 @@ def run(self): fileext = ".so" libs = ["{0:s}/lib/{1:s}".format(self.distribution.bin_dir, - lib) for lib in ["libgalario"+fileext,"libgalario_single"+fileext]] + lib) for lib in ["libgalario"+fileext,"libgalario_single"+fileext, \ + "libgalario_cuda"+fileext,"libgalario_single_cuda"+fileext]] for lib in libs: - dst = os.path.join(self.install_dir, "lib", os.path.dirname(lib. - split("/")[-1])) - self.mkpath(dst) - (out, _) = self.copy_file(lib, dst) - self.outfiles.append(out) + if os.path.exists(lib): + dst = os.path.join(self.install_dir, "lib", os.path.dirname(lib. + split("/")[-1])) + self.mkpath(dst) + (out, _) = self.copy_file(lib, dst) + self.outfiles.append(out) class InstallCMakeLibs(install_lib): def run(self): From b2a099924f9583f4f380a9c0c25a76e186cbe95c Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Wed, 4 Sep 2024 10:51:12 -0500 Subject: [PATCH 07/15] Update pip build system to use scikit-build-core --- pyproject.toml | 19 ++++- python/CMakeLists.txt | 2 +- setup.py | 159 ------------------------------------------ src/CMakeLists.txt | 8 +-- 4 files changed, 23 insertions(+), 165 deletions(-) delete mode 100644 setup.py diff --git a/pyproject.toml b/pyproject.toml index 0412da0..71e2b9c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,2 +1,19 @@ [build-system] -requires = ["setuptools","wheel","Cython", "numpy","pytest"] +requires = [ + "scikit-build-core", + "numpy", + "Cython", + "pytest", +] +build-backend="scikit_build_core.build" + +[project] +name = "galario" +version = "1.2.2" +authors = [ + { name="Marco Tazzari", email="psheehan@nrao.edu" }, +] +description = "Gpu Accelerated Library for Analysing Radio Interferometer Observations" + +[tool.scikit-build] +cmake.args = ['-DGALARIO_CHECK_CUDA=0'] diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 6ba1672..026c162 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -56,7 +56,7 @@ set(GALARIO_PYTHON_PKG_DIR "${PYTHON_PKG_DIR}" CACHE PATH "Current python instal # on unix: install .py and .so relative to ${CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT} install(DIRECTORY ${PYGALARIO_DIR} - DESTINATION "${GALARIO_PYTHON_PKG_DIR}" + DESTINATION ${SKBUILD_PLATLIB_DIR} FILES_MATCHING REGEX ".*py$|.*so$" ) diff --git a/setup.py b/setup.py deleted file mode 100644 index 7a7f23e..0000000 --- a/setup.py +++ /dev/null @@ -1,159 +0,0 @@ -import os -import platform -import subprocess -import sys -from pprint import pprint -import pathlib -import shutil - -from distutils.command.install_data import install_data -from distutils.command.install_headers import install_headers -from setuptools import setup, Extension -from setuptools.command.build_ext import build_ext -from setuptools.command.install_lib import install_lib -from setuptools.command.install_scripts import install_scripts - -# Filename for the C extension module library -c_module_name = 'galario' - -# Command line flags forwarded to CMake (for debug purpose) -cmake_cmd_args = [] -for f in sys.argv: - if f.startswith('-D'): - cmake_cmd_args.append(f) - -for f in cmake_cmd_args: - sys.argv.remove(f) - - -def _get_env_variable(name, default='OFF'): - if name not in os.environ.keys(): - return default - return os.environ[name] - - -class CMakeExtension(Extension): - def __init__(self, name, cmake_lists_dir='../..', sources=[], **kwa): - Extension.__init__(self, name, sources=sources, **kwa) - #self.cmake_lists_dir = os.path.abspath(cmake_lists_dir) - self.cmake_lists_dir = cmake_lists_dir - - -class CMakeBuild(build_ext): - - def build_extensions(self): - try: - out = subprocess.check_output(['cmake', '--version']) - except OSError: - raise RuntimeError('Cannot find CMake executable') - - for ext in self.extensions: - cmake_args = [ - '-DCMAKE_INSTALL_PREFIX=../../{}'.format(self.build_temp), - '-DPython_ADDITIONAL_VERSIONS={0:d}.{1:d}'.format( - sys.version_info[0], sys.version_info[1]), - ] - - cmake_args += cmake_cmd_args - - pprint(cmake_args) - - if not os.path.exists(self.build_temp): - os.makedirs(self.build_temp) - - extension_path = "{}".format(self.build_lib) - - if not os.path.exists(extension_path): - os.makedirs(extension_path) - - # Config and build the extension - subprocess.check_call(["env"]+ext.extra_compile_args+\ - ['cmake', ext.cmake_lists_dir] + cmake_args, - cwd=self.build_temp) - subprocess.check_call(["env"]+ext.extra_compile_args+\ - ['make'], cwd=self.build_temp) - subprocess.check_call(["env"]+ext.extra_compile_args+\ - ['make', 'install'], cwd=self.build_temp) - - # Copy files to the relevant location. - - bin_dir = self.build_temp - self.distribution.bin_dir = bin_dir - - pyd_path = os.path.join(bin_dir, "lib", "python{0:d}.{1:d}".format( - sys.version_info[0], sys.version_info[1]), "site-packages", - "galario") - - shutil.move(pyd_path, extension_path) - -class InstallCMakeHeaders(install_headers): - def run(self): - print(self.install_dir) - - headers = ["{0:s}/include/{1:s}".format(self.distribution.bin_dir, - header) for header in ["galario.h","galario_defs.h","galario_py.h"]] - - for header in headers: - dst = os.path.join(self.install_dir, os.path.dirname(header. - split("/")[-1])) - self.mkpath(dst) - (out, _) = self.copy_file(header, dst) - self.outfiles.append(out) - -class InstallCMakeLibsData(install_data): - def run(self): - print(self.install_dir) - - if sys.platform == 'darwin': - fileext = ".dylib" - else: - fileext = ".so" - - libs = ["{0:s}/lib/{1:s}".format(self.distribution.bin_dir, - lib) for lib in ["libgalario"+fileext,"libgalario_single"+fileext, \ - "libgalario_cuda"+fileext,"libgalario_single_cuda"+fileext]] - - for lib in libs: - if os.path.exists(lib): - dst = os.path.join(self.install_dir, "lib", os.path.dirname(lib. - split("/")[-1])) - self.mkpath(dst) - (out, _) = self.copy_file(lib, dst) - self.outfiles.append(out) - -class InstallCMakeLibs(install_lib): - def run(self): - super().run() - - self.distribution.run_command("install_data") - self.distribution.run_command("install_headers") - -# Check which set of extra compile args are needed, based on OS. - -extra_compile_args = [] - -if sys.prefix == 'darwin': - extra_compile_args += ['LDFLAGS="-Wl,-rpath='+sys.base_prefix+'/lib"'] -else: - extra_compile_args += ['LDFLAGS="-Wl,-rpath,'+sys.base_prefix+'/lib"'] - -# The following line is parsed by Sphinx -version = '1.2.2' - -setup(name='galario', - version=version, - description='Gpu Accelerated Library for Analysing Radio Interferometer Observations', - author='Marco Tazzari', - url='https://mtazzari.github.io/galario', - long_description=open('README.md').read(), - long_description_content_type='text/markdown', - install_requires=['numpy','pytest','cython'], - ext_modules=[CMakeExtension(c_module_name, - extra_compile_args=extra_compile_args)], - cmdclass={ - 'build_ext': CMakeBuild, - 'install_headers': InstallCMakeHeaders, - 'install_data': InstallCMakeLibsData, - 'install_lib': InstallCMakeLibs}, - zip_safe=False, - ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5c16505..2bbc782 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -127,11 +127,11 @@ endif() # cuda # it would be nice if directory would let me access all libraries but there is no such property # https://cmake.org/cmake/help/v3.0/manual/cmake-properties.7.html install (TARGETS ${install_libs} - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - RUNTIME DESTINATION bin + ARCHIVE DESTINATION ${SKBUILD_DATA_DIR}/lib + LIBRARY DESTINATION ${SKBUILD_DATA_DIR}/lib + RUNTIME DESTINATION ${SKBUILD_DATA_DIR}/bin ) -install(FILES galario.h galario_py.h galario_defs.h DESTINATION include) +install(FILES galario.h galario_py.h galario_defs.h DESTINATION ${SKBUILD_DATA_DIR}/include) ### # testing From d4973058a6b5febf051079513746598464c9c4fd Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Wed, 4 Sep 2024 10:52:16 -0500 Subject: [PATCH 08/15] ndarray.base has become read-only, so use the PyArray_SetBaseObject instead. --- python/libcommon.pyx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/python/libcommon.pyx b/python/libcommon.pyx index 5420888..353f9dd 100644 --- a/python/libcommon.pyx +++ b/python/libcommon.pyx @@ -29,6 +29,9 @@ include "galario_config.pxi" cimport galario_defs as cpp +cdef extern from "numpy/arrayobject.h": + int PyArray_SetBaseObject(np.ndarray arr, PyObject* obj) + __all__ = ['arcsec', 'deg', 'cgs_to_Jy', 'pc', 'au', '_init', '_cleanup', 'set_v_origin', 'ngpus', 'use_gpu', 'threads', @@ -82,7 +85,8 @@ cdef class ArrayWrapper: # Create a 2D array, of length `nx*ny/2+1` ndarray = np.PyArray_SimpleNewFromData(2, shape, complex_typenum, self.data_ptr) - ndarray.base = self + #ndarray.base = self + PyArray_SetBaseObject(ndarray, self) # without this, data would be cleaned up right away Py_INCREF(self) From 6b3833529cb9a256c05fdd36dffc14dbdb3fb015 Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Wed, 4 Sep 2024 14:35:02 -0500 Subject: [PATCH 09/15] Add ability to turn on CUDA compilation. --- pyproject.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 71e2b9c..03557e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,3 +17,7 @@ description = "Gpu Accelerated Library for Analysing Radio Interferometer Observ [tool.scikit-build] cmake.args = ['-DGALARIO_CHECK_CUDA=0'] + +[[tool.scikit-build.overrides]] +if.env.GALARIO_CHECK_CUDA = true +cmake.args = ['-DGALARIO_CHECK_CUDA=1'] From f2e6c9d9918aa917b70927340a7457e2c724a072 Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Thu, 5 Sep 2024 07:33:39 -0500 Subject: [PATCH 10/15] Update tests to be compatible with newer versions of numpy. --- python/utils.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/python/utils.py b/python/utils.py index 8bf3742..ceb1d14 100644 --- a/python/utils.py +++ b/python/utils.py @@ -25,7 +25,7 @@ import numpy as np from scipy.interpolate import interp1d, RectBivariateSpline -from scipy.integrate import trapz, quadrature +from scipy.integrate import trapezoid, quadrature __all__ = ["py_sampleImage", "py_sampleProfile", "py_chi2Profile", "py_chi2Image", "radial_profile", "g_sweep_prototype", "sweep_ref", @@ -217,7 +217,7 @@ def g_sweep_prototype(I, Rmin, dR, nrow, ncol, dxy, inc, dtype_image='float64'): inc_cos = np.cos(inc) # radial extent in number of image pixels covered by the profile - rmax = min(np.int(np.ceil((Rmin+nrad*dR)/dxy)), irow_center) + rmax = min(int(np.ceil((Rmin+nrad*dR)/dxy)), irow_center) row_offset = irow_center-rmax col_offset = icol_center-rmax for irow in range(rmax*2): @@ -227,7 +227,7 @@ def g_sweep_prototype(I, Rmin, dR, nrow, ncol, dxy, inc, dtype_image='float64'): rr = np.sqrt((x/inc_cos)**2. + (y)**2.) # interpolate 1D - iR = np.int(np.floor((rr-Rmin) / dR)) + iR = int(np.floor((rr-Rmin) / dR)) if iR >= nrad-1: image[irow+row_offset, jcol+col_offset] = 0. else: @@ -394,10 +394,10 @@ def int_bilin_MT(f, x, y): for i in range(len(x)): t = y[i] - np.floor(y[i]) u = x[i] - np.floor(x[i]) - y0 = f[np.int(np.floor(y[i])), np.int(np.floor(x[i]))] - y1 = f[np.int(np.floor(y[i])) + 1, np.int(np.floor(x[i]))] - y2 = f[np.int(np.floor(y[i])) + 1, np.int(np.floor(x[i])) + 1] - y3 = f[np.int(np.floor(y[i])), np.int(np.floor(x[i])) + 1] + y0 = f[int(np.floor(y[i])), int(np.floor(x[i]))] + y1 = f[int(np.floor(y[i])) + 1, int(np.floor(x[i]))] + y2 = f[int(np.floor(y[i])) + 1, int(np.floor(x[i])) + 1] + y3 = f[int(np.floor(y[i])), int(np.floor(x[i])) + 1] vis_int[i] = t * u * (y0 - y1 + y2 - y3) vis_int[i] += t * (y1 - y0) From e0113b0174e5c15c9c2b66a48ee3266dbe73d2ed Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Wed, 4 Sep 2024 16:57:21 -0500 Subject: [PATCH 11/15] Update unit-tests.yml to use scikit-build-core build --- .github/workflows/unit-tests.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 14d0728..e9e83eb 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -6,7 +6,11 @@ name: tests and docs # workflows running on Linux and MacOS have passwordless sudo rights: # https://stackoverflow.com/questions/57982945/how-to-apt-get-install-in-a-github-actions-workflow -on: push +on: + push: + branches: + - "master" + - "unit-tests_workflow_updates" jobs: test: @@ -18,7 +22,7 @@ jobs: shell: bash -l {0} strategy: matrix: - python-version: [ 3.6, 3.7, 3.8, 3.9 ] + python-version: [ 3.8, 3.9, '3.10', 3.11 ] env: OMP_NUM_THREADS: 2 steps: @@ -45,12 +49,9 @@ jobs: - name: Build and install galario, build docs run: | conda activate test - conda install astropy cython nomkl numpy pytest scipy sphinx + conda install astropy cython nomkl numpy pytest scipy sphinx scikit-build-core pip install coverage codecov pytest-cov - mkdir build && cd build - cmake -DCMAKE_INSTALL_PREFIX=/tmp -DCMAKE_PREFIX_PATH=${CONDA_PREFIX} .. - make - make install + pip install . - name: Run unit tests run: python/py.test.sh -sv --cov=./ python/test_galario.py working-directory: build From 1b56ec05c0f5ed17c159e9a1a8e6ba552f81be74 Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Thu, 5 Sep 2024 07:33:39 -0500 Subject: [PATCH 12/15] Update tests to be compatible with newer versions of numpy. --- python/utils.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/python/utils.py b/python/utils.py index 8bf3742..ceb1d14 100644 --- a/python/utils.py +++ b/python/utils.py @@ -25,7 +25,7 @@ import numpy as np from scipy.interpolate import interp1d, RectBivariateSpline -from scipy.integrate import trapz, quadrature +from scipy.integrate import trapezoid, quadrature __all__ = ["py_sampleImage", "py_sampleProfile", "py_chi2Profile", "py_chi2Image", "radial_profile", "g_sweep_prototype", "sweep_ref", @@ -217,7 +217,7 @@ def g_sweep_prototype(I, Rmin, dR, nrow, ncol, dxy, inc, dtype_image='float64'): inc_cos = np.cos(inc) # radial extent in number of image pixels covered by the profile - rmax = min(np.int(np.ceil((Rmin+nrad*dR)/dxy)), irow_center) + rmax = min(int(np.ceil((Rmin+nrad*dR)/dxy)), irow_center) row_offset = irow_center-rmax col_offset = icol_center-rmax for irow in range(rmax*2): @@ -227,7 +227,7 @@ def g_sweep_prototype(I, Rmin, dR, nrow, ncol, dxy, inc, dtype_image='float64'): rr = np.sqrt((x/inc_cos)**2. + (y)**2.) # interpolate 1D - iR = np.int(np.floor((rr-Rmin) / dR)) + iR = int(np.floor((rr-Rmin) / dR)) if iR >= nrad-1: image[irow+row_offset, jcol+col_offset] = 0. else: @@ -394,10 +394,10 @@ def int_bilin_MT(f, x, y): for i in range(len(x)): t = y[i] - np.floor(y[i]) u = x[i] - np.floor(x[i]) - y0 = f[np.int(np.floor(y[i])), np.int(np.floor(x[i]))] - y1 = f[np.int(np.floor(y[i])) + 1, np.int(np.floor(x[i]))] - y2 = f[np.int(np.floor(y[i])) + 1, np.int(np.floor(x[i])) + 1] - y3 = f[np.int(np.floor(y[i])), np.int(np.floor(x[i])) + 1] + y0 = f[int(np.floor(y[i])), int(np.floor(x[i]))] + y1 = f[int(np.floor(y[i])) + 1, int(np.floor(x[i]))] + y2 = f[int(np.floor(y[i])) + 1, int(np.floor(x[i])) + 1] + y3 = f[int(np.floor(y[i])), int(np.floor(x[i])) + 1] vis_int[i] = t * u * (y0 - y1 + y2 - y3) vis_int[i] += t * (y1 - y0) From 4eafadba915db15eca16a014c9dc14fdc6d22c94 Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Thu, 5 Sep 2024 10:38:30 -0500 Subject: [PATCH 13/15] Update pytest call and build documentation with modern Sphinx and using sphinx-build instead of cmake. --- .github/workflows/unit-tests.yml | 9 +++-- CMakeLists.txt | 12 +++---- docs/CMakeLists.txt | 57 -------------------------------- docs/{conf.py.in => conf.py} | 4 +-- 4 files changed, 12 insertions(+), 70 deletions(-) delete mode 100644 docs/CMakeLists.txt rename docs/{conf.py.in => conf.py} (99%) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index e9e83eb..b026217 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -53,20 +53,19 @@ jobs: pip install coverage codecov pytest-cov pip install . - name: Run unit tests - run: python/py.test.sh -sv --cov=./ python/test_galario.py - working-directory: build + run: pytest -sv --cov=./ python/test_galario.py + #working-directory: build - name: Upload code coverage report run: bash <(curl -s https://codecov.io/bash) || echo 'Codecov failed to upload' - name: build docs run: | conda activate test pip install sphinx_py3doc_enhanced_theme sphinxcontrib-fulltoc - cd build - make docs + sphinx-build -M html docs docs/build - name: deploy docs if: github.ref == 'refs/heads/master' && matrix.python-version == '3.7' uses: JamesIves/github-pages-deploy-action@4.1.0 with: branch: gh-pages # The branch the action should deploy to. - folder: build/docs/html # The folder the action should deploy. + folder: docs/build/html # The folder the action should deploy. dry-run: false diff --git a/CMakeLists.txt b/CMakeLists.txt index d1a5c32..e609b0d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,12 +99,12 @@ else() message(STATUS "Skipping the ${PROJECT_NAME} python wrapper") endif() -find_package(Sphinx) -if(SPHINX_FOUND) - add_subdirectory(docs) -else() - message(STATUS "Cannot build the documentation without sphinx") -endif() +#find_package(Sphinx) +#if(SPHINX_FOUND) +# add_subdirectory(docs) +#else() +# message(STATUS "Cannot build the documentation without sphinx") +#endif() ### # uninstall target diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt deleted file mode 100644 index 6eb38ad..0000000 --- a/docs/CMakeLists.txt +++ /dev/null @@ -1,57 +0,0 @@ -# https://eb2.co/blog/2012/03/sphinx-and-cmake-beautiful-documentation-for-c-projects/ - -if(NOT DEFINED SPHINX_THEME) - set(SPHINX_THEME default) -endif() - -if(NOT DEFINED SPHINX_THEME_DIR) - set(SPHINX_THEME_DIR) -endif() - -# configured documentation tools and intermediate build results -set(BINARY_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/_build") - -# Sphinx cache with pickled ReST documents -set(SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees") - -# HTML output directory -set(SPHINX_HTML_DIR "${CMAKE_CURRENT_BINARY_DIR}/html") - -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in" - "${BINARY_BUILD_DIR}/conf.py" - @ONLY) - -# sphinx requires a _static directory, even if it's empty -file(MAKE_DIRECTORY "${BINARY_BUILD_DIR}/_static") - -# copy the _static/css directory with overridden css -file(MAKE_DIRECTORY "${BINARY_BUILD_DIR}/_static/css") -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/_static/css/custom.css" - "${BINARY_BUILD_DIR}/_static/css/custom.css" - @ONLY) - -# copy the _templates directory with overridden templates -file(MAKE_DIRECTORY "${BINARY_BUILD_DIR}/_templates") -configure_file( - "${CMAKE_CURRENT_SOURCE_DIR}/_templates/layout.html" - "${BINARY_BUILD_DIR}/_templates/layout.html" - @ONLY) - -# github pages imposes jekyll theme by default. To avoid that, we need -# a `.nojekyll` file in the gh-pages branch file(WRITE -# "${SPHINX_HTML_DIR}/.nojekyll" "") - -add_custom_target(docs ALL - ${SPHINX_EXECUTABLE} - -q -b html - -c "${BINARY_BUILD_DIR}" - -d "${SPHINX_CACHE_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}" - "${SPHINX_HTML_DIR}" - COMMENT "Building HTML documentation with Sphinx") - -# sphinx can fail if it doesn't find the theme. This should not prevent building -# the actual source code, so docs have to be built explicitly -set_target_properties(docs PROPERTIES EXCLUDE_FROM_ALL TRUE) diff --git a/docs/conf.py.in b/docs/conf.py similarity index 99% rename from docs/conf.py.in rename to docs/conf.py index 26de1cd..22c72d0 100644 --- a/docs/conf.py.in +++ b/docs/conf.py @@ -72,7 +72,7 @@ # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: @@ -307,4 +307,4 @@ # override CSS file def setup(app): - app.add_stylesheet('css/custom.css') + app.add_css_file('css/custom.css') From f7fc05dd3073a4a4da2ff6e1f130ef5e339f2a26 Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Thu, 5 Sep 2024 21:26:47 -0500 Subject: [PATCH 14/15] Add a workflow to (eventually) deploy to PyPI --- .github/workflows/python-publish.yml | 121 +++++++++++++++++++++++++++ pyproject.toml | 1 + 2 files changed, 122 insertions(+) create mode 100644 .github/workflows/python-publish.yml diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..6dc27c4 --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,121 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries + +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +name: Upload Python Package + +on: + release: + types: [published] + push: + branches: + - "master" + - "add_deploy_workflow" + +permissions: + contents: read + +jobs: + #build_wheels: + + #runs-on: ${{ matrix.os }} + + #strategy: + # matrix: + # os: [ubuntu-latest] + + #steps: + #- uses: actions/checkout@v4 + #- name: Set up Python + # uses: actions/setup-python@v5 + + #- name: Install dependencies + # run: | + # python -m pip install --upgrade pip + # python -m pip install cibuildwheel==2.20.0 + + #- name: Build wheels + # run: python -m cibuildwheel --output-dir dist + # env: + # CIBW_SKIP: cp36-* + # CIBW_BEFORE_BUILD_LINUX: yum install -y fftw-devel || apk add --upgrade fftw-dev || apt-get install libfftw3-dev + # CIBW_BEFORE_BUILD_MACOS: brew install fftw + + #- uses: actions/upload-artifact@v4 + # with: + # name: dist-${{ matrix.os }}-${{ strategy.job-index }} + # path: dist/*.whl + + build_sdist: + + runs-on: [ubuntu-latest] + + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + + - name: Install FFTW3 on Linux + run: sudo apt-get install libfftw3-dev + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install build + + - name: Build package + run: python -m build + + - name: Upload sdist + uses: actions/upload-artifact@v4 + with: + name: dist-sdist + path: dist/*.tar.gz + + upload_pypi: + needs: [build_sdist] + runs-on: ubuntu-latest + if: github.event_name == 'release' && github.event.action == 'published' + steps: + - uses: actions/download-artifact@v4 + with: + name: dist + path: dist + #- name: Publish package + # uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 + # with: + # user: __token__ + # password: ${{ secrets.PYPI_API_TOKEN }} + + publish-to-testpypi: + name: Publish Python 🐍 distribution 📦 to TestPyPI + needs: + #- build_wheels + - build_sdist + runs-on: ubuntu-latest + + environment: + name: testpypi + url: https://test.pypi.org/p/galario + + permissions: + id-token: write # IMPORTANT: mandatory for trusted publishing + + steps: + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + path: dist + pattern: dist-* + merge-multiple: true + - name: check downloaded files + run: | + ls dist/ + - name: Publish distribution 📦 to TestPyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ diff --git a/pyproject.toml b/pyproject.toml index 03557e0..21be900 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,7 @@ authors = [ { name="Marco Tazzari", email="psheehan@nrao.edu" }, ] description = "Gpu Accelerated Library for Analysing Radio Interferometer Observations" +readme = "README.md" [tool.scikit-build] cmake.args = ['-DGALARIO_CHECK_CUDA=0'] From f61b0b0c34d3b2beac3c8fbbc33176780639efb6 Mon Sep 17 00:00:00 2001 From: Patrick Sheehan Date: Thu, 12 Sep 2024 10:42:56 -0500 Subject: [PATCH 15/15] Move to publishing on PyPI now that the workflow is set up properly. --- .github/workflows/python-publish.yml | 32 ++++++---------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 6dc27c4..460373b 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -14,7 +14,6 @@ on: push: branches: - "master" - - "add_deploy_workflow" permissions: contents: read @@ -76,31 +75,17 @@ jobs: name: dist-sdist path: dist/*.tar.gz - upload_pypi: - needs: [build_sdist] - runs-on: ubuntu-latest - if: github.event_name == 'release' && github.event.action == 'published' - steps: - - uses: actions/download-artifact@v4 - with: - name: dist - path: dist - #- name: Publish package - # uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 - # with: - # user: __token__ - # password: ${{ secrets.PYPI_API_TOKEN }} - - publish-to-testpypi: - name: Publish Python 🐍 distribution 📦 to TestPyPI + publish-to-pypi: + name: Publish Python 🐍 distribution 📦 to PyPI needs: #- build_wheels - build_sdist runs-on: ubuntu-latest + if: github.event_name == 'release' && github.event.action == 'published' environment: - name: testpypi - url: https://test.pypi.org/p/galario + name: pypi + url: https://pypi.org/p/galario permissions: id-token: write # IMPORTANT: mandatory for trusted publishing @@ -112,10 +97,5 @@ jobs: path: dist pattern: dist-* merge-multiple: true - - name: check downloaded files - run: | - ls dist/ - - name: Publish distribution 📦 to TestPyPI + - name: Publish distribution 📦 to PyPI uses: pypa/gh-action-pypi-publish@release/v1 - with: - repository-url: https://test.pypi.org/legacy/