Bug 2225951 - scipy: FTBFS in Fedora rawhide/f39
Summary: scipy: FTBFS in Fedora rawhide/f39
Keywords:
Status: CLOSED RAWHIDE
Alias: None
Product: Fedora
Classification: Fedora
Component: scipy
Version: rawhide
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Nikola Forró
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks: F39FTBFS F40FTBFS PYTHON3.13
TreeView+ depends on / blocked
 
Reported: 2023-07-25 18:17 UTC by Fedora Release Engineering
Modified: 2023-11-29 18:02 UTC (History)
11 users (show)

Fixed In Version: scipy-1.11.3-2.fc40
Clone Of:
Environment:
Last Closed: 2023-11-29 18:02:32 UTC
Type: ---
Embargoed:


Attachments (Terms of Use)
build.log (32.00 KB, text/plain)
2023-07-25 18:17 UTC, Fedora Release Engineering
no flags Details
root.log (32.00 KB, text/plain)
2023-07-25 18:17 UTC, Fedora Release Engineering
no flags Details
state.log (1009 bytes, text/plain)
2023-07-25 18:17 UTC, Fedora Release Engineering
no flags Details

Description Fedora Release Engineering 2023-07-25 18:17:40 UTC
scipy failed to build from source in Fedora rawhide/f39

https://koji.fedoraproject.org/koji/taskinfo?taskID=103614099


For details on the mass rebuild see:

https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
Please fix scipy at your earliest convenience and set the bug's status to
ASSIGNED when you start fixing it. If the bug remains in NEW state for 8 weeks,
scipy will be orphaned. Before branching of Fedora 40,
scipy will be retired, if it still fails to build.

For more details on the FTBFS policy, please visit:
https://docs.fedoraproject.org/en-US/fesco/Fails_to_build_from_source_Fails_to_install/

Comment 1 Fedora Release Engineering 2023-07-25 18:17:48 UTC
Created attachment 1978285 [details]
build.log

file build.log too big, will only attach last 32768 bytes

Comment 2 Fedora Release Engineering 2023-07-25 18:17:53 UTC
Created attachment 1978286 [details]
root.log

file root.log too big, will only attach last 32768 bytes

Comment 3 Fedora Release Engineering 2023-07-25 18:17:56 UTC
Created attachment 1978287 [details]
state.log

Comment 4 Ben Beasley 2023-07-25 18:32:45 UTC
This failed on i686 only. There was a single test failure, which it looks like is actually just a negligible rounding/precision discrepancy.

=================================== FAILURES ===================================
____________________________ TestQuad.test_complex _____________________________
[gw2] linux -- Python 3.12.0 /usr/bin/python3
actual = (271.4823113796459+4.827353117680502e-15j)
desired = (271.4822820782857+4.827353117680502e-15j), err_msg = ''
verbose = True
    def assert_equal(actual, desired, err_msg='', verbose=True):
        """
        Raises an AssertionError if two objects are not equal.
    
        Given two objects (scalars, lists, tuples, dictionaries or numpy arrays),
        check that all elements of these objects are equal. An exception is raised
        at the first conflicting values.
    
        When one of `actual` and `desired` is a scalar and the other is array_like,
        the function checks that each element of the array_like object is equal to
        the scalar.
    
        This function handles NaN comparisons as if NaN was a "normal" number.
        That is, AssertionError is not raised if both objects have NaNs in the same
        positions.  This is in contrast to the IEEE standard on NaNs, which says
        that NaN compared to anything must return False.
    
        Parameters
        ----------
        actual : array_like
            The object to check.
        desired : array_like
            The expected object.
        err_msg : str, optional
            The error message to be printed in case of failure.
        verbose : bool, optional
            If True, the conflicting values are appended to the error message.
    
        Raises
        ------
        AssertionError
            If actual and desired are not equal.
    
        Examples
        --------
        >>> np.testing.assert_equal([4,5], [4,6])
        Traceback (most recent call last):
            ...
        AssertionError:
        Items are not equal:
        item=1
         ACTUAL: 5
         DESIRED: 6
    
        The following comparison does not raise an exception.  There are NaNs
        in the inputs, but they are in the same positions.
    
        >>> np.testing.assert_equal(np.array([1.0, 2.0, np.nan]), [1, 2, np.nan])
    
        """
        __tracebackhide__ = True  # Hide traceback for py.test
        if isinstance(desired, dict):
            if not isinstance(actual, dict):
                raise AssertionError(repr(type(actual)))
            assert_equal(len(actual), len(desired), err_msg, verbose)
            for k, i in desired.items():
                if k not in actual:
                    raise AssertionError(repr(k))
                assert_equal(actual[k], desired[k], f'key={k!r}\n{err_msg}',
                             verbose)
            return
        if isinstance(desired, (list, tuple)) and isinstance(actual, (list, tuple)):
            assert_equal(len(actual), len(desired), err_msg, verbose)
            for k in range(len(desired)):
                assert_equal(actual[k], desired[k], f'item={k!r}\n{err_msg}',
                             verbose)
            return
        from numpy.core import ndarray, isscalar, signbit
        from numpy.lib import iscomplexobj, real, imag
        if isinstance(actual, ndarray) or isinstance(desired, ndarray):
            return assert_array_equal(actual, desired, err_msg, verbose)
        msg = build_err_msg([actual, desired], err_msg, verbose=verbose)
    
        # Handle complex numbers: separate into real/imag to handle
        # nan/inf/negative zero correctly
        # XXX: catch ValueError for subclasses of ndarray where iscomplex fail
        try:
            usecomplex = iscomplexobj(actual) or iscomplexobj(desired)
        except (ValueError, TypeError):
            usecomplex = False
    
        if usecomplex:
            if iscomplexobj(actual):
                actualr = real(actual)
                actuali = imag(actual)
            else:
                actualr = actual
                actuali = 0
            if iscomplexobj(desired):
                desiredr = real(desired)
                desiredi = imag(desired)
            else:
                desiredr = desired
                desiredi = 0
            try:
>               assert_equal(actualr, desiredr)
/usr/lib/python3.12/site-packages/numpy/testing/_private/utils.py:374: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
actual = 271.4823113796459, desired = 271.4822820782857, err_msg = ''
verbose = True
    def assert_equal(actual, desired, err_msg='', verbose=True):
        """
        Raises an AssertionError if two objects are not equal.
    
        Given two objects (scalars, lists, tuples, dictionaries or numpy arrays),
        check that all elements of these objects are equal. An exception is raised
        at the first conflicting values.
    
        When one of `actual` and `desired` is a scalar and the other is array_like,
        the function checks that each element of the array_like object is equal to
        the scalar.
    
        This function handles NaN comparisons as if NaN was a "normal" number.
        That is, AssertionError is not raised if both objects have NaNs in the same
        positions.  This is in contrast to the IEEE standard on NaNs, which says
        that NaN compared to anything must return False.
    
        Parameters
        ----------
        actual : array_like
            The object to check.
        desired : array_like
            The expected object.
        err_msg : str, optional
            The error message to be printed in case of failure.
        verbose : bool, optional
            If True, the conflicting values are appended to the error message.
    
        Raises
        ------
        AssertionError
            If actual and desired are not equal.
    
        Examples
        --------
        >>> np.testing.assert_equal([4,5], [4,6])
        Traceback (most recent call last):
            ...
        AssertionError:
        Items are not equal:
        item=1
         ACTUAL: 5
         DESIRED: 6
    
        The following comparison does not raise an exception.  There are NaNs
        in the inputs, but they are in the same positions.
    
        >>> np.testing.assert_equal(np.array([1.0, 2.0, np.nan]), [1, 2, np.nan])
    
        """
        __tracebackhide__ = True  # Hide traceback for py.test
        if isinstance(desired, dict):
            if not isinstance(actual, dict):
                raise AssertionError(repr(type(actual)))
            assert_equal(len(actual), len(desired), err_msg, verbose)
            for k, i in desired.items():
                if k not in actual:
                    raise AssertionError(repr(k))
                assert_equal(actual[k], desired[k], f'key={k!r}\n{err_msg}',
                             verbose)
            return
        if isinstance(desired, (list, tuple)) and isinstance(actual, (list, tuple)):
            assert_equal(len(actual), len(desired), err_msg, verbose)
            for k in range(len(desired)):
                assert_equal(actual[k], desired[k], f'item={k!r}\n{err_msg}',
                             verbose)
            return
        from numpy.core import ndarray, isscalar, signbit
        from numpy.lib import iscomplexobj, real, imag
        if isinstance(actual, ndarray) or isinstance(desired, ndarray):
            return assert_array_equal(actual, desired, err_msg, verbose)
        msg = build_err_msg([actual, desired], err_msg, verbose=verbose)
    
        # Handle complex numbers: separate into real/imag to handle
        # nan/inf/negative zero correctly
        # XXX: catch ValueError for subclasses of ndarray where iscomplex fail
        try:
            usecomplex = iscomplexobj(actual) or iscomplexobj(desired)
        except (ValueError, TypeError):
            usecomplex = False
    
        if usecomplex:
            if iscomplexobj(actual):
                actualr = real(actual)
                actuali = imag(actual)
            else:
                actualr = actual
                actuali = 0
            if iscomplexobj(desired):
                desiredr = real(desired)
                desiredi = imag(desired)
            else:
                desiredr = desired
                desiredi = 0
            try:
                assert_equal(actualr, desiredr)
                assert_equal(actuali, desiredi)
            except AssertionError:
                raise AssertionError(msg)
    
        # isscalar test to check cases such as [np.nan] != np.nan
        if isscalar(desired) != isscalar(actual):
            raise AssertionError(msg)
    
        try:
            isdesnat = isnat(desired)
            isactnat = isnat(actual)
            dtypes_match = (np.asarray(desired).dtype.type ==
                            np.asarray(actual).dtype.type)
            if isdesnat and isactnat:
                # If both are NaT (and have the same dtype -- datetime or
                # timedelta) they are considered equal.
                if dtypes_match:
                    return
                else:
                    raise AssertionError(msg)
    
        except (TypeError, ValueError, NotImplementedError):
            pass
    
        # Inf/nan/negative zero handling
        try:
            isdesnan = gisnan(desired)
            isactnan = gisnan(actual)
            if isdesnan and isactnan:
                return  # both nan, so equal
    
            # handle signed zero specially for floats
            array_actual = np.asarray(actual)
            array_desired = np.asarray(desired)
            if (array_actual.dtype.char in 'Mm' or
                    array_desired.dtype.char in 'Mm'):
                # version 1.18
                # until this version, gisnan failed for datetime64 and timedelta64.
                # Now it succeeds but comparison to scalar with a different type
                # emits a DeprecationWarning.
                # Avoid that by skipping the next check
                raise NotImplementedError('cannot compare to a scalar '
                                          'with a different type')
    
            if desired == 0 and actual == 0:
                if not signbit(desired) == signbit(actual):
                    raise AssertionError(msg)
    
        except (TypeError, ValueError, NotImplementedError):
            pass
    
        try:
            # Explicitly use __eq__ for comparison, gh-2552
            if not (desired == actual):
>               raise AssertionError(msg)
E               AssertionError: 
E               Items are not equal:
E                ACTUAL: 271.4823113796459
E                DESIRED: 271.4822820782857
/usr/lib/python3.12/site-packages/numpy/testing/_private/utils.py:429: AssertionError
During handling of the above exception, another exception occurred:
self = <scipy.integrate.tests.test_quadpack.TestQuad object at 0xf0ede7f8>
    def test_complex(self):
        def tfunc(x):
            return np.exp(1j*x)
    
        assert np.allclose(
                    quad(tfunc, 0, np.pi/2, complex_func=True)[0],
                    1+1j)
    
        # We consider a divergent case in order to force quadpack
        # to return an error message.  The output is compared
        # against what is returned by explicit integration
        # of the parts.
        kwargs = {'a': 0, 'b': np.inf, 'full_output': True,
                  'weight': 'cos', 'wvar': 1}
        res_c = quad(tfunc, complex_func=True, **kwargs)
        res_r = quad(lambda x: np.real(np.exp(1j*x)),
                     complex_func=False,
                     **kwargs)
        res_i = quad(lambda x: np.imag(np.exp(1j*x)),
                     complex_func=False,
                     **kwargs)
    
        np.testing.assert_equal(res_c[0], res_r[0] + 1j*res_i[0])
>       np.testing.assert_equal(res_c[1], res_r[1] + 1j*res_i[1])
E       AssertionError: 
E       Items are not equal:
E        ACTUAL: (271.4823113796459+4.827353117680502e-15j)
E        DESIRED: (271.4822820782857+4.827353117680502e-15j)
scipy/integrate/tests/test_quadpack.py:531: AssertionError

Comment 5 Fedora Release Engineering 2023-08-16 07:58:25 UTC
This bug appears to have been reported against 'rawhide' during the Fedora Linux 39 development cycle.
Changing version to 39.

Comment 6 Richard W.M. Jones 2023-11-15 11:40:16 UTC
It currently FTBFS very early on, on x86-64, because of removal of distutils:

+ for PY in 3.12
+ env 'CFLAGS=-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wno-complain-wrong-lang -Werror=format-security -Werror=implicit-function-declaration -Werror=implicit-int -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64   -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -lm' 'FFLAGS=-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Wno-complain-wrong-lang -Werror=format-security -Werror=implicit-function-declaration -Werror=implicit-int -Wp,-U_FORTIFY_SOURCE,-D_FORTIFY_SOURCE=3 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -m64   -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -fPIC -fallow-argument-mismatch' 'LDFLAGS=-Wl,-z,relro -Wl,--as-needed  -Wl,-z,now -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1  -Wl,--build-id=sha1 -specs=/usr/lib/rpm/redhat/redhat-package-notes ' /usr/bin/python3.12 setup.py config_fc --fcompiler=gnu95 --noarch build
Traceback (most recent call last):
  File "/home/rjones/d/fedora/scipy/rawhide/scipy-1.11.1/setup.py", line 532, in <module>
    setup_package()
  File "/home/rjones/d/fedora/scipy/rawhide/scipy-1.11.1/setup.py", line 506, in setup_package
    from numpy.distutils.core import setup
ModuleNotFoundError: No module named 'numpy.distutils'
error: Bad exit status from /var/tmp/rpm-tmp.nZRhAn (%build)

Comment 7 Richard W.M. Jones 2023-11-15 11:46:45 UTC
Upstream build system is slightly deranged.  They have removed 'setup.py' which
we are using:

https://github.com/scipy/scipy/commit/e8d73fa4741be67dd4329f56f400e45fd37f3fc1
https://github.com/scipy/scipy/commit/03dc21068e9a53d915a8acd36da1333e0a61bdd0

There's a meson-based build system which is hopeful, but I don't really have any
clue about how we'd go about using it.

Comment 8 Nikola Forró 2023-11-15 11:57:17 UTC
There is an open PR that takes care of the build system changes:
https://src.fedoraproject.org/rpms/scipy/pull-request/31


Note You need to log in before you can comment on or make changes to this bug.