Skip to content

Commit

Permalink
Merge pull request #396 from stfc/395_brackets
Browse files Browse the repository at this point in the history
(Closes #395) Fix bug with trailing whitespace in CallBase.match
  • Loading branch information
sergisiso authored Mar 30, 2023
2 parents d2feb47 + 017750a commit 95eb99a
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 42 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Modifications by (in alphabetical order):
* P. Vitt, University of Siegen, Germany
* A. Voysey, UK Met Office

30/03/2023 PR #396 for #395. Fix trailing whitespace bug in CallBase.

13/03/2023 PR #391 for #324. Add GH workfow to automate a pypi upload during
GH releases.

Expand Down
17 changes: 17 additions & 0 deletions src/fparser/.pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[FORMAT]

# Maximum number of characters on a single line. Black's default is 88.
max-line-length=88

# fparser dynamically generates *_List classes so pylint can't
# find them.
generated-members=Fortran2003.*_List,Fortran2008.*_List

[DESIGN]
# Maximum number of parents for a class (see R0901)
max-parents=9

# Make sure private functions (_my_private_function) are also
# documented, but standard double-underscore functions do not
# need to have a docstring.
no-docstring-rgx=__.*__
17 changes: 17 additions & 0 deletions src/fparser/two/tests/.pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[FORMAT]

# Maximum number of characters on a single line. Black's default is 88.
max-line-length=88

# fparser dynamically generates *_List classes so pylint can't
# find them.
generated-members=Fortran2003.*_List,Fortran2008.*_List

[DESIGN]
# Maximum number of parents for a class (see R0901)
max-parents=9

# Make sure private functions (_my_private_function) are also
# documented, but standard double-underscore functions do not
# need to have a docstring.
no-docstring-rgx=__.*__
16 changes: 15 additions & 1 deletion src/fparser/two/tests/test_fortran2003.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Modified work Copyright (c) 2017-2022 Science and Technology
# Modified work Copyright (c) 2017-2023 Science and Technology
# Facilities Council.
# Original work Copyright (c) 1999-2008 Pearu Peterson
#
Expand Down Expand Up @@ -1902,6 +1902,20 @@ def test_assignment_stmt():
assert isinstance(obj, tcls), repr(obj)
assert str(obj) == "b = a + 1D-8 + 1.1E+3"

# Extra white space around a part-ref
obj = tcls("zdepth(:) = ((gdept_1d(:) ))")
assert isinstance(obj, tcls), repr(obj)
assert str(obj) == "zdepth(:) = ((gdept_1d(:)))"
obj = tcls("zdepth(:) = (( gdept_1d(:) ))")
assert isinstance(obj, tcls), repr(obj)
assert str(obj) == "zdepth(:) = ((gdept_1d(:)))"
obj = tcls("zdepth(:) = ( ( gdept_1d(:) ) )")
assert isinstance(obj, tcls), repr(obj)
assert str(obj) == "zdepth(:) = ((gdept_1d(:)))"
obj = tcls("zdepth(:) = ( gdept_1d(:) ) ")
assert isinstance(obj, tcls), repr(obj)
assert str(obj) == "zdepth(:) = (gdept_1d(:))"


@pytest.mark.usefixtures("fake_symbol_table")
def test_pointer_assignment_stmt(): # R735
Expand Down
35 changes: 16 additions & 19 deletions src/fparser/two/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2018-2020 Science and Technology Facilities Council
# Copyright (c) 2018-2023 Science and Technology Facilities Council.

# All rights reserved.

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

"""Test utils.py which contain base classes to support fparser,
"""Test utils.py which contains base classes to support fparser,
exception handling and ast traversal.
"""

import pytest
from fparser.two.utils import FortranSyntaxError
from fparser.api import get_reader
from fparser.two import Fortran2003, utils


# test BlockBase

Expand All @@ -50,29 +51,27 @@ def test_blockbase_match_names(f2003_create):
as it sets match_names to True.
"""
from fparser.two.Fortran2003 import Derived_Type_Def, Case_Construct

# working named example
reader = get_reader("type abc\nend type abc")
ast = Derived_Type_Def(reader)
ast = Fortran2003.Derived_Type_Def(reader)
assert "TYPE :: abc\nEND TYPE abc" in str(ast)

# case insensitive
reader = get_reader("type abc\nend type ABC")
ast = Derived_Type_Def(reader)
ast = Fortran2003.Derived_Type_Def(reader)
assert "TYPE :: abc\nEND TYPE ABC" in str(ast)

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

# first name required if second name supplied
# switch to using select case as it can trip the exception
reader = get_reader("select case (i)\nend select label")
with pytest.raises(FortranSyntaxError) as excinfo:
ast = Case_Construct(reader)
with pytest.raises(utils.FortranSyntaxError) as excinfo:
ast = Fortran2003.Case_Construct(reader)
assert (
"at line 2\n>>>end select label\nName 'label' has no "
"corresponding starting name"
Expand All @@ -86,28 +85,26 @@ def test_blockbase_match_name_classes(f2003_create):
used when names can appear in multiple places.
"""
from fparser.two.Fortran2003 import If_Construct

# working named example
reader = get_reader("label:if (.true.) then\nendif label")
ast = If_Construct(reader)
ast = Fortran2003.If_Construct(reader)
assert "label:IF (.TRUE.) THEN\nEND IF label" in str(ast)

# case insensitive
reader = get_reader("label:if (.true.) then\nendif LABEL")
ast = If_Construct(reader)
ast = Fortran2003.If_Construct(reader)
assert "label:IF (.TRUE.) THEN\nEND IF LABEL" in str(ast)

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

# first name required if subsequent name supplied
reader = get_reader("if (.true.) then\nendif label")
with pytest.raises(FortranSyntaxError) as excinfo:
ast = If_Construct(reader)
with pytest.raises(utils.FortranSyntaxError) as excinfo:
ast = Fortran2003.If_Construct(reader)
assert (
"at line 2\n>>>endif label\nName 'label' has no corresponding " "starting name"
) in str(excinfo.value)
115 changes: 115 additions & 0 deletions src/fparser/two/tests/utils/test_call_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Copyright (c) 2023 Science and Technology Facilities Council.

# All rights reserved.

# Modifications made as part of the fparser project are distributed
# under the following license:

# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:

# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.

# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.

# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

""" Module containing pytest tests for the fparser2 CallBase class. """

import pytest
from fparser.two import Fortran2003
from fparser.two import utils


@pytest.mark.usefixtures("f2003_create")
def test_call_base_match():
"""Check that parent information is correctly set-up in the
parse tree."""
# Basic match is OK.
assert utils.CallBase.match(
Fortran2003.Procedure_Designator, Fortran2003.Actual_Arg_Spec_List, "ogg()"
)
# Trailing white space is ignored.
assert utils.CallBase.match(
Fortran2003.Procedure_Designator, Fortran2003.Actual_Arg_Spec_List, "ogg() "
)
# String doesn't end with ')'
assert not utils.CallBase.match(
Fortran2003.Procedure_Designator, Fortran2003.Actual_Arg_Spec_List, "ogg"
)
# Missing opening '('
assert not utils.CallBase.match(
Fortran2003.Procedure_Designator, Fortran2003.Actual_Arg_Spec_List, "ogg)"
)
# Missing lhs.
assert not utils.CallBase.match(
Fortran2003.Procedure_Designator, Fortran2003.Actual_Arg_Spec_List, "(ogg)"
)
# Additional, matching parentheses are OK.
assert utils.CallBase.match(
Fortran2003.Procedure_Designator,
Fortran2003.Actual_Arg_Spec_List,
"ogg((nanny) )",
)
# upper_lhs makes no difference when lhs is matched with a class.
assert utils.CallBase.match(
Fortran2003.Procedure_Designator,
Fortran2003.Actual_Arg_Spec_List,
"ogg()",
upper_lhs=True,
)
# upper_lhs is respected when lhs is matched with a str
assert not utils.CallBase.match(
"ogg", Fortran2003.Actual_Arg_Spec_List, "ogg() ", upper_lhs=True
)
assert utils.CallBase.match(
"OGG", Fortran2003.Actual_Arg_Spec_List, "ogg() ", upper_lhs=True
) == ("OGG", None)
# rhs can be matched using a str
assert utils.CallBase.match(
"ogg",
"nanny",
"ogg(nanny)",
)
assert not utils.CallBase.match(
"ogg",
"nanny",
"ogg(granny)",
)
# require_rhs is respected
assert utils.CallBase.match("ogg", "nanny", "ogg(nanny)", require_rhs=False) == (
"ogg",
"nanny",
)
assert utils.CallBase.match("ogg", "nanny", "ogg(nanny)", require_rhs=True) == (
"ogg",
"nanny",
)
assert not utils.CallBase.match("ogg", "nanny", "ogg()", require_rhs=True)


@pytest.mark.usefixtures("f2003_create")
def test_call_base_tostr():
"""Test the tostr() method of CallBase."""
fref = Fortran2003.Function_Reference("gytha(ogg)")
assert fref.tostr() == "gytha(ogg)"
fref = Fortran2003.Function_Reference("weatherwax( )")
assert fref.tostr() == "weatherwax()"
Loading

0 comments on commit 95eb99a

Please sign in to comment.