1From 1e02dbe5533d679b9ef064078a303607a7d0542a Mon Sep 17 00:00:00 2001
2From: Alexander Kanavin <alex@linutronix.de>
3Date: Fri, 29 Dec 2023 14:33:38 +0100
4Subject: [PATCH] Fix Cython 3 compatibility
5
6Upstream-Status: Backport [https://github.com/h5py/h5py/pull/2345/commits]
7Signed-off-by: Alexander Kanavin <alex@linutronix.de>
8---
9 benchmarks/benchmark_slicing.py    | 12 ++++----
10 docs/conf.py                       |  2 +-
11 docs/high/dataset.rst              |  4 +--
12 docs/high/file.rst                 |  6 ++--
13 docs/requirements-rtd.txt          |  5 ++--
14 docs/vds.rst                       |  2 +-
15 docs/whatsnew/3.0.rst              |  2 +-
16 docs/whatsnew/3.7.rst              |  4 +--
17 h5py/_errors.pxd                   | 10 +++----
18 h5py/_errors.pyx                   |  4 +--
19 h5py/_hl/base.py                   |  4 +--
20 h5py/_hl/dataset.py                |  8 ++---
21 h5py/_hl/dims.py                   |  3 +-
22 h5py/_hl/files.py                  |  2 +-
23 h5py/_locks.pxi                    |  6 ++--
24 h5py/_proxy.pyx                    |  4 +--
25 h5py/_selector.pyx                 |  2 +-
26 h5py/api_compat.h                  | 13 ++++----
27 h5py/api_types_hdf5.pxd            | 48 +++++++++++++++---------------
28 h5py/h5fd.pyx                      | 38 ++++++++++++++++-------
29 h5py/h5p.pyx                       |  4 +--
30 h5py/h5t.pyx                       |  2 +-
31 h5py/tests/test_attrs_data.py      |  2 +-
32 h5py/tests/test_big_endian_file.py |  4 +--
33 h5py/tests/test_dataset.py         |  4 +--
34 h5py/tests/test_file.py            |  6 ++--
35 h5py/tests/test_file_alignment.py  |  4 +--
36 h5py/tests/test_group.py           |  4 +--
37 h5py/tests/test_selections.py      |  2 +-
38 pylintrc                           |  2 +-
39 pyproject.toml                     |  2 +-
40 setup_configure.py                 |  2 +-
41 tox.ini                            |  2 +-
42 33 files changed, 116 insertions(+), 103 deletions(-)
43
44diff --git a/benchmarks/benchmark_slicing.py b/benchmarks/benchmark_slicing.py
45index e9a34dad..b833f012 100644
46--- a/benchmarks/benchmark_slicing.py
47+++ b/benchmarks/benchmark_slicing.py
48@@ -7,7 +7,7 @@ import logging
49 logger = logging.getLogger(__name__)
50 import h5py
51
52-#Needed for mutithreading:
53+#Needed for multithreading:
54 from queue import Queue
55 from threading import Thread, Event
56 import multiprocessing
57@@ -173,8 +173,8 @@ class SlicingBenchmark:
58
59 if __name__ == "__main__":
60     logging.basicConfig(level=logging.INFO)
61-    benckmark = SlicingBenchmark()
62-    benckmark.setup()
63-    benckmark.time_sequential_reads()
64-    benckmark.time_threaded_reads()
65-    benckmark.teardown()
66+    benchmark = SlicingBenchmark()
67+    benchmark.setup()
68+    benchmark.time_sequential_reads()
69+    benchmark.time_threaded_reads()
70+    benchmark.teardown()
71diff --git a/docs/conf.py b/docs/conf.py
72index 93b23939..a0f6c1ac 100644
73--- a/docs/conf.py
74+++ b/docs/conf.py
75@@ -109,7 +109,7 @@ pygments_style = 'sphinx'
76
77 # The theme to use for HTML and HTML Help pages.  See the documentation for
78 # a list of builtin themes.
79-html_theme = 'default'
80+html_theme = 'sphinx_rtd_theme'
81
82 # Theme options are theme-specific and customize the look and feel of a theme
83 # further.  For a list of options available for each theme, see the
84diff --git a/docs/high/dataset.rst b/docs/high/dataset.rst
85index 0f27284f..cb75fffe 100644
86--- a/docs/high/dataset.rst
87+++ b/docs/high/dataset.rst
88@@ -58,7 +58,7 @@ the requested ``dtype``.
89 Reading & writing data
90 ----------------------
91
92-HDF5 datasets re-use the NumPy slicing syntax to read and write to the file.
93+HDF5 datasets reuse the NumPy slicing syntax to read and write to the file.
94 Slice specifications are translated directly to HDF5 "hyperslab"
95 selections, and are a fast and efficient way to access data in the file. The
96 following slicing arguments are recognized:
97@@ -464,7 +464,7 @@ Reference
98         >>> dset = f["MyDS"]
99         >>> f.close()
100         >>> if dset:
101-        ...     print("datset accessible")
102+        ...     print("dataset accessible")
103         ... else:
104         ...     print("dataset inaccessible")
105         dataset inaccessible
106diff --git a/docs/high/file.rst b/docs/high/file.rst
107index 484498ce..e757fe1a 100644
108--- a/docs/high/file.rst
109+++ b/docs/high/file.rst
110@@ -392,7 +392,7 @@ Data alignment
111 When creating datasets within files, it may be advantageous to align the offset
112 within the file itself. This can help optimize read and write times if the data
113 become aligned with the underlying hardware, or may help with parallelism with
114-MPI. Unfortunately, aligning small variables to large blocks can leave alot of
115+MPI. Unfortunately, aligning small variables to large blocks can leave a lot of
116 empty space in a file. To this effect, application developers are left with two
117 options to tune the alignment of data within their file.  The two variables
118 ``alignment_threshold`` and ``alignment_interval``  in the :class:`File`
119@@ -415,7 +415,7 @@ number of regions. Setting a small value can reduce the overall file size,
120 especially in combination with the ``libver`` option. This controls how the
121 overall data and metadata are laid out within the file.
122
123-For more information, see the offical HDF5 documentation `H5P_SET_META_BLOCK_SIZE
124+For more information, see the official HDF5 documentation `H5P_SET_META_BLOCK_SIZE
125 <https://portal.hdfgroup.org/display/HDF5/H5P_SET_META_BLOCK_SIZE>`_.
126
127 Reference
128@@ -497,7 +497,7 @@ Reference
129             Only available with HDF5 >= 1.12.1 or 1.10.x >= 1.10.7.
130     :param alignment_threshold: Together with ``alignment_interval``, this
131             property ensures that any file object greater than or equal
132-            in size to the alignement threshold (in bytes) will be
133+            in size to the alignment threshold (in bytes) will be
134             aligned on an address which is a multiple of alignment interval.
135     :param alignment_interval: This property should be used in conjunction with
136             ``alignment_threshold``. See the description above. For more
137diff --git a/docs/requirements-rtd.txt b/docs/requirements-rtd.txt
138index e67a3eee..52096927 100644
139--- a/docs/requirements-rtd.txt
140+++ b/docs/requirements-rtd.txt
141@@ -1,3 +1,2 @@
142-sphinx==4.3.0
143-sphinx_rtd_theme==1.0.0
144-readthedocs-sphinx-search==0.1.1
145+sphinx==7.2.6
146+sphinx_rtd_theme==1.3.0
147diff --git a/docs/vds.rst b/docs/vds.rst
148index a9a7c7f6..bd47ad1c 100644
149--- a/docs/vds.rst
150+++ b/docs/vds.rst
151@@ -124,7 +124,7 @@ Reference
152    slice it to indicate which regions should be used in the virtual dataset.
153
154    When `creating a virtual dataset <creating_vds_>`_, paths to sources present
155-   in the same file are changed to a ".", refering to the current file (see
156+   in the same file are changed to a ".", referring to the current file (see
157    `H5Pset_virtual <https://portal.hdfgroup.org/display/HDF5/H5P_SET_VIRTUAL>`_).
158    This will keep such sources valid in case the file is renamed.
159
160diff --git a/docs/whatsnew/3.0.rst b/docs/whatsnew/3.0.rst
161index db30ad66..ff3c2bef 100644
162--- a/docs/whatsnew/3.0.rst
163+++ b/docs/whatsnew/3.0.rst
164@@ -44,7 +44,7 @@ New features
165   See also the deprecation related to the ``external`` argument.
166 * Support for setting file space strategy at file creation. Includes option to
167   persist empty space tracking between sessions. See :class:`.File` for details.
168-* More efficient writing when assiging a scalar to a chunked dataset, when the
169+* More efficient writing when assigning a scalar to a chunked dataset, when the
170   number of elements to write is no more than the size of one chunk.
171 * Introduced support for the split :ref:`file driver <file_driver>`
172   (:pr:`1468`).
173diff --git a/docs/whatsnew/3.7.rst b/docs/whatsnew/3.7.rst
174index 27790254..2e822d68 100644
175--- a/docs/whatsnew/3.7.rst
176+++ b/docs/whatsnew/3.7.rst
177@@ -19,7 +19,7 @@ New features
178   include it. Alternatively, you can :ref:`build h5py from source <source_install>`
179   against an HDF5 build with the direct driver enabled.
180 * The :class:`.File` constructor contains two new parameters ``alignment_threshold``,
181-  and ``alignment_interval`` controling the data alignment within the HDF5
182+  and ``alignment_interval`` controlling the data alignment within the HDF5
183   file (:pr:`2040`).
184 * :meth:`~.Group.create_dataset` and :meth:`~.Group.require_dataset` now accept
185   parameters ``efile_prefix`` and ``virtual_prefix`` to set a filesystem path
186@@ -40,7 +40,7 @@ Bug fixes
187   attributes with ``track_order=True``.
188 * Fix for building with mpi4py on Python 3.10 (:pr:`2101`).
189 * Fixed fancy indexing with a boolean array for a single dimension (:pr:`2079`).
190-* Avoid returning unitialised memory when reading from a chunked dataset with
191+* Avoid returning uninitialised memory when reading from a chunked dataset with
192   missing chunks and no fill value (:pr:`2076`).
193 * Enable setting of fillvalue for datasets with variable length string dtype
194   (:pr:`2044`).
195diff --git a/h5py/_errors.pxd b/h5py/_errors.pxd
196index df9c1bbe..3cba6307 100644
197--- a/h5py/_errors.pxd
198+++ b/h5py/_errors.pxd
199@@ -23,7 +23,7 @@ cdef extern from "hdf5.h":
200             H5E_ARGS,                   # invalid arguments to routine
201             H5E_RESOURCE,               # resource unavailable
202             H5E_INTERNAL,               # Internal error (too specific to document)
203-            H5E_FILE,                   # file Accessability
204+            H5E_FILE,                   # file Accessibility
205             H5E_IO,                     # Low-level I/O
206             H5E_FUNC,                   # function Entry/Exit
207             H5E_ATOM,                   # object Atom
208@@ -121,7 +121,7 @@ cdef extern from "hdf5.h":
209             # No error
210             H5E_NONE_MINOR     # No error
211
212-            # File accessability errors
213+            # File accessibility errors
214             H5E_FILEEXISTS     # File already exists
215             H5E_FILEOPEN       # File already open
216             H5E_CANTCREATE     # Unable to create file
217@@ -207,7 +207,7 @@ cdef extern from "hdf5.h":
218             H5E_ARGS,                   # invalid arguments to routine
219             H5E_RESOURCE,               # resource unavailable
220             H5E_INTERNAL,               # Internal error (too specific to document)
221-            H5E_FILE,                   # file Accessability
222+            H5E_FILE,                   # file Accessibility
223             H5E_IO,                     # Low-level I/O
224             H5E_FUNC,                   # function Entry/Exit
225             H5E_ID,                     # object ID
226@@ -305,7 +305,7 @@ cdef extern from "hdf5.h":
227             # No error
228             H5E_NONE_MINOR     # No error
229
230-            # File accessability errors
231+            # File accessibility errors
232             H5E_FILEEXISTS     # File already exists
233             H5E_FILEOPEN       # File already open
234             H5E_CANTCREATE     # Unable to create file
235@@ -425,4 +425,4 @@ ctypedef struct err_cookie:
236 cdef err_cookie set_error_handler(err_cookie handler)
237
238 # Set the default error handler set by silence_errors/unsilence_errors
239-cdef void set_default_error_handler() nogil
240+cdef void set_default_error_handler() noexcept nogil
241diff --git a/h5py/_errors.pyx b/h5py/_errors.pyx
242index c3bd184e..2a7524b2 100644
243--- a/h5py/_errors.pyx
244+++ b/h5py/_errors.pyx
245@@ -94,7 +94,7 @@ cdef struct err_data_t:
246     H5E_error_t err
247     int n
248
249-cdef herr_t walk_cb(unsigned int n, const H5E_error_t *desc, void *e) nogil noexcept:
250+cdef herr_t walk_cb(unsigned int n, const H5E_error_t *desc, void *e) noexcept nogil:
251
252     cdef err_data_t *ee = <err_data_t*>e
253
254@@ -168,7 +168,7 @@ cdef err_cookie _error_handler  # Store error handler used by h5py
255 _error_handler.func = NULL
256 _error_handler.data = NULL
257
258-cdef void set_default_error_handler() nogil:
259+cdef void set_default_error_handler() noexcept nogil:
260     """Set h5py's current default error handler"""
261     H5Eset_auto(<hid_t>H5E_DEFAULT, _error_handler.func, _error_handler.data)
262
263diff --git a/h5py/_hl/base.py b/h5py/_hl/base.py
264index cad37053..9d261c90 100644
265--- a/h5py/_hl/base.py
266+++ b/h5py/_hl/base.py
267@@ -20,7 +20,7 @@ import posixpath
268 import numpy as np
269
270 # The high-level interface is serialized; every public API function & method
271-# is wrapped in a lock.  We re-use the low-level lock because (1) it's fast,
272+# is wrapped in a lock.  We reuse the low-level lock because (1) it's fast,
273 # and (2) it eliminates the possibility of deadlocks due to out-of-order
274 # lock acquisition.
275 from .._objects import phil, with_phil
276@@ -524,7 +524,7 @@ def product(nums):
277 # Daniel Greenfeld, BSD license), where it is attributed to bottle (Copyright
278 # (c) 2009-2022, Marcel Hellkamp, MIT license).
279
280-class cached_property(object):
281+class cached_property:
282     def __init__(self, func):
283         self.__doc__ = getattr(func, "__doc__")
284         self.func = func
285diff --git a/h5py/_hl/dataset.py b/h5py/_hl/dataset.py
286index b69aba48..77b202d2 100644
287--- a/h5py/_hl/dataset.py
288+++ b/h5py/_hl/dataset.py
289@@ -334,10 +334,10 @@ class ChunkIterator:
290         self._layout = dset.chunks
291         if source_sel is None:
292             # select over entire dataset
293-            slices = []
294-            for dim in range(rank):
295-                slices.append(slice(0, self._shape[dim]))
296-            self._sel = tuple(slices)
297+            self._sel = tuple(
298+                slice(0, self._shape[dim])
299+                for dim in range(rank)
300+            )
301         else:
302             if isinstance(source_sel, slice):
303                 self._sel = (source_sel,)
304diff --git a/h5py/_hl/dims.py b/h5py/_hl/dims.py
305index d3c9206b..0cf4c9f3 100644
306--- a/h5py/_hl/dims.py
307+++ b/h5py/_hl/dims.py
308@@ -53,8 +53,7 @@ class DimensionProxy(base.CommonStateObject):
309
310     @with_phil
311     def __iter__(self):
312-        for k in self.keys():
313-            yield k
314+        yield from self.keys()
315
316     @with_phil
317     def __len__(self):
318diff --git a/h5py/_hl/files.py b/h5py/_hl/files.py
319index aa4fb78d..bfcf3098 100644
320--- a/h5py/_hl/files.py
321+++ b/h5py/_hl/files.py
322@@ -480,7 +480,7 @@ class File(Group):
323
324         alignment_threshold
325             Together with ``alignment_interval``, this property ensures that
326-            any file object greater than or equal in size to the alignement
327+            any file object greater than or equal in size to the alignment
328             threshold (in bytes) will be aligned on an address which is a
329             multiple of alignment interval.
330
331diff --git a/h5py/_locks.pxi b/h5py/_locks.pxi
332index bc8b2dd9..1ec4e2fc 100644
333--- a/h5py/_locks.pxi
334+++ b/h5py/_locks.pxi
335@@ -63,7 +63,7 @@ cdef class FastRLock:
336         return self._owner == pythread.PyThread_get_thread_ident()
337
338
339-cdef inline bint lock_lock(FastRLock lock, long current_thread, bint blocking) nogil:
340+cdef inline bint lock_lock(FastRLock lock, long current_thread, bint blocking) noexcept nogil:
341     # Note that this function *must* hold the GIL when being called.
342     # We just use 'nogil' in the signature to make sure that no Python
343     # code execution slips in that might free the GIL
344@@ -83,7 +83,7 @@ cdef inline bint lock_lock(FastRLock lock, long current_thread, bint blocking) n
345         lock, current_thread,
346         pythread.WAIT_LOCK if blocking else pythread.NOWAIT_LOCK)
347
348-cdef bint _acquire_lock(FastRLock lock, long current_thread, int wait) nogil:
349+cdef bint _acquire_lock(FastRLock lock, long current_thread, int wait) noexcept nogil:
350     # Note that this function *must* hold the GIL when being called.
351     # We just use 'nogil' in the signature to make sure that no Python
352     # code execution slips in that might free the GIL
353@@ -111,7 +111,7 @@ cdef bint _acquire_lock(FastRLock lock, long current_thread, int wait) nogil:
354     lock._count = 1
355     return 1
356
357-cdef inline void unlock_lock(FastRLock lock) nogil:
358+cdef inline void unlock_lock(FastRLock lock) noexcept nogil:
359     # Note that this function *must* hold the GIL when being called.
360     # We just use 'nogil' in the signature to make sure that no Python
361     # code execution slips in that might free the GIL
362diff --git a/h5py/_proxy.pyx b/h5py/_proxy.pyx
363index 46b4fe0d..e40504f5 100644
364--- a/h5py/_proxy.pyx
365+++ b/h5py/_proxy.pyx
366@@ -241,7 +241,7 @@ ctypedef struct h5py_scatter_t:
367     void* buf
368
369 cdef herr_t h5py_scatter_cb(void* elem, hid_t type_id, unsigned ndim,
370-                const hsize_t *point, void *operator_data) nogil except -1:
371+                const hsize_t *point, void *operator_data) except -1 nogil:
372     cdef h5py_scatter_t* info = <h5py_scatter_t*>operator_data
373
374     memcpy(elem, (<char*>info[0].buf)+((info[0].i)*(info[0].elsize)),
375@@ -252,7 +252,7 @@ cdef herr_t h5py_scatter_cb(void* elem, hid_t type_id, unsigned ndim,
376     return 0
377
378 cdef herr_t h5py_gather_cb(void* elem, hid_t type_id, unsigned ndim,
379-                const hsize_t *point, void *operator_data) nogil except -1:
380+                const hsize_t *point, void *operator_data) except -1 nogil:
381     cdef h5py_scatter_t* info = <h5py_scatter_t*>operator_data
382
383     memcpy((<char*>info[0].buf)+((info[0].i)*(info[0].elsize)), elem,
384diff --git a/h5py/_selector.pyx b/h5py/_selector.pyx
385index 8b858c82..69970176 100644
386--- a/h5py/_selector.pyx
387+++ b/h5py/_selector.pyx
388@@ -341,7 +341,7 @@ cdef class Reader:
389
390             arr = PyArray_ZEROS(arr_rank, arr_shape, self.np_typenum, 0)
391             if not self.native_byteorder:
392-                arr = arr.newbyteorder()
393+                arr = arr.view(arr.dtype.newbyteorder())
394         finally:
395             efree(arr_shape)
396
397diff --git a/h5py/api_compat.h b/h5py/api_compat.h
398index 52917f4d..a359e827 100644
399--- a/h5py/api_compat.h
400+++ b/h5py/api_compat.h
401@@ -24,7 +24,6 @@ typedef void *PyMPI_MPI_Message;
402 #include <stddef.h>
403 #include "Python.h"
404 #include "numpy/arrayobject.h"
405-#include "hdf5.h"
406
407 /* The HOFFSET macro can't be used from Cython. */
408
409@@ -35,14 +34,14 @@ typedef void *PyMPI_MPI_Message;
410 #define h5py_size_n256 (sizeof(npy_complex256))
411 #endif
412
413-#define h5py_offset_n64_real (HOFFSET(npy_complex64, real))
414-#define h5py_offset_n64_imag (HOFFSET(npy_complex64, imag))
415-#define h5py_offset_n128_real (HOFFSET(npy_complex128, real))
416-#define h5py_offset_n128_imag (HOFFSET(npy_complex128, imag))
417+#define h5py_offset_n64_real (0)
418+#define h5py_offset_n64_imag (sizeof(float))
419+#define h5py_offset_n128_real (0)
420+#define h5py_offset_n128_imag (sizeof(double))
421
422 #ifdef NPY_COMPLEX256
423-#define h5py_offset_n256_real (HOFFSET(npy_complex256, real))
424-#define h5py_offset_n256_imag (HOFFSET(npy_complex256, imag))
425+#define h5py_offset_n256_real (0)
426+#define h5py_offset_n256_imag (sizeof(long double))
427 #endif
428
429 #endif
430diff --git a/h5py/api_types_hdf5.pxd b/h5py/api_types_hdf5.pxd
431index a198f105..099e0f58 100644
432--- a/h5py/api_types_hdf5.pxd
433+++ b/h5py/api_types_hdf5.pxd
434@@ -257,27 +257,27 @@ cdef extern from "hdf5.h":
435       herr_t  (*sb_encode)(H5FD_t *file, char *name, unsigned char *p)
436       herr_t  (*sb_decode)(H5FD_t *f, const char *name, const unsigned char *p)
437       size_t  fapl_size
438-      void *  (*fapl_get)(H5FD_t *file)
439-      void *  (*fapl_copy)(const void *fapl)
440-      herr_t  (*fapl_free)(void *fapl)
441+      void *  (*fapl_get)(H5FD_t *file) except *
442+      void *  (*fapl_copy)(const void *fapl) except *
443+      herr_t  (*fapl_free)(void *fapl) except -1
444       size_t  dxpl_size
445       void *  (*dxpl_copy)(const void *dxpl)
446       herr_t  (*dxpl_free)(void *dxpl)
447-      H5FD_t *(*open)(const char *name, unsigned flags, hid_t fapl, haddr_t maxaddr)
448-      herr_t  (*close)(H5FD_t *file)
449+      H5FD_t *(*open)(const char *name, unsigned flags, hid_t fapl, haddr_t maxaddr) except *
450+      herr_t  (*close)(H5FD_t *file) except -1
451       int     (*cmp)(const H5FD_t *f1, const H5FD_t *f2)
452       herr_t  (*query)(const H5FD_t *f1, unsigned long *flags)
453       herr_t  (*get_type_map)(const H5FD_t *file, H5FD_mem_t *type_map)
454       haddr_t (*alloc)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size)
455       herr_t  (*free)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size)
456-      haddr_t (*get_eoa)(const H5FD_t *file, H5FD_mem_t type)
457-      herr_t  (*set_eoa)(H5FD_t *file, H5FD_mem_t type, haddr_t addr)
458-      haddr_t (*get_eof)(const H5FD_t *file, H5FD_mem_t type)
459+      haddr_t (*get_eoa)(const H5FD_t *file, H5FD_mem_t type) noexcept
460+      herr_t  (*set_eoa)(H5FD_t *file, H5FD_mem_t type, haddr_t addr) noexcept
461+      haddr_t (*get_eof)(const H5FD_t *file, H5FD_mem_t type) except -1
462       herr_t  (*get_handle)(H5FD_t *file, hid_t fapl, void**file_handle)
463-      herr_t  (*read)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl, haddr_t addr, size_t size, void *buffer)
464-      herr_t  (*write)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl, haddr_t addr, size_t size, const void *buffer)
465-      herr_t  (*flush)(H5FD_t *file, hid_t dxpl_id, hbool_t closing)
466-      herr_t  (*truncate)(H5FD_t *file, hid_t dxpl_id, hbool_t closing)
467+      herr_t  (*read)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl, haddr_t addr, size_t size, void *buffer) except *
468+      herr_t  (*write)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl, haddr_t addr, size_t size, const void *buffer) except *
469+      herr_t  (*flush)(H5FD_t *file, hid_t dxpl_id, hbool_t closing) except -1
470+      herr_t  (*truncate)(H5FD_t *file, hid_t dxpl_id, hbool_t closing) except -1
471       herr_t  (*lock)(H5FD_t *file, hbool_t rw)
472       herr_t  (*unlock)(H5FD_t *file)
473       H5FD_mem_t fl_map[<int>H5FD_MEM_NTYPES]
474@@ -295,27 +295,27 @@ cdef extern from "hdf5.h":
475       herr_t  (*sb_encode)(H5FD_t *file, char *name, unsigned char *p)
476       herr_t  (*sb_decode)(H5FD_t *f, const char *name, const unsigned char *p)
477       size_t  fapl_size
478-      void *  (*fapl_get)(H5FD_t *file)
479-      void *  (*fapl_copy)(const void *fapl)
480-      herr_t  (*fapl_free)(void *fapl)
481+      void *  (*fapl_get)(H5FD_t *file) except *
482+      void *  (*fapl_copy)(const void *fapl) except *
483+      herr_t  (*fapl_free)(void *fapl) except -1
484       size_t  dxpl_size
485       void *  (*dxpl_copy)(const void *dxpl)
486       herr_t  (*dxpl_free)(void *dxpl)
487-      H5FD_t *(*open)(const char *name, unsigned flags, hid_t fapl, haddr_t maxaddr)
488-      herr_t  (*close)(H5FD_t *file)
489+      H5FD_t *(*open)(const char *name, unsigned flags, hid_t fapl, haddr_t maxaddr) except *
490+      herr_t  (*close)(H5FD_t *file) except -1
491       int     (*cmp)(const H5FD_t *f1, const H5FD_t *f2)
492       herr_t  (*query)(const H5FD_t *f1, unsigned long *flags)
493       herr_t  (*get_type_map)(const H5FD_t *file, H5FD_mem_t *type_map)
494       haddr_t (*alloc)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, hsize_t size)
495       herr_t  (*free)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl_id, haddr_t addr, hsize_t size)
496-      haddr_t (*get_eoa)(const H5FD_t *file, H5FD_mem_t type)
497-      herr_t  (*set_eoa)(H5FD_t *file, H5FD_mem_t type, haddr_t addr)
498-      haddr_t (*get_eof)(const H5FD_t *file, H5FD_mem_t type)
499+      haddr_t (*get_eoa)(const H5FD_t *file, H5FD_mem_t type) noexcept
500+      herr_t  (*set_eoa)(H5FD_t *file, H5FD_mem_t type, haddr_t addr) noexcept
501+      haddr_t (*get_eof)(const H5FD_t *file, H5FD_mem_t type) except -1
502       herr_t  (*get_handle)(H5FD_t *file, hid_t fapl, void**file_handle)
503-      herr_t  (*read)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl, haddr_t addr, size_t size, void *buffer)
504-      herr_t  (*write)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl, haddr_t addr, size_t size, const void *buffer)
505-      herr_t  (*flush)(H5FD_t *file, hid_t dxpl_id, hbool_t closing)
506-      herr_t  (*truncate)(H5FD_t *file, hid_t dxpl_id, hbool_t closing)
507+      herr_t  (*read)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl, haddr_t addr, size_t size, void *buffer) except *
508+      herr_t  (*write)(H5FD_t *file, H5FD_mem_t type, hid_t dxpl, haddr_t addr, size_t size, const void *buffer) except *
509+      herr_t  (*flush)(H5FD_t *file, hid_t dxpl_id, hbool_t closing) except -1
510+      herr_t  (*truncate)(H5FD_t *file, hid_t dxpl_id, hbool_t closing) except -1
511       herr_t  (*lock)(H5FD_t *file, hbool_t rw)
512       herr_t  (*unlock)(H5FD_t *file)
513       H5FD_mem_t fl_map[<int>H5FD_MEM_NTYPES]
514diff --git a/h5py/h5fd.pyx b/h5py/h5fd.pyx
515index e9746057..d39cf68f 100644
516--- a/h5py/h5fd.pyx
517+++ b/h5py/h5fd.pyx
518@@ -144,10 +144,10 @@ cdef herr_t H5FD_fileobj_close(H5FD_fileobj_t *f) except -1 with gil:
519     stdlib_free(f)
520     return 0
521
522-cdef haddr_t H5FD_fileobj_get_eoa(const H5FD_fileobj_t *f, H5FD_mem_t type):
523+cdef haddr_t H5FD_fileobj_get_eoa(const H5FD_fileobj_t *f, H5FD_mem_t type) noexcept nogil:
524     return f.eoa
525
526-cdef herr_t H5FD_fileobj_set_eoa(H5FD_fileobj_t *f, H5FD_mem_t type, haddr_t addr):
527+cdef herr_t H5FD_fileobj_set_eoa(H5FD_fileobj_t *f, H5FD_mem_t type, haddr_t addr) noexcept nogil:
528     f.eoa = addr
529     return 0
530
531@@ -191,22 +191,38 @@ cdef herr_t H5FD_fileobj_flush(H5FD_fileobj_t *f, hid_t dxpl, hbool_t closing) e
532 cdef H5FD_class_t info
533 memset(&info, 0, sizeof(info))
534
535+# Cython doesn't support "except X" in casting definition currently
536+ctypedef herr_t (*file_free_func_ptr)(void *) except -1
537+
538+ctypedef herr_t (*file_close_func_ptr)(H5FD_t *) except -1
539+ctypedef haddr_t (*file_get_eoa_func_ptr)(const H5FD_t *, H5FD_mem_t) noexcept
540+ctypedef herr_t (*file_set_eof_func_ptr)(H5FD_t *, H5FD_mem_t, haddr_t) noexcept
541+ctypedef haddr_t (*file_get_eof_func_ptr)(const H5FD_t *, H5FD_mem_t) except -1
542+ctypedef herr_t (*file_read_func_ptr)(H5FD_t *, H5FD_mem_t, hid_t, haddr_t, size_t, void*) except -1
543+ctypedef herr_t (*file_write_func_ptr)(H5FD_t *, H5FD_mem_t, hid_t, haddr_t, size_t, const void*) except -1
544+ctypedef herr_t (*file_truncate_func_ptr)(H5FD_t *, hid_t, hbool_t) except -1
545+ctypedef herr_t (*file_flush_func_ptr)(H5FD_t *, hid_t, hbool_t) except -1
546+
547+
548 info.name = 'fileobj'
549 info.maxaddr = libc.stdint.SIZE_MAX - 1
550 info.fc_degree = H5F_CLOSE_WEAK
551 info.fapl_size = sizeof(PyObject *)
552 info.fapl_get = <void *(*)(H5FD_t *)>H5FD_fileobj_fapl_get
553 info.fapl_copy = <void *(*)(const void *)>H5FD_fileobj_fapl_copy
554-info.fapl_free = <herr_t (*)(void *)>H5FD_fileobj_fapl_free
555+
556+info.fapl_free = <file_free_func_ptr>H5FD_fileobj_fapl_free
557+
558 info.open = <H5FD_t *(*)(const char *name, unsigned flags, hid_t fapl, haddr_t maxaddr)>H5FD_fileobj_open
559-info.close = <herr_t (*)(H5FD_t *)>H5FD_fileobj_close
560-info.get_eoa = <haddr_t (*)(const H5FD_t *, H5FD_mem_t)>H5FD_fileobj_get_eoa
561-info.set_eoa = <herr_t (*)(H5FD_t *, H5FD_mem_t, haddr_t)>H5FD_fileobj_set_eoa
562-info.get_eof = <haddr_t (*)(const H5FD_t *, H5FD_mem_t)>H5FD_fileobj_get_eof
563-info.read = <herr_t (*)(H5FD_t *, H5FD_mem_t, hid_t, haddr_t, size_t, void *)>H5FD_fileobj_read
564-info.write = <herr_t (*)(H5FD_t *, H5FD_mem_t, hid_t, haddr_t, size_t, const void *)>H5FD_fileobj_write
565-info.truncate = <herr_t (*)(H5FD_t *, hid_t, hbool_t)>H5FD_fileobj_truncate
566-info.flush = <herr_t (*)(H5FD_t *, hid_t, hbool_t)>H5FD_fileobj_flush
567+
568+info.close = <file_close_func_ptr>H5FD_fileobj_close
569+info.get_eoa = <file_get_eoa_func_ptr>H5FD_fileobj_get_eoa
570+info.set_eoa = <file_set_eof_func_ptr>H5FD_fileobj_set_eoa
571+info.get_eof = <file_get_eof_func_ptr>H5FD_fileobj_get_eof
572+info.read = <file_read_func_ptr>H5FD_fileobj_read
573+info.write = <file_write_func_ptr>H5FD_fileobj_write
574+info.truncate = <file_truncate_func_ptr>H5FD_fileobj_truncate
575+info.flush = <file_flush_func_ptr>H5FD_fileobj_flush
576 # H5FD_FLMAP_DICHOTOMY
577 info.fl_map = [H5FD_MEM_SUPER,  # default
578                H5FD_MEM_SUPER,  # super
579diff --git a/h5py/h5p.pyx b/h5py/h5p.pyx
580index 779ea1b5..dc8bf65a 100644
581--- a/h5py/h5p.pyx
582+++ b/h5py/h5p.pyx
583@@ -1177,7 +1177,7 @@ cdef class PropFAID(PropInstanceID):
584                 size_t block_size   IN: File system block size
585                 size_t cbuf_size    IN: Copy buffer size
586
587-            Properites with value of 0 indicate that the HDF5 library should
588+            Properties with value of 0 indicate that the HDF5 library should
589             choose the value.
590             """
591             H5Pset_fapl_direct(self.id, alignment, block_size, cbuf_size)
592@@ -1761,7 +1761,7 @@ cdef class PropOCID(PropCreateID):
593
594         max_compact -- maximum number of attributes to be stored in compact storage(default:8)
595         must be greater than or equal to min_dense
596-        min_dense  -- minmum number of attributes to be stored in dense storage(default:6)
597+        min_dense  -- minimum number of attributes to be stored in dense storage(default:6)
598
599         """
600         H5Pset_attr_phase_change(self.id, max_compact, min_dense)
601diff --git a/h5py/h5t.pyx b/h5py/h5t.pyx
602index e7aae14f..b9d7e74d 100644
603--- a/h5py/h5t.pyx
604+++ b/h5py/h5t.pyx
605@@ -1938,7 +1938,7 @@ def check_dtype(**kwds):
606
607     vlen = dtype
608         If the dtype represents an HDF5 vlen, returns the Python base class.
609-        Currently only builting string vlens (str) are supported.  Returns
610+        Currently only built-in string vlens (str) are supported.  Returns
611         None if the dtype does not represent an HDF5 vlen.
612
613     enum = dtype
614diff --git a/h5py/tests/test_attrs_data.py b/h5py/tests/test_attrs_data.py
615index 56481ca0..5083a1aa 100644
616--- a/h5py/tests/test_attrs_data.py
617+++ b/h5py/tests/test_attrs_data.py
618@@ -262,7 +262,7 @@ class TestEmpty(BaseAttrs):
619         self.assertTrue(is_empty_dataspace(h5a.open(self.f.id, b'y')))
620
621     def test_modify(self):
622-        with self.assertRaises(IOError):
623+        with self.assertRaises(OSError):
624             self.f.attrs.modify('x', 1)
625
626     def test_values(self):
627diff --git a/h5py/tests/test_big_endian_file.py b/h5py/tests/test_big_endian_file.py
628index 4d81de01..170b5bcc 100644
629--- a/h5py/tests/test_big_endian_file.py
630+++ b/h5py/tests/test_big_endian_file.py
631@@ -24,14 +24,14 @@ def test_vlen_big_endian():
632         assert dset[4] == 1.2
633         assert dset.dtype == "<f8"
634
635-        # Same float values with big endianess
636+        # Same float values with big endianness
637         assert f["DSBEfloat"][0] == 3.14
638         assert f["DSBEfloat"].dtype == ">f8"
639
640         assert f["DSLEint"][0] == 1
641         assert f["DSLEint"].dtype == "<u8"
642
643-        # Same int values with big endianess
644+        # Same int values with big endianness
645         assert f["DSBEint"][0] == 1
646         assert f["DSBEint"].dtype == ">i8"
647
648diff --git a/h5py/tests/test_dataset.py b/h5py/tests/test_dataset.py
649index e104dd53..0ffa5c80 100644
650--- a/h5py/tests/test_dataset.py
651+++ b/h5py/tests/test_dataset.py
652@@ -1939,9 +1939,9 @@ class TestCommutative(BaseDataset):
653         dset = self.f.create_dataset("test", shape, dtype=float,
654                                      data=np.random.rand(*shape))
655
656-        # grab a value from the elements, ie dset[0]
657+        # grab a value from the elements, ie dset[0, 0]
658         # check that mask arrays are commutative wrt ==, !=
659-        val = np.float64(dset[0])
660+        val = np.float64(dset[0, 0])
661
662         assert np.all((val == dset) == (dset == val))
663         assert np.all((val != dset) == (dset != val))
664diff --git a/h5py/tests/test_file.py b/h5py/tests/test_file.py
665index b47d408e..1aa38731 100644
666--- a/h5py/tests/test_file.py
667+++ b/h5py/tests/test_file.py
668@@ -326,7 +326,7 @@ class TestDrivers(TestCase):
669         # could be an integer multiple of 512
670         #
671         # To allow HDF5 to do the heavy lifting for different platform,
672-        # We didn't provide any argumnets to the first call
673+        # We didn't provide any arguments to the first call
674         # and obtained HDF5's default values there.
675
676         # Testing creation with a few different property lists
677@@ -639,9 +639,9 @@ class TestUnicode(TestCase):
678         Modes 'r' and 'r+' do not create files even when given unicode names
679         """
680         fname = self.mktemp(prefix=chr(0x201a))
681-        with self.assertRaises(IOError):
682+        with self.assertRaises(OSError):
683             File(fname, 'r')
684-        with self.assertRaises(IOError):
685+        with self.assertRaises(OSError):
686             File(fname, 'r+')
687
688
689diff --git a/h5py/tests/test_file_alignment.py b/h5py/tests/test_file_alignment.py
690index c280bb76..da13ee04 100644
691--- a/h5py/tests/test_file_alignment.py
692+++ b/h5py/tests/test_file_alignment.py
693@@ -50,7 +50,7 @@ class TestFileAlignment(TestCase):
694         alignment_interval = 4096
695
696         for shape in [
697-            (1033,),  # A prime number above the thresold
698+            (1033,),  # A prime number above the threshold
699             (1000,),  # Exactly equal to the threshold
700             (1001,),  # one above the threshold
701         ]:
702@@ -75,7 +75,7 @@ class TestFileAlignment(TestCase):
703         alignment_interval = 1024
704
705         for shape in [
706-            (881,),  # A prime number below the thresold
707+            (881,),  # A prime number below the threshold
708             (999,),  # Exactly one below the threshold
709         ]:
710             fname = self.mktemp()
711diff --git a/h5py/tests/test_group.py b/h5py/tests/test_group.py
712index 328c352a..4af1fb1f 100644
713--- a/h5py/tests/test_group.py
714+++ b/h5py/tests/test_group.py
715@@ -771,7 +771,7 @@ class TestExternalLinks(TestCase):
716         with self.assertRaises(KeyError):
717             self.f['ext']
718
719-    # I would prefer IOError but there's no way to fix this as the exception
720+    # I would prefer OSError but there's no way to fix this as the exception
721     # class is determined by HDF5.
722     def test_exc_missingfile(self):
723         """ KeyError raised when attempting to open missing file """
724@@ -844,7 +844,7 @@ class TestExtLinkBugs(TestCase):
725                 try:
726                     if x:
727                         x.close()
728-                except IOError:
729+                except OSError:
730                     pass
731             return w
732         orig_name = self.mktemp()
733diff --git a/h5py/tests/test_selections.py b/h5py/tests/test_selections.py
734index 0b1722d7..01f6dcb7 100644
735--- a/h5py/tests/test_selections.py
736+++ b/h5py/tests/test_selections.py
737@@ -65,7 +65,7 @@ class TestTypeGeneration(BaseSelection):
738         self.assertEqual(out, np.dtype('i'))
739         self.assertEqual(format, np.dtype( [('a','i')] ))
740
741-        # Field does not apear in named typed
742+        # Field does not appear in named typed
743         with self.assertRaises(ValueError):
744             out, format = sel2.read_dtypes(dt, ('j', 'k'))
745
746diff --git a/pylintrc b/pylintrc
747index 045df2f7..2401d3b0 100644
748--- a/pylintrc
749+++ b/pylintrc
750@@ -44,7 +44,7 @@ confidence=
751 # can either give multiple identifiers separated by comma (,) or put this
752 # option multiple times (only on the command line, not in the configuration
753 # file where it should appear only once).You can also use "--disable=all" to
754-# disable everything first and then reenable specific checks. For example, if
755+# disable everything first and then re-enable specific checks. For example, if
756 # you want to run only the similarities checker, you can use "--disable=all
757 # --enable=similarities". If you want to run only the classes checker, but have
758 # no Warning level messages displayed, use"--disable=all --enable=classes
759diff --git a/pyproject.toml b/pyproject.toml
760index ee573d2f..717200ef 100644
761--- a/pyproject.toml
762+++ b/pyproject.toml
763@@ -1,6 +1,6 @@
764 [build-system]
765 requires = [
766-    "Cython >=0.29.31,<1",
767+    "Cython >=0.29.31,<4",
768     "oldest-supported-numpy",
769     "pkgconfig",
770     "setuptools >=61",
771diff --git a/setup_configure.py b/setup_configure.py
772index 0fba53ba..c3b86a64 100644
773--- a/setup_configure.py
774+++ b/setup_configure.py
775@@ -165,7 +165,7 @@ class BuildConfig:
776         try:
777             if pkgconfig.exists(pc_name):
778                 pc = pkgconfig.parse(pc_name)
779-        except EnvironmentError:
780+        except OSError:
781             if os.name != 'nt':
782                 print(
783                     "Building h5py requires pkg-config unless the HDF5 path "
784diff --git a/tox.ini b/tox.ini
785index 0efb88a6..86a176dd 100644
786--- a/tox.ini
787+++ b/tox.ini
788@@ -65,7 +65,7 @@ skip_install=True
789 package_env = DUMMY NON-EXISTENT ENV NAME
790 changedir=docs
791 deps=
792-    sphinx
793+    -r docs/requirements-rtd.txt
794 commands=
795     sphinx-build -W -b html -d {envtmpdir}/doctrees .  {envtmpdir}/html
796
797