From 1926a6be0b3dd0447fe2d7a585018061fa0f9f7a Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Thu, 14 May 2020 17:13:57 -0400 Subject: [PATCH 01/31] BLD: Move the configuration defines in Python.h earlier. Leaving it later can lead to some headers getting confused, because they're included with one set of feature flags, but the headers they depend on were included with a different set of feature flags. --- numpy/core/include/numpy/npy_common.h | 1 + numpy/random/src/distributions/random_hypergeometric.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/numpy/core/include/numpy/npy_common.h b/numpy/core/include/numpy/npy_common.h index d5a586c56a39..93b303d9c2fa 100644 --- a/numpy/core/include/numpy/npy_common.h +++ b/numpy/core/include/numpy/npy_common.h @@ -28,6 +28,7 @@ #ifndef NPY_USE_NEW_CASTINGIMPL #define NPY_USE_NEW_CASTINGIMPL 0 #endif + /* * using static inline modifiers when defining npy_math functions * allows the compiler to make optimizations when possible diff --git a/numpy/random/src/distributions/random_hypergeometric.c b/numpy/random/src/distributions/random_hypergeometric.c index 0da49bd62ad0..dc05c7729d82 100644 --- a/numpy/random/src/distributions/random_hypergeometric.c +++ b/numpy/random/src/distributions/random_hypergeometric.c @@ -1,6 +1,7 @@ +#include "Python.h" +#include #include "numpy/random/distributions.h" #include "logfactorial.h" -#include /* * Generate a sample from the hypergeometric distribution. From 7c320f34cd176fb00b534d26be3aa89fb4c6db76 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Thu, 14 May 2020 17:16:36 -0400 Subject: [PATCH 02/31] DEV: Try to rebase f2py-created modules for fewer fork() failures in rebase. Cygwin needs each DLL to have a unique address for fork() emulation to work. I'm hoping that calling rebase on a complete list of modules compiled in this session, plus those installed globally, will allow the test suite to get an accurate result for more tests. --- numpy/distutils/fcompiler/__init__.py | 27 +++++++++++++++++++-------- numpy/distutils/fcompiler/gnu.py | 6 +++--- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/numpy/distutils/fcompiler/__init__.py b/numpy/distutils/fcompiler/__init__.py index 4730a5a0999a..9a0296edfca7 100644 --- a/numpy/distutils/fcompiler/__init__.py +++ b/numpy/distutils/fcompiler/__init__.py @@ -40,6 +40,9 @@ class CompilerNotFound(Exception): pass +if sys.platform == 'cygwin': + COMPILED_MODULES = [] + def flaglist(s): if is_string(s): return split_quoted(s) @@ -154,16 +157,16 @@ class FCompiler(CCompiler): compiler_aliases = () version_pattern = None - possible_executables = [] + possible_executables = ['gfortran'] executables = { - 'version_cmd': ["f77", "-v"], - 'compiler_f77': ["f77"], - 'compiler_f90': ["f90"], - 'compiler_fix': ["f90", "-fixed"], - 'linker_so': ["f90", "-shared"], - 'linker_exe': ["f90"], + 'version_cmd': ["gfortran", "-v"], + 'compiler_f77': ["gfortran"], + 'compiler_f90': ["gfortran"], + 'compiler_fix': ["gfortran", "-fixed"], + 'linker_so': ["gfortran", "-shared"], + 'linker_exe': ["gfortran"], 'archiver': ["ar", "-cr"], - 'ranlib': None, + 'ranlib': ["ranlib"], } # If compiler does not support compiling Fortran 90 then it can @@ -679,6 +682,14 @@ def link(self, target_desc, objects, except DistutilsExecError as e: msg = str(e) raise LinkError(msg) + if sys.platform == 'cygwin': + # Rebase newly-compiled module so it has a higher + # chance of surviving fork() + COMPILED_MODULES.append(output_filename) + rebase_args = ['/usr/bin/rebase', '--database', + '--oblivious'] + rebase_args.extend(COMPILED_MODULES) + self.spawn(rebase_args) else: log.debug("skipping %s (up-to-date)", output_filename) diff --git a/numpy/distutils/fcompiler/gnu.py b/numpy/distutils/fcompiler/gnu.py index 68d1501eee6a..6f668ee64a07 100644 --- a/numpy/distutils/fcompiler/gnu.py +++ b/numpy/distutils/fcompiler/gnu.py @@ -78,7 +78,7 @@ def version_match(self, version_string): return None return v[1] - possible_executables = ['g77', 'f77'] + possible_executables = ['g77', 'f77', "gfortran"] executables = { 'version_cmd' : [None, "-dumpversion"], 'compiler_f77' : [None, "-g", "-Wall", "-fno-second-underscore"], @@ -246,7 +246,7 @@ def get_flags_arch(self): return [] def runtime_library_dir_option(self, dir): - if sys.platform == 'win32': + if sys.platform == 'win32' or sys.platform == 'cygwin': # Linux/Solaris/Unix support RPATH, Windows does not raise NotImplementedError @@ -286,7 +286,7 @@ def version_match(self, version_string): self.executables[key].append('-mno-cygwin') return v - possible_executables = ['gfortran', 'f95'] + possible_executables = ['gfortran', 'f95', '/usr/bin/gfortran'] executables = { 'version_cmd' : ["", "-dumpversion"], 'compiler_f77' : [None, "-Wall", "-g", "-ffixed-form", From 9cbd7de5958b1b285be138c2ec45e3bf28dda9ae Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Thu, 14 May 2020 17:20:25 -0400 Subject: [PATCH 03/31] TST: Mark the tests that seem to fail due to different floating-point on cygwin. Most likely I should be testing for newlib (the C runtime, roughly takes the place of glibc, I think), not cygwin (the emulation layer on Windows), but I have no idea how to do that from within python. If someone working on embedded systems runs into this issue, this hopefully gives them some idea where to start. --- numpy/core/tests/test_multiarray.py | 6 ++++++ numpy/core/tests/test_numeric.py | 6 ++++++ numpy/core/tests/test_scalarmath.py | 4 ++++ numpy/core/tests/test_umath.py | 12 ++++++++++++ 4 files changed, 28 insertions(+) diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 048b1688f2a7..0edcd6a30951 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -8576,6 +8576,9 @@ class MyAlwaysEqualNew(MyAlwaysEqual): assert_equal(array != my_always_equal, 'ne') +@pytest.mark.xfail(sys.platform == 'cygwin', + reason='abs(inf+nanj) short-circuits to inf', + strict=True) def test_npymath_complex(): # Smoketest npymath functions from numpy.core._multiarray_tests import ( @@ -8595,6 +8598,9 @@ def test_npymath_complex(): assert_allclose(got, expected) +@pytest.mark.xfail(sys.platform == 'cygwin', + reason='expects cosh(-inf) == -inf', + strict=True) def test_npymath_real(): # Smoketest npymath functions from numpy.core._multiarray_tests import ( diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index 866a96e31c1c..83b40069181e 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -614,6 +614,9 @@ def test_errobj_noerrmask(self): class TestFloatExceptions: + @pytest.mark.xfail(sys.platform == 'cygwin', + reason='FPE support incomplete', + strict=True) def assert_raises_fpe(self, fpeerr, flop, x, y): ftype = type(x) try: @@ -636,6 +639,9 @@ def assert_op_raises_fpe(self, fpeerr, flop, sc1, sc2): self.assert_raises_fpe(fpeerr, flop, sc1, sc2[()]) self.assert_raises_fpe(fpeerr, flop, sc1[()], sc2[()]) + @pytest.mark.xfail(sys.platform == 'cygwin', + reason='FPE support incomplete', + strict=True) def test_floating_exceptions(self): # Test basic arithmetic function errors with np.errstate(all='raise'): diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py index d8529418e58b..dd5a670d7f41 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -674,9 +674,13 @@ def _test_abs_func(self, absfunc): x = tp(np.finfo(tp).min) assert_equal(absfunc(x), -x.real) + @pytest.mark.xfail(sys.platform == 'cygwin', + reason='abs(np.complex256.max) overflows') def test_builtin_abs(self): self._test_abs_func(abs) + @pytest.mark.xfail(sys.platform == 'cygwin', + reason='abs(np.complex256.max) overflows') def test_numpy_abs(self): self._test_abs_func(np.abs) diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index bc72aa862a73..1c869bdce83b 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -766,6 +766,9 @@ def test_log2_values(self): yf = np.array(y, dtype=dt) assert_almost_equal(np.log2(xf), yf) + @pytest.mark.xfail(sys.platform == 'cygwin', + reason='Fails for i==29', + strict=True) def test_log2_ints(self): # a good log2 implementation should provide this, # might fail on OS with bad libm @@ -3011,6 +3014,9 @@ def test_precisions_consistent(self): assert_almost_equal(fcf, fcd, decimal=6, err_msg='fch-fcd %s' % f) assert_almost_equal(fcl, fcd, decimal=15, err_msg='fch-fcl %s' % f) + @pytest.mark.xfail(sys.platform == 'cygwin', + reason='0.7071j != 0.7071j, apparently', + strict=True) def test_branch_cuts(self): # check branch cuts and continuity on them _check_branch_cut(np.log, -0.5, 1j, 1, -1, True) @@ -3036,6 +3042,9 @@ def test_branch_cuts(self): _check_branch_cut(np.arccosh, [0-2j, 2j, 2], [1, 1, 1j], 1, 1) _check_branch_cut(np.arctanh, [0-2j, 2j, 0], [1, 1, 1j], 1, 1) + @pytest.mark.xfail(sys.platform == 'cygwin', + reason='square root faces small loss of precision', + strict=True) def test_branch_cuts_complex64(self): # check branch cuts and continuity on them _check_branch_cut(np.log, -0.5, 1j, 1, -1, True, np.complex64) @@ -3080,6 +3089,9 @@ def test_against_cmath(self): b = cfunc(p) assert_(abs(a - b) < atol, "%s %s: %s; cmath: %s" % (fname, p, a, b)) + @pytest.mark.xfail(sys.platform == 'cygwin', + reason='arcsinh(1e-20) returns 0', + strict=True) @pytest.mark.parametrize('dtype', [np.complex64, np.complex_, np.longcomplex]) def test_loss_of_precision(self, dtype): """Check loss of precision in complex arc* functions""" From 60d19649e9ed3a96e8d8b633835f068fb8fddfc7 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Thu, 14 May 2020 17:23:35 -0400 Subject: [PATCH 04/31] TST: Try to mark the tests still suseptible to fork() failures on cygwin. See two commits back for an explanation of why fork() fails on cygwin. Alternately, see the much better explanation at: https://cygwin.com/cygwin-ug-net/highlights.html#ov-hi-process with hints on error messages and workarounds at: https://cygwin.com/faq.html#faq.using.fixing-fork-failures --- numpy/f2py/tests/test_compile_function.py | 6 ++++++ numpy/f2py/tests/util.py | 6 ++++++ numpy/linalg/tests/test_linalg.py | 3 +++ numpy/random/tests/test_extending.py | 3 +++ numpy/tests/test_public_api.py | 2 ++ numpy/tests/test_scripts.py | 2 ++ 6 files changed, 22 insertions(+) diff --git a/numpy/f2py/tests/test_compile_function.py b/numpy/f2py/tests/test_compile_function.py index f76fd644807c..bf484da95407 100644 --- a/numpy/f2py/tests/test_compile_function.py +++ b/numpy/f2py/tests/test_compile_function.py @@ -26,6 +26,8 @@ def setup_module(): "extra_args", [['--noopt', '--debug'], '--noopt --debug', ''] ) @pytest.mark.leaks_references(reason="Imported module seems never deleted.") +@pytest.mark.xfail(sys.platform == 'cygwin', reason="Random fork failures", + raises=BlockingIOError) def test_f2py_init_compile(extra_args): # flush through the f2py __init__ compile() function code path as a # crude test for input handling following migration from @@ -83,6 +85,8 @@ def test_f2py_init_compile(extra_args): del sys.modules[modname] +@pytest.mark.xfail(sys.platform == 'cygwin', reason="Random fork failures", + raises=BlockingIOError) def test_f2py_init_compile_failure(): # verify an appropriate integer status value returned by # f2py.compile() when invalid Fortran is provided @@ -111,6 +115,8 @@ def test_f2py_init_compile_bad_cmd(): @pytest.mark.parametrize('fsource', ['program test_f2py\nend program test_f2py', b'program test_f2py\nend program test_f2py',]) +@pytest.mark.xfail(sys.platform == 'cygwin', reason="Random fork failures", + raises=BlockingIOError) def test_compile_from_strings(tmpdir, fsource): # Make sure we can compile str and bytes gh-12796 cwd = os.getcwd() diff --git a/numpy/f2py/tests/util.py b/numpy/f2py/tests/util.py index d5fa76fedf27..6f9c89e03056 100644 --- a/numpy/f2py/tests/util.py +++ b/numpy/f2py/tests/util.py @@ -317,6 +317,12 @@ class F2PyTest: module = None module_name = None + # Pytest seems to ignore this, but I'm not sure where else to put + # it, besides trying to make a metaclass that decorates every + # method of a subclass of F2PyTest + @pytest.mark.xfail(sys.platform == 'cygwin', + reason='Fork() randomly fails on cygwin', + raises=BlockingIOError) def setup(self): if sys.platform == 'win32': pytest.skip('Fails with MinGW64 Gfortran (Issue #9673)') diff --git a/numpy/linalg/tests/test_linalg.py b/numpy/linalg/tests/test_linalg.py index 21fab58e1d42..6fc5ab5d65f1 100644 --- a/numpy/linalg/tests/test_linalg.py +++ b/numpy/linalg/tests/test_linalg.py @@ -1837,6 +1837,9 @@ def test_xerbla_override(): @pytest.mark.slow +@pytest.mark.xfail(sys.platform == 'cygwin', + reason='Fork() fails randomly on cygwin', + raises=BlockingIOError) def test_sdot_bug_8577(): # Regression test that loading certain other libraries does not # result to wrong results in float32 linear algebra. diff --git a/numpy/random/tests/test_extending.py b/numpy/random/tests/test_extending.py index 99a819efb576..09157997ee9b 100644 --- a/numpy/random/tests/test_extending.py +++ b/numpy/random/tests/test_extending.py @@ -42,6 +42,9 @@ @pytest.mark.skipif(cython is None, reason="requires cython") @pytest.mark.slow +@pytest.mark.xfail(sys.platform == "cygwin", + reason="Random fork() failures", + raises=BlockingIOError) def test_cython(tmp_path): srcdir = os.path.join(os.path.dirname(__file__), '..') shutil.copytree(srcdir, tmp_path / 'random') diff --git a/numpy/tests/test_public_api.py b/numpy/tests/test_public_api.py index 69430eeda089..e502f09107eb 100644 --- a/numpy/tests/test_public_api.py +++ b/numpy/tests/test_public_api.py @@ -77,6 +77,8 @@ def test_numpy_namespace(): @pytest.mark.parametrize('name', ['testing', 'Tester']) +@pytest.mark.xfail(sys.platform == 'cygwin', reason="Random fork failures", + raises=BlockingIOError) def test_import_lazy_import(name): """Make sure we can actually use the modules we lazy load. diff --git a/numpy/tests/test_scripts.py b/numpy/tests/test_scripts.py index e67a829471dc..697a76b3a5ae 100644 --- a/numpy/tests/test_scripts.py +++ b/numpy/tests/test_scripts.py @@ -41,6 +41,8 @@ def test_f2py(f2py_cmd): assert_equal(stdout.strip(), np.__version__.encode('ascii')) +@pytest.mark.xfail(sys.platform == 'cygwin', reason="Random fork failures", + raises=BlockingIOError) def test_pep338(): stdout = subprocess.check_output([sys.executable, '-mnumpy.f2py', '-v']) assert_equal(stdout.strip(), np.__version__.encode('ascii')) From 6d8f36e1fef7d0daef9cf7f0b5fc5def9f8dd9ba Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Mon, 18 May 2020 16:46:37 -0400 Subject: [PATCH 05/31] DEV: Revert executable renames for F77/G77 compiler. These changes made some sense when compiling only for cygwin. They do not belong in NumPy master. --- numpy/distutils/fcompiler/__init__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/numpy/distutils/fcompiler/__init__.py b/numpy/distutils/fcompiler/__init__.py index 9a0296edfca7..fe1875f1ba77 100644 --- a/numpy/distutils/fcompiler/__init__.py +++ b/numpy/distutils/fcompiler/__init__.py @@ -157,16 +157,16 @@ class FCompiler(CCompiler): compiler_aliases = () version_pattern = None - possible_executables = ['gfortran'] + possible_executables = [] executables = { - 'version_cmd': ["gfortran", "-v"], - 'compiler_f77': ["gfortran"], - 'compiler_f90': ["gfortran"], - 'compiler_fix': ["gfortran", "-fixed"], - 'linker_so': ["gfortran", "-shared"], - 'linker_exe': ["gfortran"], + 'version_cmd': ["f77", "-v"], + 'compiler_f77': ["f77"], + 'compiler_f90': ["f90"], + 'compiler_fix': ["f90", "-fixed"], + 'linker_so': ["f90", "-shared"], + 'linker_exe': ["f90"], 'archiver': ["ar", "-cr"], - 'ranlib': ["ranlib"], + 'ranlib': None, } # If compiler does not support compiling Fortran 90 then it can From c8d1059273c4d00ff28630df6d53859b1269099f Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Mon, 18 May 2020 16:59:58 -0400 Subject: [PATCH 06/31] BLD: Add functions that fail tests on Cygwin to npy_config.h. I don't know if the list should be the same as one of the Windows lists, or if this should instead be a Newlib list. I know how to make a Cygwin list, so I did that. It didn't always work, though. --- numpy/core/src/common/npy_config.h | 49 ++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/numpy/core/src/common/npy_config.h b/numpy/core/src/common/npy_config.h index 61cc3c7f18d4..abcf2ca74608 100644 --- a/numpy/core/src/common/npy_config.h +++ b/numpy/core/src/common/npy_config.h @@ -91,6 +91,55 @@ #endif #endif /* defined(_MSC_VER) && defined(__INTEL_COMPILER) */ +/* Disable functions that give undesired floating-point outputs on + Cygwin. */ +#ifdef __CYGWIN__ + +#undef HAVE_CABS +#undef HAVE_CABSF +#undef HAVE_CABSL + +/* These work for me in C++, even for the failing test case (2 ** 29), + but the tests fail. No idea if the functions I'm getting are used + or not. */ +#undef HAVE_LOG2 +#undef HAVE_LOG2F +#undef HAVE_LOG2L + +/* Complex square root does not use sign of zero to find branch + cuts. */ +#undef HAVE_CSQRT +#undef HAVE_CSQRTF +#undef HAVE_CSQRTL + +/* C++ Real asinh works fine, complex asinh says asinh(1e-20+0j) = + 0 */ +#undef HAVE_CASINH +#undef HAVE_CASINHF +#undef HAVE_CASINHL + +/* _check_branch_cut(np.arcsin, ...) fails */ +#undef HAVE_CASIN +#undef HAVE_CASINF +#undef HAVE_CASINL + +/* Branch cuts for arccosine also fail */ +#undef HAVE_CACOS +#undef HAVE_CACOSF +#undef HAVE_CACOSL + +/* Branch cuts for arctan fail as well */ +#undef HAVE_CATAN +#undef HAVE_CATANF +#undef HAVE_CATANL + +/* check_loss_of_precision fails in arctanh */ +#undef HAVE_CATANH +#undef HAVE_CATANHF +#undef HAVE_CATANHL + +#endif + /* powl gives zero division warning on OS X, see gh-8307 */ #if defined(HAVE_POWL) && defined(NPY_OS_DARWIN) #undef HAVE_POWL From c356079ca119a0115b2645d299aeb6ec7cedbb71 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Mon, 18 May 2020 17:02:26 -0400 Subject: [PATCH 07/31] TST: Describe what I know about the FPE test failure. The generic "this doesn't work" was confusing people. Specifying what "this" is and what happed works better. --- numpy/core/tests/test_numeric.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index 83b40069181e..445690e1881e 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -639,9 +639,12 @@ def assert_op_raises_fpe(self, fpeerr, flop, sc1, sc2): self.assert_raises_fpe(fpeerr, flop, sc1, sc2[()]) self.assert_raises_fpe(fpeerr, flop, sc1[()], sc2[()]) - @pytest.mark.xfail(sys.platform == 'cygwin', - reason='FPE support incomplete', - strict=True) + @pytest.mark.xfail( + sys.platform == "cygwin", + reason="complex256(2 ** (2 ** nexp_256)) is inf+infj without OverflowError", + raises=AssertionError, + strict=True, + ) def test_floating_exceptions(self): # Test basic arithmetic function errors with np.errstate(all='raise'): From faca5fb3ba80ba26438650026601e62c236d158f Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Mon, 18 May 2020 17:03:47 -0400 Subject: [PATCH 08/31] STY: A few largely cosmetic changes. Mark tests suddenly passing, and also document how I expect them to fail. --- numpy/core/tests/test_scalarmath.py | 16 ++++++++++++---- numpy/distutils/fcompiler/gnu.py | 6 ++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py index dd5a670d7f41..db044cd6a620 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -674,13 +674,21 @@ def _test_abs_func(self, absfunc): x = tp(np.finfo(tp).min) assert_equal(absfunc(x), -x.real) - @pytest.mark.xfail(sys.platform == 'cygwin', - reason='abs(np.complex256.max) overflows') + @pytest.mark.xfail( + sys.platform == 'cygwin', + reason='abs(np.complex256.max) overflows', + raises=AssertionError, + strict=True, + ) def test_builtin_abs(self): self._test_abs_func(abs) - @pytest.mark.xfail(sys.platform == 'cygwin', - reason='abs(np.complex256.max) overflows') + @pytest.mark.xfail( + sys.platform == 'cygwin', + reason='abs(np.complex256.max) overflows', + raises=AssertionError, + strict=True, + ) def test_numpy_abs(self): self._test_abs_func(np.abs) diff --git a/numpy/distutils/fcompiler/gnu.py b/numpy/distutils/fcompiler/gnu.py index 6f668ee64a07..b0c80b476dcd 100644 --- a/numpy/distutils/fcompiler/gnu.py +++ b/numpy/distutils/fcompiler/gnu.py @@ -246,8 +246,10 @@ def get_flags_arch(self): return [] def runtime_library_dir_option(self, dir): - if sys.platform == 'win32' or sys.platform == 'cygwin': - # Linux/Solaris/Unix support RPATH, Windows does not + if ( + sys.platform[:3] == 'aix' or sys.platform == 'win32' or sys.platform == 'cygwin' + ): + # Linux/Solaris/Unix support RPATH, Windows and AIX do not raise NotImplementedError # TODO: could use -Xlinker here, if it's supported From 02593e2834fb38aab8eb62c1310734dbbd1e9c6c Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Mon, 18 May 2020 17:06:27 -0400 Subject: [PATCH 09/31] DEV: Stop trying to rebase f2py modules. This was actually making the situation worse, I think because I forgot to include the NumPy dlls themselves. Removing this made for many fewer fork() failures when I tried it. `python3 -m pip show numpy --files | grep dll` will give a list of dlls, with at least a relative path. This can be done in python with subprocess (will require adding pip as a runtime dependency), but I'm not sure that's in scope here. --- numpy/distutils/fcompiler/__init__.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/numpy/distutils/fcompiler/__init__.py b/numpy/distutils/fcompiler/__init__.py index fe1875f1ba77..4730a5a0999a 100644 --- a/numpy/distutils/fcompiler/__init__.py +++ b/numpy/distutils/fcompiler/__init__.py @@ -40,9 +40,6 @@ class CompilerNotFound(Exception): pass -if sys.platform == 'cygwin': - COMPILED_MODULES = [] - def flaglist(s): if is_string(s): return split_quoted(s) @@ -682,14 +679,6 @@ def link(self, target_desc, objects, except DistutilsExecError as e: msg = str(e) raise LinkError(msg) - if sys.platform == 'cygwin': - # Rebase newly-compiled module so it has a higher - # chance of surviving fork() - COMPILED_MODULES.append(output_filename) - rebase_args = ['/usr/bin/rebase', '--database', - '--oblivious'] - rebase_args.extend(COMPILED_MODULES) - self.spawn(rebase_args) else: log.debug("skipping %s (up-to-date)", output_filename) From db300006e1ceda7a6bd44f1f2bca52e8ebf91b09 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Tue, 19 May 2020 13:39:03 -0400 Subject: [PATCH 10/31] Remove xfails from tests that now pass. --- numpy/core/tests/test_multiarray.py | 3 --- numpy/core/tests/test_umath.py | 6 ------ 2 files changed, 9 deletions(-) diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 0edcd6a30951..9b6b8bee2e15 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -8598,9 +8598,6 @@ def test_npymath_complex(): assert_allclose(got, expected) -@pytest.mark.xfail(sys.platform == 'cygwin', - reason='expects cosh(-inf) == -inf', - strict=True) def test_npymath_real(): # Smoketest npymath functions from numpy.core._multiarray_tests import ( diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index 1c869bdce83b..db825764f762 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -766,9 +766,6 @@ def test_log2_values(self): yf = np.array(y, dtype=dt) assert_almost_equal(np.log2(xf), yf) - @pytest.mark.xfail(sys.platform == 'cygwin', - reason='Fails for i==29', - strict=True) def test_log2_ints(self): # a good log2 implementation should provide this, # might fail on OS with bad libm @@ -3089,9 +3086,6 @@ def test_against_cmath(self): b = cfunc(p) assert_(abs(a - b) < atol, "%s %s: %s; cmath: %s" % (fname, p, a, b)) - @pytest.mark.xfail(sys.platform == 'cygwin', - reason='arcsinh(1e-20) returns 0', - strict=True) @pytest.mark.parametrize('dtype', [np.complex64, np.complex_, np.longcomplex]) def test_loss_of_precision(self, dtype): """Check loss of precision in complex arc* functions""" From 66dc53a84a5fd4fec27c9f4d6bcecfa4953b4477 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Tue, 19 May 2020 13:53:23 -0400 Subject: [PATCH 11/31] Use parametrize for the dtypes in the abs tests. --- numpy/core/tests/test_scalarmath.py | 95 ++++++++++++++++++----------- 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py index db044cd6a620..151ba4e219bb 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -653,44 +653,67 @@ def test_result(self): class TestAbs: - def _test_abs_func(self, absfunc): - for tp in floating_types + complex_floating_types: - x = tp(-1.5) - assert_equal(absfunc(x), 1.5) - x = tp(0.0) - res = absfunc(x) - # assert_equal() checks zero signedness - assert_equal(res, 0.0) - x = tp(-0.0) - res = absfunc(x) - assert_equal(res, 0.0) - - x = tp(np.finfo(tp).max) - assert_equal(absfunc(x), x.real) - - x = tp(np.finfo(tp).tiny) - assert_equal(absfunc(x), x.real) - - x = tp(np.finfo(tp).min) - assert_equal(absfunc(x), -x.real) - - @pytest.mark.xfail( - sys.platform == 'cygwin', - reason='abs(np.complex256.max) overflows', - raises=AssertionError, - strict=True, + def _test_abs_func(self, absfunc, tp): + x = tp(-1.5) + assert_equal(absfunc(x), 1.5) + x = tp(0.0) + res = absfunc(x) + # assert_equal() checks zero signedness + assert_equal(res, 0.0) + x = tp(-0.0) + res = absfunc(x) + assert_equal(res, 0.0) + + x = tp(np.finfo(tp).max) + assert_equal(absfunc(x), x.real) + + x = tp(np.finfo(tp).tiny) + assert_equal(absfunc(x), x.real) + + x = tp(np.finfo(tp).min) + assert_equal(absfunc(x), -x.real) + + @pytest.mark.parametrize( + "dtype", + [ + pytest.param( + dtype, + marks=( + pytest.mark.xfail( + sys.platform == 'cygwin', + reason='abs(np.complex256.max) overflows', + raises=AssertionError, + strict=True, + ) + if dtype == np.complex256 else () + ) + ) + for dtype in floating_types + complex_floating_types + ], ) - def test_builtin_abs(self): - self._test_abs_func(abs) - - @pytest.mark.xfail( - sys.platform == 'cygwin', - reason='abs(np.complex256.max) overflows', - raises=AssertionError, - strict=True, + def test_builtin_abs(self, dtype): + self._test_abs_func(abs, dtype) + + @pytest.mark.parametrize( + "dtype", + [ + pytest.param( + dtype, + marks=( + pytest.mark.xfail( + sys.platform == 'cygwin', + reason='abs(np.complex256.max) overflows', + raises=RuntimeWarning, + strict=True, + ) + if dtype == np.complex256 else () + ) + ) + for dtype in floating_types + complex_floating_types + ], ) - def test_numpy_abs(self): - self._test_abs_func(np.abs) + def test_numpy_abs(self, dtype): + self._test_abs_func(np.abs, dtype) class TestBitShifts: From 0d4b4deb88b20967895c0a9f4d923c62de8aa4d5 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Wed, 20 May 2020 18:15:45 -0400 Subject: [PATCH 12/31] Remove xfail mark from an assert function. These should primarily be on test functions. --- numpy/core/tests/test_numeric.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index 445690e1881e..1af22a4bb291 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -614,9 +614,6 @@ def test_errobj_noerrmask(self): class TestFloatExceptions: - @pytest.mark.xfail(sys.platform == 'cygwin', - reason='FPE support incomplete', - strict=True) def assert_raises_fpe(self, fpeerr, flop, x, y): ftype = type(x) try: From 0f1130166861c1299be7d9101196e495326d4417 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Mon, 25 May 2020 13:35:18 -0400 Subject: [PATCH 13/31] Remove references to np.complex256 Unconditional access to np.complex256 triggers an error in test collection on platforms where the dtype does not exist. Find another way to test the dtype for equality. --- numpy/core/tests/test_scalarmath.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py index 151ba4e219bb..d7d337745a6c 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -685,7 +685,7 @@ def _test_abs_func(self, absfunc, tp): raises=AssertionError, strict=True, ) - if dtype == np.complex256 else () + if dtype().dtype.str.endswith("c32") else () ) ) for dtype in floating_types + complex_floating_types From bc209f17bcc7faf6a2f7bb064714cfd58e4ce9fa Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Mon, 25 May 2020 13:59:17 -0400 Subject: [PATCH 14/31] Remove reference to np.complex256 in the other test I changed this for the one test, but forgot to do so for the other. Hopefully this actually fixes the problem. --- numpy/core/tests/test_scalarmath.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py index d7d337745a6c..b7bc29cdae2c 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -706,7 +706,7 @@ def test_builtin_abs(self, dtype): raises=RuntimeWarning, strict=True, ) - if dtype == np.complex256 else () + if dtype().dtype.str.endswith("c32") else () ) ) for dtype in floating_types + complex_floating_types From c93cb735cb5dd4426b1e4c9c93a88da5ca621682 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Fri, 29 May 2020 13:57:54 -0400 Subject: [PATCH 15/31] Don't add `gfortran` to the list of GNU77 compilers Presumably whoever wrote this code had reasons for leaving this out, and making a separate class for `gfortran` --- numpy/distutils/fcompiler/gnu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/distutils/fcompiler/gnu.py b/numpy/distutils/fcompiler/gnu.py index b0c80b476dcd..41d409375f0c 100644 --- a/numpy/distutils/fcompiler/gnu.py +++ b/numpy/distutils/fcompiler/gnu.py @@ -78,7 +78,7 @@ def version_match(self, version_string): return None return v[1] - possible_executables = ['g77', 'f77', "gfortran"] + possible_executables = ['g77', 'f77'] executables = { 'version_cmd' : [None, "-dumpversion"], 'compiler_f77' : [None, "-g", "-Wall", "-fno-second-underscore"], From 343127d634d709590895a7e6f97df66111702421 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Sat, 6 Jun 2020 11:09:32 -0400 Subject: [PATCH 16/31] Include only 'gfortran' in gnu fcompiler, not absolute version Including both 'gfortran' and '/usr/bin/gfortran' should be redundant, and I'm not sure even my platform ever needed this. Remove it. --- numpy/distutils/fcompiler/gnu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/distutils/fcompiler/gnu.py b/numpy/distutils/fcompiler/gnu.py index 41d409375f0c..7127aef912b5 100644 --- a/numpy/distutils/fcompiler/gnu.py +++ b/numpy/distutils/fcompiler/gnu.py @@ -288,7 +288,7 @@ def version_match(self, version_string): self.executables[key].append('-mno-cygwin') return v - possible_executables = ['gfortran', 'f95', '/usr/bin/gfortran'] + possible_executables = ['gfortran', 'f95'] executables = { 'version_cmd' : ["", "-dumpversion"], 'compiler_f77' : [None, "-Wall", "-g", "-ffixed-form", From f9bea44117fb2f6b1686213821bd4384911cf1dc Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Thu, 9 Jul 2020 12:36:54 -0400 Subject: [PATCH 17/31] TST: Use usual names for the dtypes in xfail mark Short-circuiting is lovely. --- numpy/core/tests/test_scalarmath.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py index b7bc29cdae2c..53f978bf6d0d 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -685,7 +685,7 @@ def _test_abs_func(self, absfunc, tp): raises=AssertionError, strict=True, ) - if dtype().dtype.str.endswith("c32") else () + if sys.platform == 'cygwin' and dtype == np.complex256 else () ) ) for dtype in floating_types + complex_floating_types @@ -706,7 +706,7 @@ def test_builtin_abs(self, dtype): raises=RuntimeWarning, strict=True, ) - if dtype().dtype.str.endswith("c32") else () + if sys.platform == 'cygwin' and dtype == np.complex256 else () ) ) for dtype in floating_types + complex_floating_types From f6555358fdfed7e2299a8489abeb55e81f0b4733 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Wed, 17 Jun 2020 19:38:42 -0400 Subject: [PATCH 18/31] BLD: Remind GCC that .seh_savexmm fails for xmm16-31. Workaround for GCC bug 65782. Fixes numpy issue 14787. --- setup.py | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/setup.py b/setup.py index 6033916c2595..edb9a5506025 100755 --- a/setup.py +++ b/setup.py @@ -199,12 +199,44 @@ def _needs_gcc_c99_flag(obj): return False return True + def _is_64bit_build(): + return (sys.maxsize >> 62) == 1 + + def _gcc_version_less_than(obj, test_version): + gcc_version_lt_provided = False + if obj.compiler.compiler_type == "unix": + cc = obj.compiler.compiler[0] + if "gcc" in cc: + out = subprocess.run( + [cc, "-dumpversion"], + stdout=subprocess.PIPE, + ) + ver = LooseVersion(out.stdout.strip()) + gcc_version_lt_provided = ver < test_version + return gcc_version_lt_provided + + def _is_old_gcc_on_cygwin(obj): + return ( + sys.platform == "cygwin" and _is_64bit_build() and + _gcc_version_less_than(obj, LooseVersion("8.4")) + ) + class new_build_clib(build_clib): def build_a_library(self, build_info, lib_name, libraries): if _needs_gcc_c99_flag(self): args = build_info.get('extra_compiler_args') or [] args.append('-std=c99') build_info['extra_compiler_args'] = args + if _is_old_gcc_on_cygwin(self): + args = build_info.get('extra_compiler_args') or [] + args.append( + '-fno-asynchronous-unwind-tables ' + '-ffixed-xmm16 -ffixed-xmm17 -ffixed-xmm18 -ffixed-xmm19 ' + '-ffixed-xmm20 -ffixed-xmm21 -ffixed-xmm22 -ffixed-xmm23 ' + '-ffixed-xmm24 -ffixed-xmm25 -ffixed-xmm26 -ffixed-xmm27 ' + '-ffixed-xmm28 -ffixed-xmm29 -ffixed-xmm30 -ffixed-xmm31' + ) + build_info['extra_compiler_args'] = args build_clib.build_a_library(self, build_info, lib_name, libraries) class new_build_ext(build_ext): @@ -212,6 +244,15 @@ def build_extension(self, ext): if _needs_gcc_c99_flag(self): if '-std=c99' not in ext.extra_compile_args: ext.extra_compile_args.append('-std=c99') + if _is_old_gcc_on_cygwin(self, ext): + if '-ffixed-xmm' not in ext.extra_compile_args: + ext.extra_compile_args.append( + '-fno-asynchronous-unwind-tables ' + '-ffixed-xmm16 -ffixed-xmm17 -ffixed-xmm18 -ffixed-xmm19 ' + '-ffixed-xmm20 -ffixed-xmm21 -ffixed-xmm22 -ffixed-xmm23 ' + '-ffixed-xmm24 -ffixed-xmm25 -ffixed-xmm26 -ffixed-xmm27 ' + '-ffixed-xmm28 -ffixed-xmm29 -ffixed-xmm30 -ffixed-xmm31' + ) build_ext.build_extension(self, ext) return new_build_clib, new_build_ext From d22b6658fda1f12a3f8deed16a8ead0dfbd44f9a Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Fri, 19 Jun 2020 09:20:28 -0400 Subject: [PATCH 19/31] BLD: Fix code checking for old GCC on cygwin. I forgot the function returned bytes, not str. I also accidentally passed an extra argument. --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index edb9a5506025..9f62dd952770 100755 --- a/setup.py +++ b/setup.py @@ -211,7 +211,7 @@ def _gcc_version_less_than(obj, test_version): [cc, "-dumpversion"], stdout=subprocess.PIPE, ) - ver = LooseVersion(out.stdout.strip()) + ver = LooseVersion(out.stdout.strip().decode("ascii")) gcc_version_lt_provided = ver < test_version return gcc_version_lt_provided @@ -244,7 +244,7 @@ def build_extension(self, ext): if _needs_gcc_c99_flag(self): if '-std=c99' not in ext.extra_compile_args: ext.extra_compile_args.append('-std=c99') - if _is_old_gcc_on_cygwin(self, ext): + if _is_old_gcc_on_cygwin(self): if '-ffixed-xmm' not in ext.extra_compile_args: ext.extra_compile_args.append( '-fno-asynchronous-unwind-tables ' From 8e2352ba0e124bf11bf7769d44817e56cda0ee6a Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Fri, 19 Jun 2020 09:21:58 -0400 Subject: [PATCH 20/31] TST: Only mark fork()-using tests xfail on 32-bit cygwin. The problem seems to have gone away on 64-bit. --- numpy/f2py/tests/test_compile_function.py | 7 ++++--- numpy/f2py/tests/util.py | 3 ++- numpy/random/tests/test_extending.py | 3 ++- numpy/testing/_private/utils.py | 3 ++- numpy/tests/test_public_api.py | 3 ++- numpy/tests/test_scripts.py | 3 ++- 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/numpy/f2py/tests/test_compile_function.py b/numpy/f2py/tests/test_compile_function.py index bf484da95407..b25349685033 100644 --- a/numpy/f2py/tests/test_compile_function.py +++ b/numpy/f2py/tests/test_compile_function.py @@ -10,6 +10,7 @@ import numpy.f2py from numpy.testing import assert_equal +from numpy.testing._private.utils import IS_32BIT_CYGWIN from . import util @@ -26,7 +27,7 @@ def setup_module(): "extra_args", [['--noopt', '--debug'], '--noopt --debug', ''] ) @pytest.mark.leaks_references(reason="Imported module seems never deleted.") -@pytest.mark.xfail(sys.platform == 'cygwin', reason="Random fork failures", +@pytest.mark.xfail(IS_32BIT_CYGWIN, reason="Random fork failures", raises=BlockingIOError) def test_f2py_init_compile(extra_args): # flush through the f2py __init__ compile() function code path as a @@ -85,7 +86,7 @@ def test_f2py_init_compile(extra_args): del sys.modules[modname] -@pytest.mark.xfail(sys.platform == 'cygwin', reason="Random fork failures", +@pytest.mark.xfail(IS_32BIT_CYGWIN, reason="Random fork failures", raises=BlockingIOError) def test_f2py_init_compile_failure(): # verify an appropriate integer status value returned by @@ -115,7 +116,7 @@ def test_f2py_init_compile_bad_cmd(): @pytest.mark.parametrize('fsource', ['program test_f2py\nend program test_f2py', b'program test_f2py\nend program test_f2py',]) -@pytest.mark.xfail(sys.platform == 'cygwin', reason="Random fork failures", +@pytest.mark.xfail(IS_32BIT_CYGWIN, reason="Random fork failures", raises=BlockingIOError) def test_compile_from_strings(tmpdir, fsource): # Make sure we can compile str and bytes gh-12796 diff --git a/numpy/f2py/tests/util.py b/numpy/f2py/tests/util.py index 6f9c89e03056..f867d6db7021 100644 --- a/numpy/f2py/tests/util.py +++ b/numpy/f2py/tests/util.py @@ -17,6 +17,7 @@ from numpy.compat import asbytes, asstr from numpy.testing import temppath +from numpy.testing._private.utils import IS_32BIT_CYGWIN from importlib import import_module # @@ -320,7 +321,7 @@ class F2PyTest: # Pytest seems to ignore this, but I'm not sure where else to put # it, besides trying to make a metaclass that decorates every # method of a subclass of F2PyTest - @pytest.mark.xfail(sys.platform == 'cygwin', + @pytest.mark.xfail(IS_32BIT_CYGWIN, reason='Fork() randomly fails on cygwin', raises=BlockingIOError) def setup(self): diff --git a/numpy/random/tests/test_extending.py b/numpy/random/tests/test_extending.py index 09157997ee9b..0080b70be382 100644 --- a/numpy/random/tests/test_extending.py +++ b/numpy/random/tests/test_extending.py @@ -5,6 +5,7 @@ import sys import warnings import numpy as np +from numpy.testing._private.utils import IS_32BIT_CYGWIN try: import cffi @@ -42,7 +43,7 @@ @pytest.mark.skipif(cython is None, reason="requires cython") @pytest.mark.slow -@pytest.mark.xfail(sys.platform == "cygwin", +@pytest.mark.xfail(IS_32BIT_CYGWIN, reason="Random fork() failures", raises=BlockingIOError) def test_cython(tmp_path): diff --git a/numpy/testing/_private/utils.py b/numpy/testing/_private/utils.py index b4d42728e3cd..519893aa7ac1 100644 --- a/numpy/testing/_private/utils.py +++ b/numpy/testing/_private/utils.py @@ -35,7 +35,7 @@ 'SkipTest', 'KnownFailureException', 'temppath', 'tempdir', 'IS_PYPY', 'HAS_REFCOUNT', 'suppress_warnings', 'assert_array_compare', '_assert_valid_refcount', '_gen_alignment_data', 'assert_no_gc_cycles', - 'break_cycles', 'HAS_LAPACK64' + 'break_cycles', 'HAS_LAPACK64', 'IS_32BIT_CYGWIN' ] @@ -48,6 +48,7 @@ class KnownFailureException(Exception): verbose = 0 IS_PYPY = platform.python_implementation() == 'PyPy' +IS_32BIT_CYGWIN = (sys.platform == 'cygwin' and (sys.maxsize >> 30) == 1) HAS_REFCOUNT = getattr(sys, 'getrefcount', None) is not None HAS_LAPACK64 = numpy.linalg.lapack_lite._ilp64 diff --git a/numpy/tests/test_public_api.py b/numpy/tests/test_public_api.py index e502f09107eb..711f81659f00 100644 --- a/numpy/tests/test_public_api.py +++ b/numpy/tests/test_public_api.py @@ -7,6 +7,7 @@ import numpy as np import numpy +from numpy.testing._private.utils import IS_32BIT_CYGWIN import pytest try: @@ -77,7 +78,7 @@ def test_numpy_namespace(): @pytest.mark.parametrize('name', ['testing', 'Tester']) -@pytest.mark.xfail(sys.platform == 'cygwin', reason="Random fork failures", +@pytest.mark.xfail(IS_32BIT_CYGWIN, reason="Random fork failures", raises=BlockingIOError) def test_import_lazy_import(name): """Make sure we can actually use the modules we lazy load. diff --git a/numpy/tests/test_scripts.py b/numpy/tests/test_scripts.py index 697a76b3a5ae..2e3b1ea1dd4e 100644 --- a/numpy/tests/test_scripts.py +++ b/numpy/tests/test_scripts.py @@ -10,6 +10,7 @@ import numpy as np from numpy.testing import assert_equal +from numpy.testing._private.utils import IS_32BIT_CYGWIN is_inplace = isfile(pathjoin(dirname(np.__file__), '..', 'setup.py')) @@ -41,7 +42,7 @@ def test_f2py(f2py_cmd): assert_equal(stdout.strip(), np.__version__.encode('ascii')) -@pytest.mark.xfail(sys.platform == 'cygwin', reason="Random fork failures", +@pytest.mark.xfail(IS_32BIT_CYGWIN, reason="Random fork failures", raises=BlockingIOError) def test_pep338(): stdout = subprocess.check_output([sys.executable, '-mnumpy.f2py', '-v']) From c519dd0cbbff4ddfc9890a94b18eeeb95756f483 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Fri, 19 Jun 2020 13:16:56 -0400 Subject: [PATCH 21/31] BLD: Fix flags added to compiler line for old GCC on MS. It may be worth broadening the platform list, since I believe the error this tries to fix is in the MS ABI/CRT rather than in the Cygwin runtime. --- setup.py | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index 9f62dd952770..a5b434830d50 100755 --- a/setup.py +++ b/setup.py @@ -229,13 +229,8 @@ def build_a_library(self, build_info, lib_name, libraries): build_info['extra_compiler_args'] = args if _is_old_gcc_on_cygwin(self): args = build_info.get('extra_compiler_args') or [] - args.append( - '-fno-asynchronous-unwind-tables ' - '-ffixed-xmm16 -ffixed-xmm17 -ffixed-xmm18 -ffixed-xmm19 ' - '-ffixed-xmm20 -ffixed-xmm21 -ffixed-xmm22 -ffixed-xmm23 ' - '-ffixed-xmm24 -ffixed-xmm25 -ffixed-xmm26 -ffixed-xmm27 ' - '-ffixed-xmm28 -ffixed-xmm29 -ffixed-xmm30 -ffixed-xmm31' - ) + args.append('-fno-asynchronous-unwind-tables') + args.extend('-ffixed-xmm{0:02d}'.format(i) for i in range(16, 32)) build_info['extra_compiler_args'] = args build_clib.build_a_library(self, build_info, lib_name, libraries) @@ -246,13 +241,8 @@ def build_extension(self, ext): ext.extra_compile_args.append('-std=c99') if _is_old_gcc_on_cygwin(self): if '-ffixed-xmm' not in ext.extra_compile_args: - ext.extra_compile_args.append( - '-fno-asynchronous-unwind-tables ' - '-ffixed-xmm16 -ffixed-xmm17 -ffixed-xmm18 -ffixed-xmm19 ' - '-ffixed-xmm20 -ffixed-xmm21 -ffixed-xmm22 -ffixed-xmm23 ' - '-ffixed-xmm24 -ffixed-xmm25 -ffixed-xmm26 -ffixed-xmm27 ' - '-ffixed-xmm28 -ffixed-xmm29 -ffixed-xmm30 -ffixed-xmm31' - ) + ext.extra_compile_args.append('-fno-asynchronous-unwind-tables') + ext.extra_compile_args.extend('-ffixed-xmm{0:02d}'.format(i) for i in range(16, 32)) build_ext.build_extension(self, ext) return new_build_clib, new_build_ext From 33e863b3709aa2d173d63eff68c7515d2ee94fe3 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:26:52 -0400 Subject: [PATCH 22/31] TST: parametrize test_npymath_complex. Allows more precise xfail. --- numpy/core/tests/test_multiarray.py | 48 +++++++++++++++++------------ 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 9b6b8bee2e15..e4e6a74b623d 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -8576,26 +8576,36 @@ class MyAlwaysEqualNew(MyAlwaysEqual): assert_equal(array != my_always_equal, 'ne') -@pytest.mark.xfail(sys.platform == 'cygwin', - reason='abs(inf+nanj) short-circuits to inf', - strict=True) -def test_npymath_complex(): +@pytest.mark.parametrize( + ["fun", "npfun", "x", "y", "dtype"], + [ + pytest.param( + fun, npfun, x, y, dtype, marks=pytest.mark.xfail( + sys.platform == "cygwin" and + dtype in (np.clongdouble,) and + fun == _multiarray_tests.npy_cabs and + np.isinf([x, y]).any() and np.isnan([x, y]).any(), + reason='abs(inf+nanj) short-circuits to inf', + strict=True, + ) + ) + for (fun, npfun), x, y, dtype in itertools.product( + [ + (_multiarray_tests.npy_cabs, np.absolute), + (_multiarray_tests.npy_carg, np.angle), + ], + [1, np.inf, -np.inf, np.nan], + [1, np.inf, -np.inf, np.nan], + [np.complex64, np.complex128, np.clongdouble], + ) + ], +) +def test_npymath_complex(fun, npfun, x, y, dtype): # Smoketest npymath functions - from numpy.core._multiarray_tests import ( - npy_cabs, npy_carg) - - funcs = {npy_cabs: np.absolute, - npy_carg: np.angle} - vals = (1, np.inf, -np.inf, np.nan) - types = (np.complex64, np.complex128, np.clongdouble) - - for fun, npfun in funcs.items(): - for x, y in itertools.product(vals, vals): - for t in types: - z = t(complex(x, y)) - got = fun(z) - expected = npfun(z) - assert_allclose(got, expected) + z = dtype(complex(x, y)) + got = fun(z) + expected = npfun(z) + assert_allclose(got, expected) def test_npymath_real(): From 853f82aedf3d8503ee8118cb3a345e032d1fe628 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Sat, 29 Aug 2020 07:08:44 -0400 Subject: [PATCH 23/31] TST: Clarify the xfail messages for branch cuts. I think these are the tests where the "branch cut code doesn't use sign of zero" became relevant. --- numpy/core/tests/test_umath.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/numpy/core/tests/test_umath.py b/numpy/core/tests/test_umath.py index db825764f762..b54657c847f8 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -3011,9 +3011,11 @@ def test_precisions_consistent(self): assert_almost_equal(fcf, fcd, decimal=6, err_msg='fch-fcd %s' % f) assert_almost_equal(fcl, fcd, decimal=15, err_msg='fch-fcl %s' % f) - @pytest.mark.xfail(sys.platform == 'cygwin', - reason='0.7071j != 0.7071j, apparently', - strict=True) + @pytest.mark.xfail( + sys.platform == 'cygwin', + reason='Cygwin does not use the sign of zero for branch cuts along an axis', + strict=True, + ) def test_branch_cuts(self): # check branch cuts and continuity on them _check_branch_cut(np.log, -0.5, 1j, 1, -1, True) @@ -3039,9 +3041,11 @@ def test_branch_cuts(self): _check_branch_cut(np.arccosh, [0-2j, 2j, 2], [1, 1, 1j], 1, 1) _check_branch_cut(np.arctanh, [0-2j, 2j, 0], [1, 1, 1j], 1, 1) - @pytest.mark.xfail(sys.platform == 'cygwin', - reason='square root faces small loss of precision', - strict=True) + @pytest.mark.xfail( + sys.platform == 'cygwin', + reason='Cygwin does not use sign of zero for branch cuts along an axis', + strict=True, + ) def test_branch_cuts_complex64(self): # check branch cuts and continuity on them _check_branch_cut(np.log, -0.5, 1j, 1, -1, True, np.complex64) From c32f1ce028d5d83455cb6881068e8c01a3b69377 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Sat, 29 Aug 2020 07:10:19 -0400 Subject: [PATCH 24/31] BLD: Remove probably-unnecessary include. This was trying to ensure the definition of symbols that depend on feature macros set in "Python.h". That issue seems to have resolved itself. --- numpy/random/src/distributions/random_hypergeometric.c | 1 - 1 file changed, 1 deletion(-) diff --git a/numpy/random/src/distributions/random_hypergeometric.c b/numpy/random/src/distributions/random_hypergeometric.c index dc05c7729d82..668e10a9f483 100644 --- a/numpy/random/src/distributions/random_hypergeometric.c +++ b/numpy/random/src/distributions/random_hypergeometric.c @@ -1,4 +1,3 @@ -#include "Python.h" #include #include "numpy/random/distributions.h" #include "logfactorial.h" From 31c1fe1b85dc5af055c4ff921ae5fc208fcd4cb5 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Sun, 23 Aug 2020 18:21:24 -0400 Subject: [PATCH 25/31] TST: Try to keep testing code from changing tempfile name. I think I saw a test failure because the generated tempfile name contained the string "mkl". I think what the code is trying to do is to change the "[mkl]" section to a "[DEFAULT]" section without changing any of the contents of that section. I think this change should do the trick. --- numpy/distutils/tests/test_system_info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/numpy/distutils/tests/test_system_info.py b/numpy/distutils/tests/test_system_info.py index ec15126f7f7b..fe44ef139602 100644 --- a/numpy/distutils/tests/test_system_info.py +++ b/numpy/distutils/tests/test_system_info.py @@ -277,7 +277,7 @@ def test_overrides(self): # Also, the values will be taken from a section named '[DEFAULT]' with open(cfg, 'r') as fid: - dflt = fid.read().replace('mkl', 'DEFAULT') + dflt = fid.read().replace('[mkl]', '[DEFAULT]', 1) with open(cfg, 'w') as fid: fid.write(dflt) info = mkl_info() From 3666fce7b908c746124a7126c1104e36f722d645 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Sat, 29 Aug 2020 07:07:17 -0400 Subject: [PATCH 26/31] BLD: Mark modfl as problematic on cygwin. The implementation currently segfaults. I'll report this to the developers soon; hopefully it can be re-enabled soon. --- numpy/core/src/common/npy_config.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/numpy/core/src/common/npy_config.h b/numpy/core/src/common/npy_config.h index abcf2ca74608..b1097fd9c550 100644 --- a/numpy/core/src/common/npy_config.h +++ b/numpy/core/src/common/npy_config.h @@ -138,6 +138,9 @@ #undef HAVE_CATANHF #undef HAVE_CATANHL +/* modfl seems to be segfaulting at the moment */ +#undef HAVE_MODFL + #endif /* powl gives zero division warning on OS X, see gh-8307 */ From 78e8c95c38a020fb0e1bc40b0c908ccf5148b30b Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Tue, 1 Sep 2020 11:13:18 -0400 Subject: [PATCH 27/31] Undef HAVE_MODFL only on 64-bit cygwin 32-bit modfl appears to work fine. Problem exists in Cygwin 3.1.5 to 3.1.7 and should be fixed in 3.2.0. --- numpy/core/src/common/npy_config.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/numpy/core/src/common/npy_config.h b/numpy/core/src/common/npy_config.h index b1097fd9c550..4d66d533c10b 100644 --- a/numpy/core/src/common/npy_config.h +++ b/numpy/core/src/common/npy_config.h @@ -138,8 +138,10 @@ #undef HAVE_CATANHF #undef HAVE_CATANHL -/* modfl seems to be segfaulting at the moment */ +/* modfl segfaults on 64-bit Cygwin 3.1.5-3.1.7 */ +#ifdef __x86_64__ #undef HAVE_MODFL +#endif #endif From af0de3dd68c4d3027feb1478d642f83725f8216f Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Tue, 27 Oct 2020 16:01:58 -0400 Subject: [PATCH 28/31] Revert "BLD: Fix flags added to compiler line for old GCC on MS." This reverts commit 6ffbcb2e0df30863787aa3a3da796ad9a93c4a79. Replaced by 17548. --- setup.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/setup.py b/setup.py index a5b434830d50..9f62dd952770 100755 --- a/setup.py +++ b/setup.py @@ -229,8 +229,13 @@ def build_a_library(self, build_info, lib_name, libraries): build_info['extra_compiler_args'] = args if _is_old_gcc_on_cygwin(self): args = build_info.get('extra_compiler_args') or [] - args.append('-fno-asynchronous-unwind-tables') - args.extend('-ffixed-xmm{0:02d}'.format(i) for i in range(16, 32)) + args.append( + '-fno-asynchronous-unwind-tables ' + '-ffixed-xmm16 -ffixed-xmm17 -ffixed-xmm18 -ffixed-xmm19 ' + '-ffixed-xmm20 -ffixed-xmm21 -ffixed-xmm22 -ffixed-xmm23 ' + '-ffixed-xmm24 -ffixed-xmm25 -ffixed-xmm26 -ffixed-xmm27 ' + '-ffixed-xmm28 -ffixed-xmm29 -ffixed-xmm30 -ffixed-xmm31' + ) build_info['extra_compiler_args'] = args build_clib.build_a_library(self, build_info, lib_name, libraries) @@ -241,8 +246,13 @@ def build_extension(self, ext): ext.extra_compile_args.append('-std=c99') if _is_old_gcc_on_cygwin(self): if '-ffixed-xmm' not in ext.extra_compile_args: - ext.extra_compile_args.append('-fno-asynchronous-unwind-tables') - ext.extra_compile_args.extend('-ffixed-xmm{0:02d}'.format(i) for i in range(16, 32)) + ext.extra_compile_args.append( + '-fno-asynchronous-unwind-tables ' + '-ffixed-xmm16 -ffixed-xmm17 -ffixed-xmm18 -ffixed-xmm19 ' + '-ffixed-xmm20 -ffixed-xmm21 -ffixed-xmm22 -ffixed-xmm23 ' + '-ffixed-xmm24 -ffixed-xmm25 -ffixed-xmm26 -ffixed-xmm27 ' + '-ffixed-xmm28 -ffixed-xmm29 -ffixed-xmm30 -ffixed-xmm31' + ) build_ext.build_extension(self, ext) return new_build_clib, new_build_ext From 8fc9a9f289f023f53be44f770af7524523fc7472 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Tue, 27 Oct 2020 16:03:44 -0400 Subject: [PATCH 29/31] Revert "BLD: Fix code checking for old GCC on cygwin." This reverts commit d9c21bbffe176316192cdc4c7fd251ea99c7fecd. Replaced by numpy/numpy#17548. --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 9f62dd952770..edb9a5506025 100755 --- a/setup.py +++ b/setup.py @@ -211,7 +211,7 @@ def _gcc_version_less_than(obj, test_version): [cc, "-dumpversion"], stdout=subprocess.PIPE, ) - ver = LooseVersion(out.stdout.strip().decode("ascii")) + ver = LooseVersion(out.stdout.strip()) gcc_version_lt_provided = ver < test_version return gcc_version_lt_provided @@ -244,7 +244,7 @@ def build_extension(self, ext): if _needs_gcc_c99_flag(self): if '-std=c99' not in ext.extra_compile_args: ext.extra_compile_args.append('-std=c99') - if _is_old_gcc_on_cygwin(self): + if _is_old_gcc_on_cygwin(self, ext): if '-ffixed-xmm' not in ext.extra_compile_args: ext.extra_compile_args.append( '-fno-asynchronous-unwind-tables ' From 7c43e1632f55c165909f48d9b24ef4ffba3fc099 Mon Sep 17 00:00:00 2001 From: DWesl <22566757+DWesl@users.noreply.github.com> Date: Tue, 27 Oct 2020 16:04:18 -0400 Subject: [PATCH 30/31] Revert "BLD: Remind GCC that .seh_savexmm fails for xmm16-31." This reverts commit 92eaff35813f668a24cefd625600a80dbcd9e3c7. Replaced by numpy/numpy#17548. --- setup.py | 42 ------------------------------------------ 1 file changed, 42 deletions(-) diff --git a/setup.py b/setup.py index edb9a5506025..bb80761981b1 100755 --- a/setup.py +++ b/setup.py @@ -181,7 +181,6 @@ def get_build_overrides(): """ from numpy.distutils.command.build_clib import build_clib from numpy.distutils.command.build_ext import build_ext - from distutils.version import LooseVersion def _needs_gcc_c99_flag(obj): if obj.compiler.compiler_type != 'unix': @@ -199,44 +198,12 @@ def _needs_gcc_c99_flag(obj): return False return True - def _is_64bit_build(): - return (sys.maxsize >> 62) == 1 - - def _gcc_version_less_than(obj, test_version): - gcc_version_lt_provided = False - if obj.compiler.compiler_type == "unix": - cc = obj.compiler.compiler[0] - if "gcc" in cc: - out = subprocess.run( - [cc, "-dumpversion"], - stdout=subprocess.PIPE, - ) - ver = LooseVersion(out.stdout.strip()) - gcc_version_lt_provided = ver < test_version - return gcc_version_lt_provided - - def _is_old_gcc_on_cygwin(obj): - return ( - sys.platform == "cygwin" and _is_64bit_build() and - _gcc_version_less_than(obj, LooseVersion("8.4")) - ) - class new_build_clib(build_clib): def build_a_library(self, build_info, lib_name, libraries): if _needs_gcc_c99_flag(self): args = build_info.get('extra_compiler_args') or [] args.append('-std=c99') build_info['extra_compiler_args'] = args - if _is_old_gcc_on_cygwin(self): - args = build_info.get('extra_compiler_args') or [] - args.append( - '-fno-asynchronous-unwind-tables ' - '-ffixed-xmm16 -ffixed-xmm17 -ffixed-xmm18 -ffixed-xmm19 ' - '-ffixed-xmm20 -ffixed-xmm21 -ffixed-xmm22 -ffixed-xmm23 ' - '-ffixed-xmm24 -ffixed-xmm25 -ffixed-xmm26 -ffixed-xmm27 ' - '-ffixed-xmm28 -ffixed-xmm29 -ffixed-xmm30 -ffixed-xmm31' - ) - build_info['extra_compiler_args'] = args build_clib.build_a_library(self, build_info, lib_name, libraries) class new_build_ext(build_ext): @@ -244,15 +211,6 @@ def build_extension(self, ext): if _needs_gcc_c99_flag(self): if '-std=c99' not in ext.extra_compile_args: ext.extra_compile_args.append('-std=c99') - if _is_old_gcc_on_cygwin(self, ext): - if '-ffixed-xmm' not in ext.extra_compile_args: - ext.extra_compile_args.append( - '-fno-asynchronous-unwind-tables ' - '-ffixed-xmm16 -ffixed-xmm17 -ffixed-xmm18 -ffixed-xmm19 ' - '-ffixed-xmm20 -ffixed-xmm21 -ffixed-xmm22 -ffixed-xmm23 ' - '-ffixed-xmm24 -ffixed-xmm25 -ffixed-xmm26 -ffixed-xmm27 ' - '-ffixed-xmm28 -ffixed-xmm29 -ffixed-xmm30 -ffixed-xmm31' - ) build_ext.build_extension(self, ext) return new_build_clib, new_build_ext From 0c93f5f27bbf235a69161910c1dc486bda0a342c Mon Sep 17 00:00:00 2001 From: Charles Harris Date: Thu, 31 Dec 2020 16:26:23 -0700 Subject: [PATCH 31/31] MAINT: Fixup setpy.py merge --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index bb80761981b1..6033916c2595 100755 --- a/setup.py +++ b/setup.py @@ -181,6 +181,7 @@ def get_build_overrides(): """ from numpy.distutils.command.build_clib import build_clib from numpy.distutils.command.build_ext import build_ext + from distutils.version import LooseVersion def _needs_gcc_c99_flag(obj): if obj.compiler.compiler_type != 'unix':