diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..5b3efcb5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,83 @@ +name: CI + +on: + push: + pull_request: + # Allow manual runs through the web UI + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-2019] + # python-version: ["3.7", "3.8", "3.9", "3.10"] + python-version: ["3.10"] + + name: Python ${{ matrix.python-version }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + architecture: 'x64' + + - name: Install mingw-w64 on Windows + if: ${{ runner.os == 'Windows' }} + uses: msys2/setup-msys2@v2 + with: + msystem: ucrt64 + update: true + install: | + mingw-w64-ucrt-x86_64-toolchain + + - name: Install on MacOS + if: ${{ matrix.os == 'macos-latest' }} + run: | + brew reinstall gcc + CC=/usr/local/bin/gcc-12 pip install ".[test]" + + - name: Print gfortran info + run: | + gfortran --version + + - name: Install on not MacOS + if: ${{ matrix.os != 'macos-latest' }} + run: | + pip install ".[test]" + + - name: Run unit and integration tests + run: | + pytest tests/ + + publish: + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-2019] + + name: Build wheel on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install mingw-w64 on Windows + if: ${{ runner.os == 'Windows' }} + uses: msys2/setup-msys2@v2 + with: + msystem: ucrt64 + update: true + install: | + mingw-w64-ucrt-x86_64-toolchain + + - name: Build and test wheels + uses: pypa/cibuildwheel@v2.16.1 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index dc2d5595..00000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,43 +0,0 @@ -# This workflow will install Python dependencies, run tests and lint with a -# variety of Python versions. For more information see: -# https://help.github.com/actions/language-and-framework-guides/ -# using-python-with-github-actions - -name: Documentation test - -on: [push, pull_request] - -jobs: - build: - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - python-version: ["3.9"] - - env: - FC: gfortran - - name: Docs ${{ matrix.python-version }} on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - - name: Install standard and test dependencies, then apexpy - run: | - pip install build - python -m build . - pip install -r docs/requirements.txt - - - name: Check documentation build - run: sphinx-build -E -b html docs dist/docs - - - name: Check documentation links - run: sphinx-build -b linkcheck docs dist/docs - - - name: Load .zenodo.json to check for errors - run: python -c "import json; json.loads(open('.zenodo.json').read())" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index c50a12bf..00000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,114 +0,0 @@ -# This workflow will install Python dependencies, run tests and lint with a -# variety of Python versions. For more information see: -# https://help.github.com/actions/language-and-framework-guides/ -# using-python-with-github-actions - -name: pytest with flake8 - -on: - pull_request: - push: - schedule: - - cron: "0 3 * * 1" # Runs 03:00 UT on Mondays - -jobs: - build: - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.7", "3.8", "3.9", "3.10"] - - name: Python ${{ matrix.python-version }} on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - architecture: 'x64' - - - name: Install standard and test dependencies on Mac/Linux - if: ${{ matrix.os != 'windows-latest' }} - run: pip install build coverage coveralls flake8 numpy pytest - - - name: Install standard and test dependencies on Windows - if: ${{ matrix.os == 'windows-latest' }} - run: | - choco install ninja mingw - choco install rtools --no-progress - echo "c:\rtools40\ucrt64\bin;" >> $env:GITHUB_PATH - gfortran --version - pip install coverage coveralls flake8 meson-python numpy pytest scipy - - - name: Install on Linux - if: ${{ matrix.os == 'ubuntu-latest' }} - run: | - python -m build . - pip install . - - - name: Install on MacOS - if: ${{ matrix.os == 'macos-latest' }} - run: | - brew reinstall gcc - CC=/usr/local/bin/gcc-12 python -m build . - CC=/usr/local/bin/gcc-12 pip install . - - - name: Install on Windows - if: ${{ matrix.os == 'windows-latest' }} - run: | - meson setup build - ninja -j 2 -C build - cd build - meson install --destdir=${{ env.Python3_ROOT_DIR }} - - - name: Test PEP8 compliance - run: flake8 . --count --show-source --statistics - - - name: Evaluate complexity - run: flake8 . --count --exit-zero --max-complexity=10 --statistics - - - name: Run unit and integration tests on Mac/Linux - if: ${{ matrix.os != 'windows-latest' }} - run: | - cd .. - coverage run --rcfile=apexpy/setup.cfg -m pytest - - - name: Run unit and integration tests on Windows - if: ${{ matrix.os == 'windows-latest' }} - run: | - cd .. - coverage run --rcfile=apexpy\setup.cfg -m pytest - - - name: Publish results to coveralls upon success on Mac/Linux - if: ${{ matrix.os != 'windows-latest' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - cd .. - coverage combine - coverage report -m - coveralls --rcfile=apexpy/setup.cfg --service=github - - - name: Publish results to coveralls upon success on Windows - if: ${{ matrix.os == 'windows-latest' }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - cd .. - coverage combine - coverage report -m - coveralls --rcfile=apexpy\setup.cfg --service=github - - - name: Create a Windows wheel - if: ${{ matrix.os == 'windows-latest' }} - run: | - mkdir dist - pip wheel . -w dist - - - name: Upload wheels - uses: actions/upload-artifact@v3 - with: - path: dist/*.whl - if-no-files-found: warn diff --git a/cibw_before_build_macos.sh b/cibw_before_build_macos.sh new file mode 100644 index 00000000..03fc72b8 --- /dev/null +++ b/cibw_before_build_macos.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -e +set -x + +sudo ln -fs /usr/local/bin/gfortran-12 /usr/local/bin/gfortran diff --git a/meson.build b/meson.build index e7f1556d..03d0af6e 100644 --- a/meson.build +++ b/meson.build @@ -81,11 +81,7 @@ is_mingw = is_windows and cc.get_id() == 'gcc' cython_c_args = [] if is_windows - # For mingw-w64, link statically against the UCRT. - gcc_link_args = ['-lucrt', '-static'] if is_mingw - add_global_link_arguments(gcc_link_args, language: ['c']) - # Force gcc to float64 long doubles for compatibility with MSVC # builds, for C only. add_global_arguments('-mlong-double-64', language: 'c') @@ -95,7 +91,7 @@ if is_windows # Manual add of MS_WIN64 macro when not using MSVC. # https://bugs.python.org/issue28267 - bitness = run_command('apexpy/_gcc_build_bitness.py').stdout().strip() + bitness = run_command('src/apexpy/_gcc_build_bitness.py').stdout().strip() if bitness == '64' add_global_arguments('-DMS_WIN64', language: ['c', 'fortran']) endif @@ -108,15 +104,13 @@ if is_windows # Windows may need the directory for Python.h added. This location # does not have the same name for all installs. This is the one # for Windows on GitHub actions - incdir_py = run_command(py3, - ['-c', 'import os; os.chdir(".."); import sys; print(os.path.join(sys.prefix, "include"))'], - check : true).stdout().strip() - inc_dirs = include_directories(incdir_numpy, incdir_f2py, incdir_py) + # incdir_py = run_command(py3, + # ['-c', 'import os; os.chdir(".."); import sys; print(os.path.join(sys.prefix, "include"))'], + # check : true).stdout().strip() + # inc_dirs = include_directories(incdir_numpy, incdir_f2py, incdir_py) endif if meson.get_compiler('fortran').get_id() == 'gcc' - add_global_link_arguments(gcc_link_args, language: ['fortran']) - # Flag needed to work around BLAS and LAPACK Gfortran dependence on # undocumented C feature when passing single character string # arguments. @@ -173,11 +167,12 @@ py3.extension_module('fortranapex', # Declare the sources py3.install_sources([ - 'apexpy/__init__.py', - 'apexpy/__main__.py', - 'apexpy/apex.py', - 'apexpy/apexsh.dat', - 'apexpy/helpers.py', - 'apexpy/igrf13coeffs.txt'], + 'src/apexpy/__init__.py', + 'src/apexpy/__main__.py', + 'src/apexpy/apex.py', + 'src/apexpy/apexsh.dat', + 'src/apexpy/helpers.py', + 'src/apexpy/igrf13coeffs.txt', + ], pure: false, subdir: 'apexpy') diff --git a/pyproject.toml b/pyproject.toml index 51255d5e..7f3ccfb2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,13 @@ [build-system] build-backend = 'mesonpy' requires = [ - "wheel", - "meson-python>=0.12.0", - "setuptools<60.0", # Do not increase, 60.0 enables vendored distutils - "Cython>=0.29.21", - "python-dev-tools", - "oldest-supported-numpy; python_version>'3.9'", - "numpy; python_version<='3.9'" + "wheel", + "meson-python>=0.12.0", + "setuptools<60.0", # Do not increase, 60.0 enables vendored distutils + "Cython>=0.29.21", + "python-dev-tools", + "oldest-supported-numpy; python_version>'3.9'", + "numpy; python_version<='3.9'" ] [project] @@ -17,7 +17,7 @@ description = "A Python wrapper for Apex coordinates" maintainers = [ {name = "Angeline G. Burrell", email = "angeline.burrell@nrl.navy.mil"}, ] -requires-python = ">=3.7" +requires-python = ">=3.8" dependencies = [ # TODO: update to "pin-compatible" once possible, see # https://github.com/FFY00/meson-python/issues/29 @@ -25,16 +25,16 @@ dependencies = [ ] readme = "README.rst" keywords = [ - "apex", - "modified apex", - "quasi-dipole", - "quasi dipole", - "coordinates", - "magnetic coordinates", - "mlt", - "magnetic local time", - "conversion", - "converting", + "apex", + "modified apex", + "quasi-dipole", + "quasi dipole", + "coordinates", + "magnetic coordinates", + "mlt", + "magnetic local time", + "conversion", + "converting", ] classifiers = [ "Development Status :: 5 - Production/Stable", @@ -47,6 +47,7 @@ classifiers = [ "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development :: Libraries", "Topic :: Scientific/Engineering :: Physics", @@ -75,3 +76,27 @@ source = "https://github.com/aburrell/apexpy" documentation = "https://apexpy.readthedocs.io/en/latest/" tracker = "https://github.com/aburrell/apexpy/issues" download = "https://github.com/aburrell/apexpy/releases" + +[tool.cibuildwheel] +build = "cp*" +build-verbosity = "3" +test-command = "pytest {project}/tests" +# Will cause the wheel to be installed with `pip install [test]` +test-extras = ["test"] +# Skip building on CPython 3.12 on all platforms (seems meson dosen't work at the moment) +# Also skip 32bit builds +skip = ["cp312-*", "*-win32", "*-manylinux_i686"] + +[tool.cibuildwheel.linux] +manylinux-i686-image = "manylinux2014" +manylinux-x86_64-image = "manylinux2014" + +[tool.cibuildwheel.macos] +before-build = "bash {project}/cibw_before_build_macos.sh" + +[tool.cibuildwheel.windows] +repair-wheel-command = "bash python/build_tools/cibw_repair_wheel_command_windows.sh {wheel} {dest_dir}" + +[[tool.cibuildwheel.overrides]] +select = "*-win_amd64" +environment = { PKG_CONFIG_PATH="c:/opt/64/lib/pkgconfig" } diff --git a/apexpy/__init__.py b/src/apexpy/__init__.py similarity index 100% rename from apexpy/__init__.py rename to src/apexpy/__init__.py diff --git a/apexpy/__main__.py b/src/apexpy/__main__.py similarity index 100% rename from apexpy/__main__.py rename to src/apexpy/__main__.py diff --git a/apexpy/_gcc_build_bitness.py b/src/apexpy/_gcc_build_bitness.py similarity index 100% rename from apexpy/_gcc_build_bitness.py rename to src/apexpy/_gcc_build_bitness.py diff --git a/apexpy/apex.py b/src/apexpy/apex.py similarity index 100% rename from apexpy/apex.py rename to src/apexpy/apex.py diff --git a/apexpy/apexsh.dat b/src/apexpy/apexsh.dat similarity index 100% rename from apexpy/apexsh.dat rename to src/apexpy/apexsh.dat diff --git a/apexpy/helpers.py b/src/apexpy/helpers.py similarity index 100% rename from apexpy/helpers.py rename to src/apexpy/helpers.py diff --git a/apexpy/igrf13coeffs.txt b/src/apexpy/igrf13coeffs.txt similarity index 100% rename from apexpy/igrf13coeffs.txt rename to src/apexpy/igrf13coeffs.txt diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apexpy/tests/test_Apex.py b/tests/test_Apex.py similarity index 100% rename from apexpy/tests/test_Apex.py rename to tests/test_Apex.py diff --git a/apexpy/tests/test_cmd.py b/tests/test_cmd.py similarity index 100% rename from apexpy/tests/test_cmd.py rename to tests/test_cmd.py diff --git a/apexpy/tests/test_convert.txt b/tests/test_convert.txt similarity index 100% rename from apexpy/tests/test_convert.txt rename to tests/test_convert.txt diff --git a/apexpy/tests/test_convert_single_line.txt b/tests/test_convert_single_line.txt similarity index 100% rename from apexpy/tests/test_convert_single_line.txt rename to tests/test_convert_single_line.txt diff --git a/apexpy/tests/test_fortranapex.py b/tests/test_fortranapex.py similarity index 100% rename from apexpy/tests/test_fortranapex.py rename to tests/test_fortranapex.py diff --git a/apexpy/tests/test_helpers.py b/tests/test_helpers.py similarity index 100% rename from apexpy/tests/test_helpers.py rename to tests/test_helpers.py