summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rwxr-xr-xnumpy/f2py/crackfortran.py49
-rw-r--r--numpy/f2py/tests/test_crackfortran.py30
2 files changed, 59 insertions, 20 deletions
diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py
index 984bd642b..2f491ed7e 100755
--- a/numpy/f2py/crackfortran.py
+++ b/numpy/f2py/crackfortran.py
@@ -1526,27 +1526,40 @@ def removespaces(expr):
def markinnerspaces(line):
- l = ''
- f = 0
- cc = '\''
- cb = ''
+ """
+ The function replace all spaces in the input variable line which are
+ surrounded with quotation marks, with the triplet "@_@".
+
+ For instance, for the input "a 'b c'" the function returns "a 'b@_@c'"
+
+ Parameters
+ ----------
+ line : str
+
+ Returns
+ -------
+ str
+
+ """
+ fragment = ''
+ inside = False
+ current_quote = None
+ escaped = ''
for c in line:
- if cb == '\\' and c in ['\\', '\'', '"']:
- l = l + c
- cb = c
+ if escaped == '\\' and c in ['\\', '\'', '"']:
+ fragment += c
+ escaped = c
continue
- if f == 0 and c in ['\'', '"']:
- cc = c
- if c == cc:
- f = f + 1
- elif c == cc:
- f = f - 1
- elif c == ' ' and f == 1:
- l = l + '@_@'
+ if not inside and c in ['\'', '"']:
+ current_quote = c
+ if c == current_quote:
+ inside = not inside
+ elif c == ' ' and inside:
+ fragment += '@_@'
continue
- l = l + c
- cb = c
- return l
+ fragment += c
+ escaped = c # reset to non-backslash
+ return fragment
def updatevars(typespec, selector, attrspec, entitydecl):
diff --git a/numpy/f2py/tests/test_crackfortran.py b/numpy/f2py/tests/test_crackfortran.py
index d26917f0c..140f42cbc 100644
--- a/numpy/f2py/tests/test_crackfortran.py
+++ b/numpy/f2py/tests/test_crackfortran.py
@@ -1,8 +1,8 @@
import numpy as np
-from numpy.testing import assert_array_equal
+from numpy.testing import assert_array_equal, assert_equal
+from numpy.f2py.crackfortran import markinnerspaces
from . import util
from numpy.f2py import crackfortran
-import tempfile
import textwrap
@@ -37,6 +37,7 @@ class TestNoSpace(util.F2PyTest):
assert_array_equal(k, w + 1)
assert self.module.t0(23) == b'2'
+
class TestPublicPrivate():
def test_defaultPrivate(self, tmp_path):
f_path = tmp_path / "mod.f90"
@@ -87,6 +88,7 @@ class TestPublicPrivate():
assert 'private' not in mod['vars']['seta']['attrspec']
assert 'public' in mod['vars']['seta']['attrspec']
+
class TestExternal(util.F2PyTest):
# issue gh-17859: add external attribute support
code = """
@@ -116,6 +118,7 @@ class TestExternal(util.F2PyTest):
r = self.module.external_as_attribute(incr)
assert r == 123
+
class TestCrackFortran(util.F2PyTest):
suffix = '.f90'
@@ -139,3 +142,26 @@ class TestCrackFortran(util.F2PyTest):
def test_gh2848(self):
r = self.module.gh2848(1, 2)
assert r == (1, 2)
+
+
+class TestMarkinnerspaces():
+ # issue #14118: markinnerspaces does not handle multiple quotations
+
+ def test_do_not_touch_normal_spaces(self):
+ test_list = ["a ", " a", "a b c", "'abcdefghij'"]
+ for i in test_list:
+ assert_equal(markinnerspaces(i), i)
+
+ def test_one_relevant_space(self):
+ assert_equal(markinnerspaces("a 'b c' \\\' \\\'"), "a 'b@_@c' \\' \\'")
+ assert_equal(markinnerspaces(r'a "b c" \" \"'), r'a "b@_@c" \" \"')
+
+ def test_ignore_inner_quotes(self):
+ assert_equal(markinnerspaces('a \'b c" " d\' e'),
+ "a 'b@_@c\"@_@\"@_@d' e")
+ assert_equal(markinnerspaces('a "b c\' \' d" e'),
+ "a \"b@_@c'@_@'@_@d\" e")
+
+ def test_multiple_relevant_spaces(self):
+ assert_equal(markinnerspaces("a 'b c' 'd e'"), "a 'b@_@c' 'd@_@e'")
+ assert_equal(markinnerspaces(r'a "b c" "d e"'), r'a "b@_@c" "d@_@e"')