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

Skip to content

BUG: Infer return types for Fortran functions in f2py #23600

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

Merged
merged 7 commits into from
Apr 28, 2023
Merged
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
2 changes: 1 addition & 1 deletion doc/source/f2py/code/ftype.f
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ SUBROUTINE FOO(N)
Cf2py integer optional,intent(in) :: n = 13
REAL A,X
COMMON /DATA/ A,X(3)
PRINT*, "IN FOO: N=",N," A=",A," X=[",X(1),X(2),X(3),"]"
C PRINT*, "IN FOO: N=",N," A=",A," X=[",X(1),X(2),X(3),"]"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we want to remove this line entirely?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack, sorry, didn't see this earlier, I'll open a general cleanup to make sure we have no print statements in the f2py tests this weekend.

END
C END OF FTYPE.F
5 changes: 5 additions & 0 deletions numpy/f2py/crackfortran.py
Original file line number Diff line number Diff line change
Expand Up @@ -2856,6 +2856,11 @@ def compute_deps(v, deps):
kindselect, charselect, typename = cracktypespec(
typespec, selector)
vars[n]['typespec'] = typespec
try:
if block['result']:
vars[block['result']]['typespec'] = typespec
except Exception:
pass
if kindselect:
if 'kind' in kindselect:
try:
Expand Down
6 changes: 6 additions & 0 deletions numpy/f2py/func2subr.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ def add(line, ret=ret):

sargs = ', '.join(args)
if f90mode:
# gh-23598 fix warning
# Essentially, this gets called again with modules where the name of the
# function is added to the arguments, which is not required, and removed
sargs = sargs.replace(f"{name}, ", '')
args = [arg for arg in args if arg != name]
rout['args'] = args
add('subroutine f2pywrap_%s_%s (%s)' %
(rout['modulename'], name, sargs))
if not signature:
Expand Down
4 changes: 4 additions & 0 deletions numpy/f2py/tests/src/crackfortran/gh23598.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
integer function intproduct(a, b) result(res)
integer, intent(in) :: a, b
res = a*b
end function
11 changes: 11 additions & 0 deletions numpy/f2py/tests/src/crackfortran/gh23598Warn.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module test_bug
implicit none
private
public :: intproduct

contains
integer function intproduct(a, b) result(res)
integer, intent(in) :: a, b
res = a*b
end function
end module
10 changes: 9 additions & 1 deletion numpy/f2py/tests/test_crackfortran.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,4 +312,12 @@ def test_nameargspattern_backtracking(self, adversary):
# according to the old version of the regex.
# that should still be true.
good_version_of_adversary = repeated_adversary + '@)@'
assert nameargspattern.search(good_version_of_adversary)
assert nameargspattern.search(good_version_of_adversary)


class TestFunctionReturn(util.F2PyTest):
sources = [util.getpath("tests", "src", "crackfortran", "gh23598.f90")]

def test_function_rettype(self):
# gh-23598
assert self.module.intproduct(3, 4) == 12
22 changes: 22 additions & 0 deletions numpy/f2py/tests/test_f2py2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ def hello_world_f90(tmpdir_factory):
return fn


@pytest.fixture(scope="session")
def gh23598_warn(tmpdir_factory):
"""F90 file for testing warnings in gh23598"""
fdat = util.getpath("tests", "src", "crackfortran", "gh23598Warn.f90").read_text()
fn = tmpdir_factory.getbasetemp() / "gh23598Warn.f90"
fn.write_text(fdat, encoding="ascii")
return fn


@pytest.fixture(scope="session")
def hello_world_f77(tmpdir_factory):
"""Generates a single f77 file for testing"""
Expand Down Expand Up @@ -91,6 +100,19 @@ def f2cmap_f90(tmpdir_factory):
return fn


def test_gh23598_warn(capfd, gh23598_warn, monkeypatch):
foutl = get_io_paths(gh23598_warn, mname="test")
ipath = foutl.f90inp
monkeypatch.setattr(
sys, "argv",
f'f2py {ipath} -m test'.split())

with util.switchdir(ipath.parent):
f2pycli() # Generate files
wrapper = foutl.wrap90.read_text()
assert "intproductf2pywrap, intpr" not in wrapper


def test_gen_pyf(capfd, hello_world_f90, monkeypatch):
"""Ensures that a signature file is generated via the CLI
CLI :: -h
Expand Down