Thanks to visit codestin.com
Credit goes to github.com

Skip to content

TST: Use meson for testing f2py #25427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,7 @@ stages:
# yum does not have a ninja package, so use the PyPI one
docker run -v $(pwd):/numpy -e CFLAGS="-msse2 -std=c99 -UNDEBUG" \
-e F77=gfortran-5 -e F90=gfortran-5 quay.io/pypa/manylinux2014_i686 \
/bin/bash -xc " \
git config --global --add safe.directory /numpy && \
cd /numpy && \
/opt/python/cp39-cp39/bin/python -mvenv venv && \
source venv/bin/activate && \
target=\$(python3 tools/openblas_support.py) && \
cp -r \$target/lib/* /usr/lib && \
cp \$target/include/* /usr/include && \
python3 -m pip install ninja && \
python3 -m pip install -r test_requirements.txt && \
echo CFLAGS \$CFLAGS && \
python3 -m pip install -v . && \
cd tools && \
python3 -m pytest --pyargs numpy"
/bin/bash -xc "source /numpy/tools/ci/run_32_bit_linux_docker.sh"
displayName: 'Run 32-bit manylinux2014 Docker Build / Tests'

- job: Windows
Expand Down
2 changes: 1 addition & 1 deletion numpy/distutils/tests/test_build_ext.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def test_multi_fortran_libs_link(tmp_path):
# We need to make sure we actually have an f77 compiler.
# This is nontrivial, so we'll borrow the utilities
# from f2py tests:
from numpy.f2py.tests.util import has_f77_compiler
from numpy.distutils.tests.utilities import has_f77_compiler
if not has_f77_compiler():
pytest.skip('No F77 compiler found')

Expand Down
90 changes: 90 additions & 0 deletions numpy/distutils/tests/utilities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Kanged out of numpy.f2py.tests.util for test_build_ext
from numpy.testing import IS_WASM
import textwrap
import shutil
import tempfile
import os
import re
import subprocess
import sys

#
# Check if compilers are available at all...
#

_compiler_status = None


def _get_compiler_status():
global _compiler_status
if _compiler_status is not None:
return _compiler_status

_compiler_status = (False, False, False)
if IS_WASM:
# Can't run compiler from inside WASM.
return _compiler_status

# XXX: this is really ugly. But I don't know how to invoke Distutils
# in a safer way...
code = textwrap.dedent(
f"""\
import os
import sys
sys.path = {repr(sys.path)}

def configuration(parent_name='',top_path=None):
global config
from numpy.distutils.misc_util import Configuration
config = Configuration('', parent_name, top_path)
return config

from numpy.distutils.core import setup
setup(configuration=configuration)

config_cmd = config.get_config_cmd()
have_c = config_cmd.try_compile('void foo() {{}}')
print('COMPILERS:%%d,%%d,%%d' %% (have_c,
config.have_f77c(),
config.have_f90c()))
sys.exit(99)
"""
)
code = code % dict(syspath=repr(sys.path))

tmpdir = tempfile.mkdtemp()
try:
script = os.path.join(tmpdir, "setup.py")

with open(script, "w") as f:
f.write(code)

cmd = [sys.executable, "setup.py", "config"]
p = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=tmpdir
)
out, err = p.communicate()
finally:
shutil.rmtree(tmpdir)

m = re.search(rb"COMPILERS:(\d+),(\d+),(\d+)", out)
if m:
_compiler_status = (
bool(int(m.group(1))),
bool(int(m.group(2))),
bool(int(m.group(3))),
)
# Finished
return _compiler_status


def has_c_compiler():
return _get_compiler_status()[0]


def has_f77_compiler():
return _get_compiler_status()[1]


def has_f90_compiler():
return _get_compiler_status()[2]
26 changes: 7 additions & 19 deletions numpy/f2py/_backends/_meson.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,6 @@ def _move_exec_to_root(self, build_dir: Path):
shutil.copy2(path_object, dest_path)
os.remove(path_object)

def _get_build_command(self):
return [
"meson",
"setup",
self.meson_build_dir,
]

def write_meson_build(self, build_dir: Path) -> None:
"""Writes the meson build file at specified location"""
meson_template = MesonTemplate(
Expand All @@ -122,19 +115,14 @@ def write_meson_build(self, build_dir: Path) -> None:
meson_build_file.write_text(src)
return meson_build_file

def _run_subprocess_command(self, command, cwd):
subprocess.run(command, cwd=cwd, check=True)

def run_meson(self, build_dir: Path):
completed_process = subprocess.run(self._get_build_command(), cwd=build_dir)
if completed_process.returncode != 0:
raise subprocess.CalledProcessError(
completed_process.returncode, completed_process.args
)
completed_process = subprocess.run(
["meson", "compile", "-C", self.meson_build_dir], cwd=build_dir
)
if completed_process.returncode != 0:
raise subprocess.CalledProcessError(
completed_process.returncode, completed_process.args
)
setup_command = ["meson", "setup", self.meson_build_dir]
self._run_subprocess_command(setup_command, build_dir)
compile_command = ["meson", "compile", "-C", self.meson_build_dir]
self._run_subprocess_command(compile_command, build_dir)

def compile(self) -> None:
self.sources = _prepare_sources(self.modulename, self.sources, self.build_dir)
Expand Down
1 change: 1 addition & 0 deletions numpy/f2py/tests/test_abstract_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@


@pytest.mark.skipif(IS_WASM, reason="Cannot start subprocess")
@pytest.mark.slow
class TestAbstractInterface(util.F2PyTest):
sources = [util.getpath("tests", "src", "abstract_interface", "foo.f90")]

Expand Down
22 changes: 7 additions & 15 deletions numpy/f2py/tests/test_array_from_pyobj.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import copy
import platform
import pytest
from pathlib import Path

import numpy as np

Expand All @@ -19,31 +20,22 @@
**_typeinfo)


def get_testdir():
testroot = Path(__file__).resolve().parent / "src"
return testroot / "array_from_pyobj"

def setup_module():
"""
Build the required testing extension module

"""
global wrap

# Check compiler availability first
if not util.has_c_compiler():
pytest.skip("No C compiler available")

if wrap is None:
config_code = """
config.add_extension('test_array_from_pyobj_ext',
sources=['wrapmodule.c', 'fortranobject.c'],
define_macros=[])
"""
d = os.path.dirname(__file__)
src = [
util.getpath("tests", "src", "array_from_pyobj", "wrapmodule.c"),
util.getpath("src", "fortranobject.c"),
util.getpath("src", "fortranobject.h"),
get_testdir() / "wrapmodule.c",
]
wrap = util.build_module_distutils(src, config_code,
"test_array_from_pyobj_ext")
wrap = util.build_meson(src, module_name = "test_array_from_pyobj_ext")


def flags_info(arr):
Expand Down
1 change: 1 addition & 0 deletions numpy/f2py/tests/test_block_docstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from numpy.testing import IS_PYPY


@pytest.mark.slow
class TestBlockDocString(util.F2PyTest):
sources = [util.getpath("tests", "src", "block_docstring", "foo.f")]

Expand Down
5 changes: 4 additions & 1 deletion numpy/f2py/tests/test_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class TestF77Callback(util.F2PyTest):
sources = [util.getpath("tests", "src", "callback", "foo.f")]

@pytest.mark.parametrize("name", "t,t2".split(","))
@pytest.mark.slow
def test_all(self, name):
self.check_function(name)

Expand Down Expand Up @@ -205,6 +206,7 @@ class TestF77CallbackPythonTLS(TestF77Callback):
class TestF90Callback(util.F2PyTest):
sources = [util.getpath("tests", "src", "callback", "gh17797.f90")]

@pytest.mark.slow
def test_gh17797(self):
def incr(x):
return x + 123
Expand All @@ -222,6 +224,7 @@ class TestGH18335(util.F2PyTest):
"""
sources = [util.getpath("tests", "src", "callback", "gh18335.f90")]

@pytest.mark.slow
def test_gh18335(self):
def foo(x):
x[0] += 1
Expand All @@ -235,7 +238,7 @@ class TestGH25211(util.F2PyTest):
util.getpath("tests", "src", "callback", "gh25211.pyf")]
module_name = "callback2"

def test_gh18335(self):
def test_gh25211(self):
def bar(x):
return x*x

Expand Down
3 changes: 3 additions & 0 deletions numpy/f2py/tests/test_character.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from numpy.f2py.tests import util


@pytest.mark.slow
class TestCharacterString(util.F2PyTest):
# options = ['--debug-capi', '--build-dir', '/tmp/test-build-f2py']
suffix = '.f90'
Expand Down Expand Up @@ -512,6 +513,7 @@ class TestMiscCharacter(util.F2PyTest):
end subroutine {fprefix}_character_bc_old
""")

@pytest.mark.slow
def test_gh18684(self):
# Test character(len=5) and character*5 usages
f = getattr(self.module, self.fprefix + '_gh18684')
Expand Down Expand Up @@ -596,6 +598,7 @@ class TestStringAssumedLength(util.F2PyTest):
def test_gh24008(self):
self.module.greet("joe", "bob")

@pytest.mark.slow
class TestStringOptionalInOut(util.F2PyTest):
sources = [util.getpath("tests", "src", "string", "gh24662.f90")]

Expand Down
9 changes: 1 addition & 8 deletions numpy/f2py/tests/test_common.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import os
import sys
import pytest

import numpy as np
from . import util


@pytest.mark.slow
class TestCommonBlock(util.F2PyTest):
sources = [util.getpath("tests", "src", "common", "block.f")]

@pytest.mark.skipif(sys.platform == "win32",
reason="Fails with MinGW64 Gfortran (Issue #9673)")
def test_common_block(self):
self.module.initcb()
assert self.module.block.long_bn == np.array(1.0, dtype=np.float64)
Expand All @@ -21,7 +16,5 @@ def test_common_block(self):
class TestCommonWithUse(util.F2PyTest):
sources = [util.getpath("tests", "src", "common", "gh19161.f90")]

@pytest.mark.skipif(sys.platform == "win32",
reason="Fails with MinGW64 Gfortran (Issue #9673)")
def test_common_gh19161(self):
assert self.module.data.x == 0
3 changes: 3 additions & 0 deletions numpy/f2py/tests/test_crackfortran.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ class TestDimSpec(util.F2PyTest):
)

@pytest.mark.parametrize("dimspec", all_dimspecs)
@pytest.mark.slow
def test_array_size(self, dimspec):

count = self.all_dimspecs.index(dimspec)
Expand Down Expand Up @@ -276,6 +277,7 @@ def test_input_encoding(self, tmp_path, encoding):
assert mod[0]['name'] == 'foo'


@pytest.mark.slow
class TestUnicodeComment(util.F2PyTest):
sources = [util.getpath("tests", "src", "crackfortran", "unicode_comment.f90")]

Expand Down Expand Up @@ -327,6 +329,7 @@ def test_nameargspattern_backtracking(self, adversary):
class TestFunctionReturn(util.F2PyTest):
sources = [util.getpath("tests", "src", "crackfortran", "gh23598.f90")]

@pytest.mark.slow
def test_function_rettype(self):
# gh-23598
assert self.module.intproduct(3, 4) == 12
Expand Down
1 change: 1 addition & 0 deletions numpy/f2py/tests/test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class TestData(util.F2PyTest):
sources = [util.getpath("tests", "src", "crackfortran", "data_stmts.f90")]

# For gh-23276
@pytest.mark.slow
def test_data_stmts(self):
assert self.module.cmplxdat.i == 2
assert self.module.cmplxdat.j == 3
Expand Down
28 changes: 12 additions & 16 deletions numpy/f2py/tests/test_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,23 @@
import numpy as np
from numpy.testing import assert_array_equal, assert_equal
from . import util

from pathlib import Path

def get_docdir():
# assuming that documentation tests are run from a source
# directory
return os.path.abspath(os.path.join(
os.path.dirname(__file__),
'..', '..', '..',
'doc', 'source', 'f2py', 'code'))

# Assumes that spin is used to run tests
nproot = Path(__file__).resolve().parents[8]
return nproot / "doc" / "source" / "f2py" / "code"

pytestmark = pytest.mark.skipif(
not os.path.isdir(get_docdir()),
reason=('Could not find f2py documentation sources'
f' ({get_docdir()} does not exists)'))


def _path(*a):
return os.path.join(*((get_docdir(),) + a))
not get_docdir().is_dir(),
reason=f"Could not find f2py documentation sources"
f"({get_docdir()} does not exist)",
)

def _path(*args):
return get_docdir().joinpath(*args)

@pytest.mark.slow
class TestDocAdvanced(util.F2PyTest):
# options = ['--debug-capi', '--build-dir', '/tmp/build-f2py']
sources = [_path('asterisk1.f90'), _path('asterisk2.f90'),
Expand All @@ -37,7 +33,7 @@ def test_asterisk2(self):
foo = getattr(self.module, 'foo2')
assert_equal(foo(2), b'12')
assert_equal(foo(12), b'123456789A12')
assert_equal(foo(24), b'123456789A123456789B')
assert_equal(foo(20), b'123456789A123456789B')

def test_ftype(self):
ftype = self.module
Expand Down
2 changes: 1 addition & 1 deletion numpy/f2py/tests/test_f2cmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class TestF2Cmap(util.F2PyTest):
]

# gh-15095
def test_long_long_map(self):
def test_gh15095(self):
inp = np.ones(3)
out = self.module.func1(inp)
exp_out = 3
Expand Down
Loading