diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml
new file mode 100644
index 00000000..4abd3eb0
--- /dev/null
+++ b/.github/workflows/build_wheels.yml
@@ -0,0 +1,155 @@
+name: Wheels
+
+on: [ push, pull_request ]
+
+jobs:
+ build_wheels:
+ name: Build wheels on ${{ matrix.os }}
+ if: ${{ startsWith(github.ref, 'refs/tags/') || contains(github.event.head_commit.message, '[pypi]') }}
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ macos-11, macos-12, macos-13, flyci-macos-large-latest-m2, macos-14, ubuntu-latest, windows-latest ]
+
+ steps:
+ - uses: awvwgk/setup-fortran@main
+ if: matrix.os == 'windows-latest'
+ id: setup-fortran
+ with:
+ compiler: gcc
+ version: 11
+
+ - run: ln -s $(which gfortran-11) /usr/local/bin/gfortran
+ if: matrix.os != 'windows-latest'
+
+ - run: gfortran --version
+
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - uses: actions/setup-python@v5
+
+ - name: Install cibuildwheel
+ run: python -m pip install cibuildwheel==2.18.1
+
+ - name: Build macos-13 wheels
+ if: matrix.os == 'macos-13' || matrix.os == 'macos-13-xlarge' || matrix.os == 'flyci-macos-large-latest-m2'
+ env:
+ MACOSX_DEPLOYMENT_TARGET: 13
+ CIBW_BUILD: cp311-*
+ CIBW_SKIP: pp*
+ CIBW_BUILD_VERBOSITY: 1
+ run: python -m cibuildwheel --output-dir wheelhouse
+
+ - name: Build macos-12 wheels
+ if: matrix.os == 'macos-12'
+ env:
+ MACOSX_DEPLOYMENT_TARGET: 12
+ CIBW_BUILD: cp311-*
+ CIBW_SKIP: pp*
+ CIBW_BUILD_VERBOSITY: 1
+ run: python -m cibuildwheel --output-dir wheelhouse
+
+ - name: Build macos-11 wheels
+ if: matrix.os == 'macos-11'
+ env:
+ # all cp3xx, since old macs seem to only use osx 11+ builds if this is set not "none"
+ # see consistency with get_tag() in setup.py
+ MACOSX_DEPLOYMENT_TARGET: 11
+ CIBW_SKIP: pp*
+ CIBW_BUILD_VERBOSITY: 1
+ run: python -m cibuildwheel --output-dir wheelhouse
+
+ - name: Build wheels
+ if: matrix.os == 'macos-14' || matrix.os == 'ubuntu-latest' || matrix.os == 'windows-latest'
+ env:
+ MACOSX_DEPLOYMENT_TARGET: 14
+ CIBW_BUILD: cp311-*
+ CIBW_SKIP: pp* *-win32 *-manylinux_i686 *musllinux*
+ CIBW_BUILD_VERBOSITY: 1
+ run: python -m cibuildwheel --output-dir wheelhouse
+
+ - uses: actions/upload-artifact@v4
+ with:
+ name: wheels-${{ matrix.os }}
+ path: |
+ wheelhouse/*.whl
+
+ build-sdist-and-upload:
+ runs-on: ubuntu-latest
+ needs: [ 'build_wheels' ]
+ environment: wheels
+ if: github.repository_owner == 'cmbant'
+ permissions:
+ id-token: write
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ submodules: recursive
+
+ - name: Set up Python
+ uses: actions/setup-python@v5
+ with:
+ python-version: "3.10"
+ cache: pip
+ cache-dependency-path: "setup.py"
+
+ - name: Install dependencies
+ run: |
+ python -m pip install -U pip
+ python -m pip install -U build twine
+
+ - name: Download wheels from build artifacts
+ uses: actions/download-artifact@v4
+ with:
+ pattern: wheels-*
+ merge-multiple: true
+ path: dist-wheels/
+
+ - name: Build package
+ run: |
+ python -m build --sdist
+ twine check --strict dist/*
+ twine check --strict dist-wheels/*
+
+ - name: Publish wheels to PyPI Test
+ if: ${{ !startsWith(github.ref, 'refs/tags/') }}
+ uses: pypa/gh-action-pypi-publish@release/v1
+ with:
+ repository-url: https://test.pypi.org/legacy/
+ packages-dir: dist-wheels/
+
+ - name: Publish sdist to PyPI Test
+ if: ${{ !startsWith(github.ref, 'refs/tags/') }}
+ uses: pypa/gh-action-pypi-publish@release/v1
+ with:
+ repository-url: https://test.pypi.org/legacy/
+
+ - name: Publish wheels to PyPI
+ if: ${{ startsWith(github.ref, 'refs/tags/') }}
+ uses: pypa/gh-action-pypi-publish@release/v1
+ with:
+ packages-dir: dist-wheels/
+
+ - name: Publish sdist to PyPI
+ if: ${{ startsWith(github.ref, 'refs/tags/') }}
+ uses: pypa/gh-action-pypi-publish@release/v1
+
+ test_wheels:
+ name: Test wheels on ${{ matrix.os }}
+ if: contains(github.event.head_commit.message, '[testpypi]')
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ macos-11, macos-12, macos-13, flyci-macos-large-latest-m2, macos-14, ubuntu-latest, windows-latest ]
+
+ steps:
+ - uses: actions/setup-python@v5
+
+ - name: install
+ run: python -m pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ camb
+
+ - name: test
+ run: python -m unittest camb.tests.camb_test
diff --git a/.travis.yml b/.travis.yml
index d0808e61..60e6f7bf 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -88,16 +88,3 @@ script:
after_failure:
- test $TRAVIS_PULL_REQUEST == "false" && test $PYPI_DIST == "true" && test $TRAVIS_REPO_SLUG == "cmbant/CAMB" && [ -d fortran/testfiles ] && bash fortran/tests/upload_tests.sh
-before_deploy:
- - pushd fortran; make clean delete; popd
-
-deploy:
- - provider: pypi
- distributions: sdist
- username: "__token__"
- password: $PYPI_PASSWORD
- on:
- branch: master
- repo: cmbant/CAMB
- tags: true
- condition: $PYPI_DIST = true
diff --git a/README.rst b/README.rst
index 38773749..8e0a601f 100644
--- a/README.rst
+++ b/README.rst
@@ -39,9 +39,9 @@ Then install using::
pip install -e ./CAMB [--user]
-You will need gfortran 6 or higher installed to compile. Binary files for Windows are also provided, so these are used instead if no
-gfortran installation is found on Windows machines. If you have gfortran installed, "python setup.py make"
-(and other standard setup commands) will build the Fortran library on all systems (including Windows without directly using a Makefile).
+You will need gfortran 6 or higher installed to compile (usually included with gcc by default).
+If you have gfortran installed, "python setup.py make" (and other standard setup commands) will build the Fortran
+library on all systems (including Windows without directly using a Makefile).
The python wrapper provides a module called "camb" documented in the Python `CAMB documentation `_.
diff --git a/camb/__init__.py b/camb/__init__.py
index 8f66592b..54450a67 100644
--- a/camb/__init__.py
+++ b/camb/__init__.py
@@ -7,7 +7,7 @@
__author__ = "Antony Lewis"
__contact__ = "antony at cosmologist dot info"
__url__ = "https://camb.readthedocs.io"
-__version__ = "1.5.4"
+__version__ = "1.5.5"
from . import baseconfig
diff --git a/camb/cambdll.dll b/camb/cambdll.dll
deleted file mode 100644
index d7fbe665..00000000
Binary files a/camb/cambdll.dll and /dev/null differ
diff --git a/camb/sources.py b/camb/sources.py
index 373b75a5..0314d1bb 100644
--- a/camb/sources.py
+++ b/camb/sources.py
@@ -57,7 +57,7 @@ def set_table(self, z, W, bias_z=None, k_bias=None, bias_kz=None):
:param z: array of redshift values (monotonically increasing)
:param W: array of window function values. It must be well enough sampled to smoothly cubic-spline interpolate
:param bias_z: optional array of bias values at each z for scale-independent bias
- :param k_bias: optional array of k values for bias
+ :param k_bias: optional array of k values for bias (Mpc^-1)
:param bias_kz: optional 2D contiguous array for space-dependent bias(k, z).
Must ensure range of k is large enough to cover required values.
diff --git a/camb/tests/camb_test.py b/camb/tests/camb_test.py
index cfc6b41e..03b57edb 100644
--- a/camb/tests/camb_test.py
+++ b/camb/tests/camb_test.py
@@ -13,7 +13,7 @@
from camb import model, correlations, bbn, dark_energy, initialpower
from camb.baseconfig import CAMBParamRangeError, CAMBValueError
-fast = 'ci fast' in os.getenv("TRAVIS_COMMIT_MESSAGE", "")
+fast = 'ci fast' in os.getenv("TRAVIS_COMMIT_MESSAGE", "") or os.getenv("GITHUB_ACTIONS")
class CambTest(unittest.TestCase):
diff --git a/docs/source/fortran_compilers.rst b/docs/source/fortran_compilers.rst
index f90b557b..311d178a 100644
--- a/docs/source/fortran_compilers.rst
+++ b/docs/source/fortran_compilers.rst
@@ -45,7 +45,7 @@ This includes in Jupyter notebooks; just re-start the kernel or use::
import IPython
IPython.Application.instance().kernel.do_shutdown(True)
-If you want to automamatically rebuild the library from Jupyter you can do something like this::
+If you want to automatically rebuild the library from Jupyter you can do something like this::
import subprocess
import sys
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 8af74a21..426a710e 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -21,17 +21,17 @@ If you want to work on the code from `GitHub `_,
pip install -e ./CAMB [--user]
You will need ifort or gfortran 6 or higher installed (and on your path) to compile; see :ref:`fortran-compilers` for
-compiler installation details if needed. A compiled library for Windows is also provided, and is used if no
-gfortran installation is found on Windows machines. If you have gfortran installed, "python setup.py make" will build
+compiler installation details if needed. If you have gfortran installed, "python setup.py make" will build
the Fortran library on all systems (including Windows without directly using a Makefile), and can be used to update
a source installation after changes or pulling an updated version.
+The standard pip installation includes binary pre-compiled code, so no need for a Fortran compiler
+(unless you want to use custom sources/symbolic compilation features).
Anaconda users can also install from conda-forge, best making a new clean environment using::
- conda create -n camb -c conda-forge python=3.9 camb
+ conda create -n camb -c conda-forge python=3.11 camb
activate camb
-with no need for a Fortran compiler (unless you want to use custom sources/symbolic compilation features).
Check that conda installs the latest version, if not try installing
in a new clean conda environment as above.
diff --git a/fortran/config.f90 b/fortran/config.f90
index 70d5ee6c..7f56d42e 100644
--- a/fortran/config.f90
+++ b/fortran/config.f90
@@ -3,7 +3,7 @@ module config
use constants, only: const_twopi
implicit none
- character(LEN=*), parameter :: version = '1.5.4'
+ character(LEN=*), parameter :: version = '1.5.5'
integer :: FeedbackLevel = 0 !if >0 print out useful information about the model
diff --git a/pyproject.toml b/pyproject.toml
index f4030e80..64dd5822 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -8,11 +8,11 @@ authors = [
{ name = "Antony Lewis" },
]
description = "Code for Anisotropies in the Microwave Background"
-keywords= ['cosmology', 'CAMB', 'CMB']
+keywords = ['cosmology', 'CAMB', 'CMB']
readme = "docs/README_pypi.rst"
license = { file = "LICENCE.txt" }
dynamic = ["version"]
-requires-python = ">=3.6.0"
+requires-python = ">=3.7.0"
classifiers = [
"Development Status :: 5 - Production/Stable",
"Operating System :: OS Independent",
@@ -20,7 +20,6 @@ classifiers = [
"Intended Audience :: Science/Research",
"Topic :: Scientific/Engineering :: Astronomy",
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
- "Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
@@ -46,4 +45,4 @@ Tracker = "https://github.com/cmbant/camb/issues"
Licensing = "https://github.com/cmbant/camb/blob/master/LICENCE.txt"
[tool.setuptools.dynamic]
-version = {attr = "camb.__version__"}
+version = { attr = "camb.__version__" }
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 874592c7..752ad950 100644
--- a/setup.py
+++ b/setup.py
@@ -3,10 +3,12 @@
import os
import shutil
from typing import Any
-from setuptools import setup
+from setuptools import setup, Command, Extension
+from setuptools.command.build_ext import build_ext
from setuptools.command.build_py import build_py
from setuptools.command.develop import develop
-from setuptools import Command
+from setuptools.command.install import install
+from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
file_dir = os.path.abspath(os.path.dirname(__file__))
os.chdir(file_dir)
@@ -19,6 +21,7 @@
else:
DLLNAME = 'camblib.so'
+
def get_forutils():
fpath = os.getenv('FORUTILSPATH')
@@ -177,7 +180,7 @@ def make_library(cluster=False):
get_forutils()
print("Compiling source...")
subprocess.call("make python PYCAMB_OUTPUT_DIR=%s/camb/ CLUSTER_SAFE=%d" %
- (pycamb_path, int(cluster)), shell=True)
+ (pycamb_path, int(cluster if not os.getenv("GITHUB_ACTIONS") else 1)), shell=True)
subprocess.call("chmod 755 %s" % lib_file, shell=True)
if not os.path.isfile(os.path.join(pycamb_path, 'camb', DLLNAME)):
@@ -246,12 +249,41 @@ def run(self):
subprocess.call("make clean", shell=True, cwd=os.path.join(file_dir, 'fortran'))
+class BDistWheelNonPure(_bdist_wheel):
+ def finalize_options(self):
+ super().finalize_options()
+ self.root_is_pure = False
+
+ def get_tag(self):
+ _, _, plat = super().get_tag()
+ if "osx_11" in plat:
+ return _, _, plat
+ return "py3", "none", plat
+
+
+class InstallPlatlib(install):
+ def finalize_options(self):
+ super().finalize_options()
+ if self.distribution.has_ext_modules():
+ self.install_lib = self.install_platlib
+
+
+class BuildExtCommand(build_ext):
+ """Ensure built extensions are added to the correct path in the wheel."""
+
+ def run(self):
+ pass
+
+
if __name__ == "__main__":
setup(name=os.getenv('CAMB_PACKAGE_NAME', 'camb'),
zip_safe=False,
cmdclass={'build_py': SharedLibrary, 'build_cluster': SharedLibraryCluster,
'make': MakeLibrary, 'make_cluster': MakeLibraryCluster, 'clean': CleanLibrary,
- 'develop': DevelopLibrary, 'develop_cluster': DevelopLibraryCluster},
+ 'develop': DevelopLibrary, 'develop_cluster': DevelopLibraryCluster,
+ 'bdist_wheel': BDistWheelNonPure, 'install': InstallPlatlib,
+ "build_ext": BuildExtCommand},
+ ext_modules=[Extension("camb.camblib", [])],
packages=['camb', 'camb.tests'],
platforms="any",
package_data={'camb': [DLLNAME, 'HighLExtrapTemplate_lenspotentialCls.dat',