Skip to content

Commit 95eb99a

Browse files
authored
Merge pull request #396 from stfc/395_brackets
(Closes #395) Fix bug with trailing whitespace in CallBase.match
2 parents d2feb47 + 017750a commit 95eb99a

File tree

7 files changed

+255
-42
lines changed

7 files changed

+255
-42
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ Modifications by (in alphabetical order):
1818
* P. Vitt, University of Siegen, Germany
1919
* A. Voysey, UK Met Office
2020

21+
30/03/2023 PR #396 for #395. Fix trailing whitespace bug in CallBase.
22+
2123
13/03/2023 PR #391 for #324. Add GH workfow to automate a pypi upload during
2224
GH releases.
2325

src/fparser/.pylintrc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[FORMAT]
2+
3+
# Maximum number of characters on a single line. Black's default is 88.
4+
max-line-length=88
5+
6+
# fparser dynamically generates *_List classes so pylint can't
7+
# find them.
8+
generated-members=Fortran2003.*_List,Fortran2008.*_List
9+
10+
[DESIGN]
11+
# Maximum number of parents for a class (see R0901)
12+
max-parents=9
13+
14+
# Make sure private functions (_my_private_function) are also
15+
# documented, but standard double-underscore functions do not
16+
# need to have a docstring.
17+
no-docstring-rgx=__.*__

src/fparser/two/tests/.pylintrc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
[FORMAT]
2+
3+
# Maximum number of characters on a single line. Black's default is 88.
4+
max-line-length=88
5+
6+
# fparser dynamically generates *_List classes so pylint can't
7+
# find them.
8+
generated-members=Fortran2003.*_List,Fortran2008.*_List
9+
10+
[DESIGN]
11+
# Maximum number of parents for a class (see R0901)
12+
max-parents=9
13+
14+
# Make sure private functions (_my_private_function) are also
15+
# documented, but standard double-underscore functions do not
16+
# need to have a docstring.
17+
no-docstring-rgx=__.*__

src/fparser/two/tests/test_fortran2003.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Modified work Copyright (c) 2017-2022 Science and Technology
1+
# Modified work Copyright (c) 2017-2023 Science and Technology
22
# Facilities Council.
33
# Original work Copyright (c) 1999-2008 Pearu Peterson
44
#
@@ -1902,6 +1902,20 @@ def test_assignment_stmt():
19021902
assert isinstance(obj, tcls), repr(obj)
19031903
assert str(obj) == "b = a + 1D-8 + 1.1E+3"
19041904

1905+
# Extra white space around a part-ref
1906+
obj = tcls("zdepth(:) = ((gdept_1d(:) ))")
1907+
assert isinstance(obj, tcls), repr(obj)
1908+
assert str(obj) == "zdepth(:) = ((gdept_1d(:)))"
1909+
obj = tcls("zdepth(:) = (( gdept_1d(:) ))")
1910+
assert isinstance(obj, tcls), repr(obj)
1911+
assert str(obj) == "zdepth(:) = ((gdept_1d(:)))"
1912+
obj = tcls("zdepth(:) = ( ( gdept_1d(:) ) )")
1913+
assert isinstance(obj, tcls), repr(obj)
1914+
assert str(obj) == "zdepth(:) = ((gdept_1d(:)))"
1915+
obj = tcls("zdepth(:) = ( gdept_1d(:) ) ")
1916+
assert isinstance(obj, tcls), repr(obj)
1917+
assert str(obj) == "zdepth(:) = (gdept_1d(:))"
1918+
19051919

19061920
@pytest.mark.usefixtures("fake_symbol_table")
19071921
def test_pointer_assignment_stmt(): # R735

src/fparser/two/tests/test_utils.py

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018-2020 Science and Technology Facilities Council
1+
# Copyright (c) 2018-2023 Science and Technology Facilities Council.
22

33
# All rights reserved.
44

@@ -32,14 +32,15 @@
3232
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3333
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3434

35-
"""Test utils.py which contain base classes to support fparser,
35+
"""Test utils.py which contains base classes to support fparser,
3636
exception handling and ast traversal.
3737
3838
"""
3939

4040
import pytest
41-
from fparser.two.utils import FortranSyntaxError
4241
from fparser.api import get_reader
42+
from fparser.two import Fortran2003, utils
43+
4344

4445
# test BlockBase
4546

@@ -50,29 +51,27 @@ def test_blockbase_match_names(f2003_create):
5051
as it sets match_names to True.
5152
5253
"""
53-
from fparser.two.Fortran2003 import Derived_Type_Def, Case_Construct
54-
5554
# working named example
5655
reader = get_reader("type abc\nend type abc")
57-
ast = Derived_Type_Def(reader)
56+
ast = Fortran2003.Derived_Type_Def(reader)
5857
assert "TYPE :: abc\nEND TYPE abc" in str(ast)
5958

6059
# case insensitive
6160
reader = get_reader("type abc\nend type ABC")
62-
ast = Derived_Type_Def(reader)
61+
ast = Fortran2003.Derived_Type_Def(reader)
6362
assert "TYPE :: abc\nEND TYPE ABC" in str(ast)
6463

6564
# incorrect name exception
6665
reader = get_reader("type abc\nend type cde")
67-
with pytest.raises(FortranSyntaxError) as excinfo:
68-
ast = Derived_Type_Def(reader)
66+
with pytest.raises(utils.FortranSyntaxError) as excinfo:
67+
ast = Fortran2003.Derived_Type_Def(reader)
6968
assert "at line 2\n>>>end type cde\nExpecting name 'abc'" in str(excinfo.value)
7069

7170
# first name required if second name supplied
7271
# switch to using select case as it can trip the exception
7372
reader = get_reader("select case (i)\nend select label")
74-
with pytest.raises(FortranSyntaxError) as excinfo:
75-
ast = Case_Construct(reader)
73+
with pytest.raises(utils.FortranSyntaxError) as excinfo:
74+
ast = Fortran2003.Case_Construct(reader)
7675
assert (
7776
"at line 2\n>>>end select label\nName 'label' has no "
7877
"corresponding starting name"
@@ -86,28 +85,26 @@ def test_blockbase_match_name_classes(f2003_create):
8685
used when names can appear in multiple places.
8786
8887
"""
89-
from fparser.two.Fortran2003 import If_Construct
90-
9188
# working named example
9289
reader = get_reader("label:if (.true.) then\nendif label")
93-
ast = If_Construct(reader)
90+
ast = Fortran2003.If_Construct(reader)
9491
assert "label:IF (.TRUE.) THEN\nEND IF label" in str(ast)
9592

9693
# case insensitive
9794
reader = get_reader("label:if (.true.) then\nendif LABEL")
98-
ast = If_Construct(reader)
95+
ast = Fortran2003.If_Construct(reader)
9996
assert "label:IF (.TRUE.) THEN\nEND IF LABEL" in str(ast)
10097

10198
# incorrect name exception
10299
reader = get_reader("label:if (.true.) then\nendif bella")
103-
with pytest.raises(FortranSyntaxError) as excinfo:
104-
ast = If_Construct(reader)
100+
with pytest.raises(utils.FortranSyntaxError) as excinfo:
101+
ast = Fortran2003.If_Construct(reader)
105102
assert "at line 2\n>>>endif bella\nExpecting name 'label'" in str(excinfo.value)
106103

107104
# first name required if subsequent name supplied
108105
reader = get_reader("if (.true.) then\nendif label")
109-
with pytest.raises(FortranSyntaxError) as excinfo:
110-
ast = If_Construct(reader)
106+
with pytest.raises(utils.FortranSyntaxError) as excinfo:
107+
ast = Fortran2003.If_Construct(reader)
111108
assert (
112109
"at line 2\n>>>endif label\nName 'label' has no corresponding " "starting name"
113110
) in str(excinfo.value)
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# Copyright (c) 2023 Science and Technology Facilities Council.
2+
3+
# All rights reserved.
4+
5+
# Modifications made as part of the fparser project are distributed
6+
# under the following license:
7+
8+
# Redistribution and use in source and binary forms, with or without
9+
# modification, are permitted provided that the following conditions are
10+
# met:
11+
12+
# 1. Redistributions of source code must retain the above copyright
13+
# notice, this list of conditions and the following disclaimer.
14+
15+
# 2. Redistributions in binary form must reproduce the above copyright
16+
# notice, this list of conditions and the following disclaimer in the
17+
# documentation and/or other materials provided with the distribution.
18+
19+
# 3. Neither the name of the copyright holder nor the names of its
20+
# contributors may be used to endorse or promote products derived from
21+
# this software without specific prior written permission.
22+
23+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26+
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27+
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34+
35+
""" Module containing pytest tests for the fparser2 CallBase class. """
36+
37+
import pytest
38+
from fparser.two import Fortran2003
39+
from fparser.two import utils
40+
41+
42+
@pytest.mark.usefixtures("f2003_create")
43+
def test_call_base_match():
44+
"""Check that parent information is correctly set-up in the
45+
parse tree."""
46+
# Basic match is OK.
47+
assert utils.CallBase.match(
48+
Fortran2003.Procedure_Designator, Fortran2003.Actual_Arg_Spec_List, "ogg()"
49+
)
50+
# Trailing white space is ignored.
51+
assert utils.CallBase.match(
52+
Fortran2003.Procedure_Designator, Fortran2003.Actual_Arg_Spec_List, "ogg() "
53+
)
54+
# String doesn't end with ')'
55+
assert not utils.CallBase.match(
56+
Fortran2003.Procedure_Designator, Fortran2003.Actual_Arg_Spec_List, "ogg"
57+
)
58+
# Missing opening '('
59+
assert not utils.CallBase.match(
60+
Fortran2003.Procedure_Designator, Fortran2003.Actual_Arg_Spec_List, "ogg)"
61+
)
62+
# Missing lhs.
63+
assert not utils.CallBase.match(
64+
Fortran2003.Procedure_Designator, Fortran2003.Actual_Arg_Spec_List, "(ogg)"
65+
)
66+
# Additional, matching parentheses are OK.
67+
assert utils.CallBase.match(
68+
Fortran2003.Procedure_Designator,
69+
Fortran2003.Actual_Arg_Spec_List,
70+
"ogg((nanny) )",
71+
)
72+
# upper_lhs makes no difference when lhs is matched with a class.
73+
assert utils.CallBase.match(
74+
Fortran2003.Procedure_Designator,
75+
Fortran2003.Actual_Arg_Spec_List,
76+
"ogg()",
77+
upper_lhs=True,
78+
)
79+
# upper_lhs is respected when lhs is matched with a str
80+
assert not utils.CallBase.match(
81+
"ogg", Fortran2003.Actual_Arg_Spec_List, "ogg() ", upper_lhs=True
82+
)
83+
assert utils.CallBase.match(
84+
"OGG", Fortran2003.Actual_Arg_Spec_List, "ogg() ", upper_lhs=True
85+
) == ("OGG", None)
86+
# rhs can be matched using a str
87+
assert utils.CallBase.match(
88+
"ogg",
89+
"nanny",
90+
"ogg(nanny)",
91+
)
92+
assert not utils.CallBase.match(
93+
"ogg",
94+
"nanny",
95+
"ogg(granny)",
96+
)
97+
# require_rhs is respected
98+
assert utils.CallBase.match("ogg", "nanny", "ogg(nanny)", require_rhs=False) == (
99+
"ogg",
100+
"nanny",
101+
)
102+
assert utils.CallBase.match("ogg", "nanny", "ogg(nanny)", require_rhs=True) == (
103+
"ogg",
104+
"nanny",
105+
)
106+
assert not utils.CallBase.match("ogg", "nanny", "ogg()", require_rhs=True)
107+
108+
109+
@pytest.mark.usefixtures("f2003_create")
110+
def test_call_base_tostr():
111+
"""Test the tostr() method of CallBase."""
112+
fref = Fortran2003.Function_Reference("gytha(ogg)")
113+
assert fref.tostr() == "gytha(ogg)"
114+
fref = Fortran2003.Function_Reference("weatherwax( )")
115+
assert fref.tostr() == "weatherwax()"

0 commit comments

Comments
 (0)