nipy / nibabel

Python package to access a cacophony of neuro-imaging file formats

Home Page:http://nipy.org/nibabel/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

1 test fails: test_pkg_info

yurivict opened this issue · comments

========================================================================================= FAILURES ==========================================================================================
_______________________________________________________________________________________ test_pkg_info _______________________________________________________________________________________

    def test_pkg_info():
        """Smoke test nibabel.get_info()
    
        Hits:
            - nibabel.get_info
            - nibabel.pkg_info.get_pkg_info
            - nibabel.pkg_info.pkg_commit_hash
        """
>       info = nib.get_info()

nibabel/tests/test_pkg_info.py:18: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
nibabel/__init__.py:81: in get_info
    return _get_pkg_info(os.path.dirname(__file__))
nibabel/pkg_info.py:129: in get_pkg_info
    src, hsh = pkg_commit_hash(pkg_path)
nibabel/pkg_info.py:106: in pkg_commit_hash
    proc = run(
/usr/local/lib/python3.9/subprocess.py:505: in run
    with Popen(*popenargs, **kwargs) as process:
/usr/local/lib/python3.9/subprocess.py:951: in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <Popen: returncode: 255 args: ('git', 'rev-parse', '--short', 'HEAD')>, args = ['git', 'rev-parse', '--short', 'HEAD'], executable = b'git', preexec_fn = None, close_fds = True
pass_fds = (), cwd = '/usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel', env = None, startupinfo = None, creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1
c2pread = 158, c2pwrite = 159, errread = 160, errwrite = 161, restore_signals = True, gid = None, gids = None, uid = None, umask = -1, start_new_session = False

    def _execute_child(self, args, executable, preexec_fn, close_fds,
                       pass_fds, cwd, env,
                       startupinfo, creationflags, shell,
                       p2cread, p2cwrite,
                       c2pread, c2pwrite,
                       errread, errwrite,
                       restore_signals,
                       gid, gids, uid, umask,
                       start_new_session):
        """Execute program (POSIX version)"""
    
        if isinstance(args, (str, bytes)):
            args = [args]
        elif isinstance(args, os.PathLike):
            if shell:
                raise TypeError('path-like args is not allowed when '
                                'shell is true')
            args = [args]
        else:
            args = list(args)
    
        if shell:
            # On Android the default shell is at '/system/bin/sh'.
            unix_shell = ('/system/bin/sh' if
                      hasattr(sys, 'getandroidapilevel') else '/bin/sh')
            args = [unix_shell, "-c"] + args
            if executable:
                args[0] = executable
    
        if executable is None:
            executable = args[0]
    
        sys.audit("subprocess.Popen", executable, args, cwd, env)
    
        if (_USE_POSIX_SPAWN
                and os.path.dirname(executable)
                and preexec_fn is None
                and not close_fds
                and not pass_fds
                and cwd is None
                and (p2cread == -1 or p2cread > 2)
                and (c2pwrite == -1 or c2pwrite > 2)
                and (errwrite == -1 or errwrite > 2)
                and not start_new_session
                and gid is None
                and gids is None
                and uid is None
                and umask < 0):
            self._posix_spawn(args, executable, env, restore_signals,
                              p2cread, p2cwrite,
                              c2pread, c2pwrite,
                              errread, errwrite)
            return
    
        orig_executable = executable
    
        # For transferring possible exec failure from child to parent.
        # Data format: "exception name:hex errno:description"
        # Pickle is not used; it is complex and involves memory allocation.
        errpipe_read, errpipe_write = os.pipe()
        # errpipe_write must not be in the standard io 0, 1, or 2 fd range.
        low_fds_to_close = []
        while errpipe_write < 3:
            low_fds_to_close.append(errpipe_write)
            errpipe_write = os.dup(errpipe_write)
        for low_fd in low_fds_to_close:
            os.close(low_fd)
        try:
            try:
                # We must avoid complex work that could involve
                # malloc or free in the child process to avoid
                # potential deadlocks, thus we do all this here.
                # and pass it to fork_exec()
    
                if env is not None:
                    env_list = []
                    for k, v in env.items():
                        k = os.fsencode(k)
                        if b'=' in k:
                            raise ValueError("illegal environment variable name")
                        env_list.append(k + b'=' + os.fsencode(v))
                else:
                    env_list = None  # Use execv instead of execve.
                executable = os.fsencode(executable)
                if os.path.dirname(executable):
                    executable_list = (executable,)
                else:
                    # This matches the behavior of os._execvpe().
                    executable_list = tuple(
                        os.path.join(os.fsencode(dir), executable)
                        for dir in os.get_exec_path(env))
                fds_to_keep = set(pass_fds)
                fds_to_keep.add(errpipe_write)
                self.pid = _posixsubprocess.fork_exec(
                        args, executable_list,
                        close_fds, tuple(sorted(map(int, fds_to_keep))),
                        cwd, env_list,
                        p2cread, p2cwrite, c2pread, c2pwrite,
                        errread, errwrite,
                        errpipe_read, errpipe_write,
                        restore_signals, start_new_session,
                        gid, gids, uid, umask,
                        preexec_fn)
                self._child_created = True
            finally:
                # be sure the FD is closed no matter what
                os.close(errpipe_write)
    
            self._close_pipe_fds(p2cread, p2cwrite,
                                 c2pread, c2pwrite,
                                 errread, errwrite)
    
            # Wait for exec to fail or succeed; possibly raising an
            # exception (limited in size)
            errpipe_data = bytearray()
            while True:
                part = os.read(errpipe_read, 50000)
                errpipe_data += part
                if not part or len(errpipe_data) > 50000:
                    break
        finally:
            # be sure the FD is closed no matter what
            os.close(errpipe_read)
    
        if errpipe_data:
            try:
                pid, sts = os.waitpid(self.pid, 0)
                if pid == self.pid:
                    self._handle_exitstatus(sts)
                else:
                    self.returncode = sys.maxsize
            except ChildProcessError:
                pass
    
            try:
                exception_name, hex_errno, err_msg = (
                        errpipe_data.split(b':', 2))
                # The encoding here should match the encoding
                # written in by the subprocess implementations
                # like _posixsubprocess
                err_msg = err_msg.decode()
            except ValueError:
                exception_name = b'SubprocessError'
                hex_errno = b'0'
                err_msg = 'Bad exception data from child: {!r}'.format(
                              bytes(errpipe_data))
            child_exception_type = getattr(
                    builtins, exception_name.decode('ascii'),
                    SubprocessError)
            if issubclass(child_exception_type, OSError) and hex_errno:
                errno_num = int(hex_errno, 16)
                child_exec_never_called = (err_msg == "noexec")
                if child_exec_never_called:
                    err_msg = ""
                    # The error must be from chdir(cwd).
                    err_filename = cwd
                else:
                    err_filename = orig_executable
                if errno_num != 0:
                    err_msg = os.strerror(errno_num)
>               raise child_exception_type(errno_num, err_msg, err_filename)
E               FileNotFoundError: [Errno 2] No such file or directory: 'git'

/usr/local/lib/python3.9/subprocess.py:1837: FileNotFoundError
===================================================================================== warnings summary ======================================================================================
nibabel/casting.py:25
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/casting.py:25: RuntimeWarning: invalid value encountered in cast
    TRUNC_UINT64 = np.float64(_test_val).astype(np.uint64) != _test_val

nisext/__init__.py:10
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nisext/__init__.py:10: UserWarning: The nisext package is deprecated as of NiBabel 5.0 and will be fully
  removed in NiBabel 6.0
    warnings.warn(

nibabel/cifti2/tests/test_cifti2.py: 3 warnings
nibabel/tests/test_arraywriters.py: 40 warnings
nibabel/tests/test_round_trip.py: 72 warnings
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/volumeutils.py:783: RuntimeWarning: invalid value encountered in cast
    dslice = dslice.astype(out_dtype)

nibabel/externals/tests/test_netcdf.py::test_itemset_no_segfault_on_readonly
nibabel/tests/test_proxy_api.py::TestMinc1API::test_array_interface_with_dtype
nibabel/tests/test_proxy_api.py::TestMinc1API::test_asarray
nibabel/tests/test_proxy_api.py::TestMinc1API::test_fileobj_isolated
nibabel/tests/test_proxy_api.py::TestMinc1API::test_header_isolated
nibabel/tests/test_proxy_api.py::TestMinc1API::test_is_proxy
nibabel/tests/test_proxy_api.py::TestMinc1API::test_ndim
nibabel/tests/test_proxy_api.py::TestMinc1API::test_proxy_slicing
nibabel/tests/test_proxy_api.py::TestMinc1API::test_shape
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/externals/netcdf.py:301: RuntimeWarning: Cannot close a netcdf_file opened with mmap=True, when netcdf_variables or arrays referring to its data still exist. All data arrays obtained from such files refer directly to data on disk, and must be copied before the file can be cleanly closed. (See netcdf_file docstring for more information on mmap.)
    warnings.warn((

nibabel/tests/test_analyze.py: 1 warning
nibabel/tests/test_nifti1.py: 18 warnings
nibabel/tests/test_spm2analyze.py: 1 warning
nibabel/tests/test_spm99analyze.py: 1 warning
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/analyze.py:621: DeprecationWarning: NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays.  The conversion of 32768 to int16 will fail in the future.
  For the old behavior, usually:
      np.array(value).astype(dtype)
  will give the desired result (the cast overflows).
    dims[1 : ndims + 1] = shape

nibabel/tests/test_arraywriters.py: 26 warnings
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_arraywriters.py:147: RuntimeWarning: invalid value encountered in cast
    exp_back = exp_back.astype(out_dtype)

nibabel/tests/test_arraywriters.py: 15 warnings
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_arraywriters.py:147: RuntimeWarning: overflow encountered in cast
    exp_back = exp_back.astype(out_dtype)

nibabel/tests/test_arraywriters.py::test_nan2zero
nibabel/tests/test_arraywriters.py::test_nan2zero
nibabel/tests/test_arraywriters.py::test_nan2zero
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_arraywriters.py:517: RuntimeWarning: invalid value encountered in cast
    astype_res = np.array(np.nan).astype(np.int32)

nibabel/tests/test_arraywriters.py::test_to_float
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/volumeutils.py:783: RuntimeWarning: overflow encountered in cast
    dslice = dslice.astype(out_dtype)

nibabel/tests/test_arraywriters.py::test_to_float
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_arraywriters.py:577: RuntimeWarning: overflow encountered in cast
    assert_array_equal(arr.astype(out_type), arr_back)

nibabel/tests/test_arraywriters.py::test_nan2zero_scaling
nibabel/tests/test_arraywriters.py::test_nan2zero_scaling
nibabel/tests/test_arraywriters.py::test_nan2zero_scaling
nibabel/tests/test_arraywriters.py::test_nan2zero_scaling
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/arraywriters.py:678: RuntimeWarning: invalid value encountered in cast
    if nan_fill_i == np.array(nan_fill_i, dtype=out_dtype):

nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_floating.py::test_floor_exact_16
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/casting.py:524: RuntimeWarning: overflow encountered in cast
    fval = flt_type(val)

nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_casting.py:43: RuntimeWarning: overflow encountered in cast
    fimax = ft(imax)

nibabel/tests/test_casting.py: 10 warnings
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_casting.py:49: RuntimeWarning: invalid value encountered in cast
    imax_roundtrip = fimax.astype(it)

nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_casting.py:69: RuntimeWarning: overflow encountered in cast
    fimin = ft(imin)

nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_casting.py:75: RuntimeWarning: invalid value encountered in cast
    imin_roundtrip = fimin.astype(it)

nibabel/tests/test_casting.py: 11 warnings
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_casting.py:36: RuntimeWarning: invalid value encountered in cast
    bit_bigger = ovs[np.isfinite(ovs)].astype(it)

nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_casting.py:63: RuntimeWarning: invalid value encountered in cast
    bit_smaller = ovs[np.isfinite(ovs)].astype(it)

nibabel/tests/test_casting.py::test_shared_range
nibabel/tests/test_casting.py::test_shared_range
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_casting.py:37: RuntimeWarning: invalid value encountered in cast
    casted_mx = ft(mx).astype(it)

nibabel/tests/test_casting.py::test_casting
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_casting.py:118: RuntimeWarning: invalid value encountered in cast
    exp_arr[arr.index(np.nan)] = ft(np.nan).astype(it)

nibabel/tests/test_casting.py::test_casting
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_casting.py:96: RuntimeWarning: overflow encountered in cast
    farr_orig = np.array(arr, dtype=ft)

nibabel/tests/test_casting.py::test_casting
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_casting.py:102: RuntimeWarning: invalid value encountered in cast
    exp_arr = np.array([mn, mx, mn, mx, 0, 0, 11], dtype=it)

nibabel/tests/test_floating.py::test_floor_exact
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/casting.py:524: RuntimeWarning: overflow encountered in conversion from python long
    fval = flt_type(val)

nibabel/tests/test_nifti1.py::TestNifti1PairHeader::test_freesurfer_large_vector_hack
nibabel/tests/test_nifti1.py::TestNifti1SingleHeader::test_freesurfer_large_vector_hack
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/nifti1.py:895: DeprecationWarning: NumPy will stop allowing conversion of out-of-bound Python integers to integer arrays.  The conversion of 2147483648 to int32 will fail in the future.
  For the old behavior, usually:
      np.array(value).astype(dtype)
  will give the desired result (the cast overflows).
    hdr['glmin'] = shape[0]

nibabel/tests/test_proxy_api.py::TestEcatAPI::test_array_interface_with_dtype
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/ecat.py:712: RuntimeWarning: overflow encountered in cast
    data = data.astype(dtype, copy=False)

nibabel/tests/test_proxy_api.py::TestEcatAPI::test_array_interface_with_dtype
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_proxy_api.py:159: RuntimeWarning: overflow encountered in cast
    assert_allclose(direct, orig.astype(dtype), rtol=rtol, atol=1e-08)

nibabel/tests/test_proxy_api.py::TestEcatAPI::test_array_interface_with_dtype
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/ecat.py:712: RuntimeWarning: invalid value encountered in cast
    data = data.astype(dtype, copy=False)

nibabel/tests/test_proxy_api.py::TestEcatAPI::test_array_interface_with_dtype
nibabel/tests/test_proxy_api.py::TestPARRECAPI::test_array_interface_with_dtype
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_proxy_api.py:159: RuntimeWarning: invalid value encountered in cast
    assert_allclose(direct, orig.astype(dtype), rtol=rtol, atol=1e-08)

nibabel/tests/test_proxy_api.py::TestPARRECAPI::test_array_interface_with_dtype
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/parrec.py:711: RuntimeWarning: invalid value encountered in cast
    arr = arr.astype(dtype, copy=False)

nibabel/tests/test_round_trip.py: 24 warnings
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_round_trip.py:29: RuntimeWarning: overflow encountered in cast
    arr = in_arr.astype(in_type)

nibabel/tests/test_round_trip.py::test_round_trip
nibabel/tests/test_round_trip.py::test_round_trip
nibabel/tests/test_round_trip.py::test_round_trip
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/arraywriters.py:511: RuntimeWarning: overflow encountered in cast
    self._inter = np.squeeze(self.scaler_dtype.type(val))

nibabel/tests/test_round_trip.py::test_round_trip
nibabel/tests/test_round_trip.py::test_round_trip
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/arraywriters.py:322: RuntimeWarning: overflow encountered in cast
    self._slope = np.squeeze(self.scaler_dtype.type(val))

nibabel/tests/test_round_trip.py: 117 warnings
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_round_trip.py:29: RuntimeWarning: invalid value encountered in cast
    arr = in_arr.astype(in_type)

nibabel/tests/test_scaling.py::test_a2f_nan2zero
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/tests/test_scaling.py:133: RuntimeWarning: invalid value encountered in cast
    assert_array_equal(data_back, [np.array(np.nan).astype(np.int32), 99])

nibabel/tests/test_volumeutils.py::test__ftype4scaled_finite_warningfilters
nibabel/tests/test_volumeutils.py::test__ftype4scaled_finite_warningfilters
nibabel/tests/test_volumeutils.py::test__ftype4scaled_finite_warningfilters
nibabel/tests/test_volumeutils.py::test__ftype4scaled_finite_warningfilters
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nibabel/volumeutils.py:1174: RuntimeWarning: overflow encountered in multiply
    tst_trans = tst_trans * slope

nisext/tests/test_sexts.py: 18 warnings
  /usr/ports/science/py-nibabel/work-py39/nibabel-5.2.0/nisext/sexts.py:199: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
    if checker(have_version) < checker(version):

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================================================================== short test summary info ==================================================================================
SKIPPED [31] ../../../../../local/lib/python3.9/site-packages/_pytest/unittest.py:371: Need nibabel-data directory for this test
SKIPPED [5] ../../../../../local/lib/python3.9/site-packages/_pytest/unittest.py:371: cannot find freesurfer fsaverage directory
SKIPPED [15] ../../../../../local/lib/python3.9/site-packages/_pytest/unittest.py:371: Could not import pydicom
SKIPPED [6] ../../../../../local/lib/python3.9/site-packages/_pytest/unittest.py:371: No pydicom for these tests
SKIPPED [1] nibabel/nicom/tests/test_dicomwrappers.py:624: Could not import pydicom
SKIPPED [1] nibabel/nicom/tests/test_dicomwrappers.py:650: Could not import pydicom
SKIPPED [1] nibabel/nicom/tests/test_dicomwrappers.py:667: Could not import pydicom
SKIPPED [1] nibabel/nicom/tests/test_dicomwrappers.py:631: Could not import pydicom
SKIPPED [1] nibabel/nicom/tests/test_dicomwrappers.py:659: Could not import pydicom
SKIPPED [1] nibabel/nicom/tests/test_dicomwrappers.py:455: Could not import pydicom
SKIPPED [1] nibabel/nicom/tests/test_dicomwrappers.py:645: Could not import pydicom
SKIPPED [1] nibabel/tests/test_arrayproxy.py:592: could not import 'indexed_gzip': No module named 'indexed_gzip'
SKIPPED [8] ../../../../../local/lib/python3.9/site-packages/_pytest/unittest.py:371: Need pydicom for dft tests, skipping
SKIPPED [1] ../../../../../local/lib/python3.9/site-packages/_pytest/unittest.py:371: It would take too long to test filehandles
SKIPPED [5] ../../../../../local/lib/python3.9/site-packages/_pytest/unittest.py:371: Skipped
SKIPPED [1] nibabel/tests/test_loadsave.py:89: Skipped
SKIPPED [1] nibabel/tests/test_loadsave.py:99: Skipped
SKIPPED [1] ../../../../../local/lib/python3.9/site-packages/_pytest/unittest.py:371: Skip slow tests.
SKIPPED [1] ../../../../../local/lib/python3.9/site-packages/_pytest/unittest.py:371: ECAT header does not support dtype get
================================================ 1 failed, 5383 passed, 83 skipped, 37 xfailed, 3 xpassed, 422 warnings in 669.57s (0:11:09) ================================================

Version: 5.2.0
Python-3.9
FreeBSD 13.2

Are you able to add patches? I'm happy to include a fix, but I'd rather not re-release just for this fix.

Please try this patch:

diff --git a/nibabel/pkg_info.py b/nibabel/pkg_info.py
index 7e816939..7232806a 100644
--- a/nibabel/pkg_info.py
+++ b/nibabel/pkg_info.py
@@ -1,6 +1,7 @@
 from __future__ import annotations
 
 import sys
+from contextlib import suppress
 from subprocess import run
 
 from packaging.version import Version
@@ -102,14 +103,16 @@ def pkg_commit_hash(pkg_path: str | None = None) -> tuple[str, str]:
     ver = Version(__version__)
     if ver.local is not None and ver.local.startswith('g'):
         return 'installation', ver.local[1:8]
-    # maybe we are in a repository
-    proc = run(
-        ('git', 'rev-parse', '--short', 'HEAD'),
-        capture_output=True,
-        cwd=pkg_path,
-    )
-    if proc.stdout:
-        return 'repository', proc.stdout.decode().strip()
+    # maybe we are in a repository, but consider that we may not have git
+    with suppress(FileNotFoundError):
+        proc = run(
+            ('git', 'rev-parse', '--short', 'HEAD'),
+            capture_output=True,
+            cwd=pkg_path,
+        )
+        if proc.stdout:
+            return 'repository', proc.stdout.decode().strip()
+
     return '(none found)', '<not found>'
 
 

This patch fixes the failing test, thank you.
I'll add it to the port.

Thank you for checking. I will make sure this is in the next release, which will either be 5.2.1 or 6.0.0.