From 46409edf99fd08e679ab4ba8b0d4d8b461242760 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/30] 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 | 6 +++--- numpy/random/src/distributions/random_hypergeometric.c | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/numpy/core/include/numpy/npy_common.h b/numpy/core/include/numpy/npy_common.h index c2e755958164..ac1259fff0c8 100644 --- a/numpy/core/include/numpy/npy_common.h +++ b/numpy/core/include/numpy/npy_common.h @@ -1,15 +1,15 @@ #ifndef _NPY_COMMON_H_ #define _NPY_COMMON_H_ +/* need Python.h for npy_intp, npy_uintp */ +#include + /* numpconfig.h is auto-generated */ #include "numpyconfig.h" #ifdef HAVE_NPY_CONFIG_H #include #endif -/* need Python.h for npy_intp, npy_uintp */ -#include - /* * 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 058cfa1f993602a05ef524a5e097551ded6855af 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/30] 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 1c3069363f84..c0459aab9b21 100644 --- a/numpy/distutils/fcompiler/__init__.py +++ b/numpy/distutils/fcompiler/__init__.py @@ -42,6 +42,9 @@ class CompilerNotFound(Exception): pass +if sys.platform == 'cygwin': + COMPILED_MODULES = [] + def flaglist(s): if is_string(s): return split_quoted(s) @@ -156,16 +159,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 @@ -681,6 +684,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 796dff3519d0..b55c0b2a67b9 100644 --- a/numpy/distutils/fcompiler/gnu.py +++ b/numpy/distutils/fcompiler/gnu.py @@ -84,7 +84,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"], @@ -252,7 +252,7 @@ def get_flags_arch(self): return [] def runtime_library_dir_option(self, dir): - if sys.platform[:3] == 'aix' or sys.platform == 'win32': + 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 @@ -287,7 +287,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 5c9f8a000a47b5633c566cec567a27daa0822f16 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/30] 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 | 13 +++++++++++++ 4 files changed, 29 insertions(+) diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index f36c27c6cb19..790ebf4e0880 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -8262,6 +8262,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 ( @@ -8281,6 +8284,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 acd442e2fbb6..30cbecd40c62 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -585,6 +585,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: @@ -607,6 +610,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 c7f44cf5097a..a03007fba3cf 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -667,9 +667,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 e7965c0cab44..f477fc69a9c3 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -3,6 +3,7 @@ import fnmatch import itertools import pytest +import sys from fractions import Fraction import numpy.core.umath as ncu @@ -566,6 +567,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 @@ -2737,6 +2741,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) @@ -2762,6 +2769,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) @@ -2806,6 +2816,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 973b14bb300f6d8dc5833778cb4dbe204998fd11 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/30] 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 c5b06697d330..0dd07ace7aba 100644 --- a/numpy/f2py/tests/util.py +++ b/numpy/f2py/tests/util.py @@ -319,6 +319,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 3f3bf9f70917..fcf0cd19c13c 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 77353463e9b4..c102fb914029 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 fb7ec5d83eb4..d219cf16076f 100644 --- a/numpy/tests/test_public_api.py +++ b/numpy/tests/test_public_api.py @@ -73,6 +73,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 a0f2ba70a4a1..f6e0981e4230 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(), b'2') +@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(), b'2') From acea1576ff313c8ffadb4965ab6329eff092e9a3 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/30] 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 c0459aab9b21..f9b56d0a1554 100644 --- a/numpy/distutils/fcompiler/__init__.py +++ b/numpy/distutils/fcompiler/__init__.py @@ -159,16 +159,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 34184fd93f455a151672f7b572015138c4d8d514 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/30] 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 aebe241a5694..001e61072abc 100644 --- a/numpy/core/src/common/npy_config.h +++ b/numpy/core/src/common/npy_config.h @@ -81,6 +81,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 9c07574eded468fc950c20e9cdba64ea599bb940 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/30] 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 30cbecd40c62..e029c1e3c5da 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -610,9 +610,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 df5b0c69196d94f1bfdfde811bcf3f6b2afaa575 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/30] 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 | 4 +++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py index a03007fba3cf..859573065b26 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -667,13 +667,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 b55c0b2a67b9..a5a3aa982bc4 100644 --- a/numpy/distutils/fcompiler/gnu.py +++ b/numpy/distutils/fcompiler/gnu.py @@ -252,7 +252,9 @@ def get_flags_arch(self): return [] def runtime_library_dir_option(self, dir): - if sys.platform[:3] == 'aix' or sys.platform == 'win32' or sys.platform == 'cygwin': + 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 From 8b11932e7415e6b95e3b73f4d5d3c33b423c40e6 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/30] 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 f9b56d0a1554..1c3069363f84 100644 --- a/numpy/distutils/fcompiler/__init__.py +++ b/numpy/distutils/fcompiler/__init__.py @@ -42,9 +42,6 @@ class CompilerNotFound(Exception): pass -if sys.platform == 'cygwin': - COMPILED_MODULES = [] - def flaglist(s): if is_string(s): return split_quoted(s) @@ -684,14 +681,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 fc56c7913159f78cccd2b6af01c8c67075eae2e6 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/30] 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 790ebf4e0880..4208f58e8233 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -8284,9 +8284,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 f477fc69a9c3..53f64b455f9a 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -567,9 +567,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 @@ -2816,9 +2813,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 10dae6e1a93ac70de61a27b1878821815d29414b 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/30] 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 859573065b26..fdab1e18ed14 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -646,44 +646,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 debf8461e12e5837c8330ec444328e56e6a46b36 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/30] 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 e029c1e3c5da..05b1ea1fce12 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -585,9 +585,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 b530f9908fddc28aa3ae5dc329020aaa968bd0ae 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/30] 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 fdab1e18ed14..176d4ce9a433 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -678,7 +678,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 c11ee6f52105ec653296088856a8f358177189f1 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/30] 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 176d4ce9a433..f03d51eebe27 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -699,7 +699,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 1a2292f89ec653939460eefa6d128e2cd6a7a2ee 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/30] 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 a5a3aa982bc4..977e1b0d86cd 100644 --- a/numpy/distutils/fcompiler/gnu.py +++ b/numpy/distutils/fcompiler/gnu.py @@ -84,7 +84,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 20df822e8c0774aa0164c995418239488195b734 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/30] 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 977e1b0d86cd..d3aae2d828e4 100644 --- a/numpy/distutils/fcompiler/gnu.py +++ b/numpy/distutils/fcompiler/gnu.py @@ -289,7 +289,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 6a1645258163a56b77c7d8b57c9832afa463946f 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/30] 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 f03d51eebe27..0308086c1f7e 100644 --- a/numpy/core/tests/test_scalarmath.py +++ b/numpy/core/tests/test_scalarmath.py @@ -678,7 +678,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 @@ -699,7 +699,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 92eaff35813f668a24cefd625600a80dbcd9e3c7 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/30] BLD: Remind GCC that .seh_savexmm fails for xmm16-31. Workaround for GCC bug 65782. Fixes numpy issue 14787. --- setup.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/setup.py b/setup.py index 2cd2bda02bdf..f491faaf39e9 100755 --- a/setup.py +++ b/setup.py @@ -234,6 +234,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 _is_using_gcc(obj): is_gcc = False @@ -245,12 +246,44 @@ def _is_using_gcc(obj): is_gcc = "gcc" in compiler_name return is_gcc + 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 _is_using_gcc(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): @@ -258,6 +291,15 @@ def build_extension(self, ext): if _is_using_gcc(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 d9c21bbffe176316192cdc4c7fd251ea99c7fecd 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/30] 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 f491faaf39e9..9a4eef21b1be 100755 --- a/setup.py +++ b/setup.py @@ -258,7 +258,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 @@ -291,7 +291,7 @@ def build_extension(self, ext): if _is_using_gcc(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 eca1e273d4501ecbdb3749c718dcd61ed36c25cb 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/30] 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 0dd07ace7aba..536d60089564 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 from hashlib import md5 @@ -322,7 +323,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 c102fb914029..ae4e15a43535 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 3827b7505314..87ef8667a223 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 8250ac8fa4e0..1a3e72cdaddb 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 f6e0981e4230..93d510a1448f 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(), b'2') -@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 6ffbcb2e0df30863787aa3a3da796ad9a93c4a79 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/30] 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 9a4eef21b1be..1c1171a6a944 100755 --- a/setup.py +++ b/setup.py @@ -276,13 +276,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) @@ -293,13 +288,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 5adbca171373e1dbadb28520b296f7bc9643ae29 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/30] 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 174a385e4843..827934779551 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -8262,26 +8262,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 51fbbb8385a3b7a9fab3eb40f89047b61d15c9dc 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/30] 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 cc90f03a20ac..c181f3775762 100644 --- a/numpy/core/tests/test_umath.py +++ b/numpy/core/tests/test_umath.py @@ -2785,9 +2785,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) @@ -2813,9 +2815,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 f47f3155771167ac216956bbc5f814f2d0261b41 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/30] 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 5cb8a0f6c8f75e20d88691b74c44c3da6c532cdf 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/30] 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 0768ffdde55a..3a2b2b2ac24c 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 ced41b59ad2ebd6c4554b5719c5691cefa4a3be6 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/30] 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 e92e070860ee..04a3d1e0bcca 100644 --- a/numpy/core/src/common/npy_config.h +++ b/numpy/core/src/common/npy_config.h @@ -129,6 +129,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 d706499f06c087b0dae5dc31e46c017b1a12b8ad 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/30] 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 04a3d1e0bcca..74bd83c87ca7 100644 --- a/numpy/core/src/common/npy_config.h +++ b/numpy/core/src/common/npy_config.h @@ -129,8 +129,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 160fd731485f554905a2078915de2b863e0179fa 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/30] 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 1c1171a6a944..9a4eef21b1be 100755 --- a/setup.py +++ b/setup.py @@ -276,8 +276,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) @@ -288,8 +293,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 cc9e8dfb60d5b18e257a5b128b2863016f405d3e 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/30] 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 9a4eef21b1be..f491faaf39e9 100755 --- a/setup.py +++ b/setup.py @@ -258,7 +258,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 @@ -291,7 +291,7 @@ def build_extension(self, ext): if _is_using_gcc(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 e18c4b675599806c7c1402c85345a3d2adfc2e5d 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/30] 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 f491faaf39e9..2cd2bda02bdf 100755 --- a/setup.py +++ b/setup.py @@ -234,7 +234,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 _is_using_gcc(obj): is_gcc = False @@ -246,44 +245,12 @@ def _is_using_gcc(obj): is_gcc = "gcc" in compiler_name return is_gcc - 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 _is_using_gcc(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): @@ -291,15 +258,6 @@ def build_extension(self, ext): if _is_using_gcc(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