diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 54880ec6..b7e0b4f7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -16,8 +16,8 @@ jobs: fail-fast: false matrix: os: [macos-latest, ubuntu-latest] - pyver: ["3.8", "3.9", "3.10", "3.11"] - npver: ["1.20", "1.21", "1.23"] + pyver: ["3.8", "3.9", "3.10", "3.11", "3.12"] + npver: ["1.20", "1.21", "1.23", "1.26", "2.0"] exclude: - pyver: "3.11" npver: "1.20" @@ -25,6 +25,17 @@ jobs: npver: "1.21" - pyver: "3.10" npver: "1.20" + - pyver: "3.12" + npver: "1.20" + - pyver: "3.12" + npver: "1.21" + - pyver: "3.12" + npver: "1.23" + - pyver: "3.8" + npver: "2.0" + - pyver: "3.8" + npver: "1.26" + runs-on: ${{ matrix.os }} steps: @@ -38,7 +49,7 @@ jobs: - uses: conda-incubator/setup-miniconda@v2 with: python-version: ${{ matrix.pyver }} - channels: conda-forge,defaults + channels: conda-forge/label/numpy_rc,conda-forge,defaults channel-priority: strict show-channel-urls: true miniforge-version: latest diff --git a/fitsio/fitslib.py b/fitsio/fitslib.py index 7ef718ba..3d435491 100644 --- a/fitsio/fitslib.py +++ b/fitsio/fitslib.py @@ -25,7 +25,7 @@ import numpy from . import _fitsio_wrap -from .util import IS_PY3, mks, array_to_native, isstring +from .util import IS_PY3, mks, array_to_native, isstring, copy_if_needed from .header import FITSHDR from .hdu import ( ANY_HDU, IMAGE_HDU, BINARY_TBL, ASCII_TBL, @@ -957,7 +957,7 @@ def create_image_hdu(self, if IS_PY3 and img2send.dtype.char == 'U': # for python3, we convert unicode to ascii # this will error if the character is not in ascii - img2send = img2send.astype('S', copy=False) + img2send = img2send.astype('S', copy=copy_if_needed) else: self._ensure_empty_image_ok() @@ -1738,7 +1738,7 @@ def npy_obj2fits(data, name=None): else: fits_dtype = _table_npy2fits_form['S'] else: - arr0 = numpy.array(first, copy=False) + arr0 = numpy.array(first, copy=copy_if_needed) dtype0 = arr0.dtype npy_dtype = dtype0.descr[0][1][1:] if npy_dtype[0] == 'S' or npy_dtype[0] == 'U': diff --git a/fitsio/hdu/image.py b/fitsio/hdu/image.py index 8c06bcfa..a2d16c8d 100644 --- a/fitsio/hdu/image.py +++ b/fitsio/hdu/image.py @@ -27,7 +27,7 @@ from math import floor from .base import HDUBase, IMAGE_HDU -from ..util import IS_PY3, array_to_native +from ..util import IS_PY3, array_to_native, copy_if_needed # for python3 compat if IS_PY3: @@ -146,7 +146,7 @@ def write(self, img, start=0, **keys): if IS_PY3 and img_send.dtype.char == 'U': # for python3, we convert unicode to ascii # this will error if the character is not in ascii - img_send = img_send.astype('S', copy=False) + img_send = img_send.astype('S', copy=copy_if_needed) if not numpy.isscalar(start): # convert to scalar offset diff --git a/fitsio/hdu/table.py b/fitsio/hdu/table.py index f210121b..3b462b1b 100644 --- a/fitsio/hdu/table.py +++ b/fitsio/hdu/table.py @@ -36,7 +36,8 @@ array_to_native, array_to_native_c, FITSRuntimeWarning, - mks + mks, + copy_if_needed, ) from .base import HDUBase, ASCII_TBL, IMAGE_HDU, _hdu_type_map @@ -282,7 +283,7 @@ def write(self, data, firstrow=0, columns=None, names=None, slow=False, if IS_PY3 and colref.dtype.char == 'U': # for python3, we convert unicode to ascii # this will error if the character is not in ascii - colref = colref.astype('S', copy=False) + colref = colref.astype('S', copy=copy_if_needed) nonobj_arrays.append(colref) @@ -347,7 +348,7 @@ def write_column(self, column, data, firstrow=0, **keys): if IS_PY3 and data_send.dtype.char == 'U': # for python3, we convert unicode to ascii # this will error if the character is not in ascii - data_send = data_send.astype('S', copy=False) + data_send = data_send.astype('S', copy=copy_if_needed) self._verify_column_data(colnum, data_send) @@ -1420,13 +1421,13 @@ def _extract_rows(self, rows, sort=False): Extract an array of rows from an input scalar or sequence """ if rows is not None: - rows = np.array(rows, ndmin=1, copy=False, dtype='i8') + rows = np.array(rows, ndmin=1, copy=copy_if_needed, dtype='i8') if sort: rows = np.unique(rows) return rows, None # returns unique, sorted. Force i8 for 32-bit systems - sortind = np.array(rows.argsort(), dtype='i8', copy=False) + sortind = np.array(rows.argsort(), dtype='i8', copy=copy_if_needed) maxrow = self._info['nrows']-1 if rows.size > 0: @@ -1583,7 +1584,7 @@ def _maybe_decode_fits_ascii_strings_to_unicode_py3(self, array): else: new_dt.append(_dt) if do_conversion: - array = array.astype(new_dt, copy=False) + array = array.astype(new_dt, copy=copy_if_needed) return array def _convert_bool_array(self, array): @@ -1721,7 +1722,7 @@ def _read_var_column(self, colnum, rows, sortind, vstorage): descr = 'S%d' % max_size array = np.fromiter(dlist, descr) if IS_PY3: - array = array.astype('U', copy=False) + array = array.astype('U', copy=copy_if_needed) else: descr = dlist[0].dtype.str array = np.zeros((len(dlist), max_size), dtype=descr) diff --git a/fitsio/util.py b/fitsio/util.py index 562b6099..5d337be7 100644 --- a/fitsio/util.py +++ b/fitsio/util.py @@ -41,7 +41,10 @@ def cfitsio_version(asfloat=False): numpy.uint64, numpy.int64) # different for py3 -_stypes += (numpy.string_, numpy.str_) +if numpy.lib.NumpyVersion(numpy.__version__) < "1.28.0": + _stypes += (numpy.string_, numpy.str_,) +else: + _stypes += (numpy.bytes_, numpy.str_,) # for header keywords _ftypes = (float, numpy.float32, numpy.float64) @@ -134,9 +137,22 @@ def array_to_native(array, inplace=False): return output +if numpy.lib.NumpyVersion(numpy.__version__) >= "2.0.0": + copy_if_needed = None +elif numpy.lib.NumpyVersion(numpy.__version__) < "1.28.0": + copy_if_needed = False +else: + # 2.0.0 dev versions, handle cases where copy may or may not exist + try: + numpy.array([1]).__array__(copy=None) + copy_if_needed = None + except TypeError: + copy_if_needed = False + + def array_to_native_c(array_in, inplace=False): # copy only made if not C order - arr = numpy.array(array_in, order='C', copy=False) + arr = numpy.array(array_in, order='C', copy=copy_if_needed) return array_to_native(arr, inplace=inplace)