Skip to content
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

Add support for station names surrounded by double quotes #538

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
4 changes: 2 additions & 2 deletions hydrolib/core/dflowfm/xyn/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ def _validate_name(cls, value):
if str_is_empty_or_none(value):
raise ValueError("Name cannot be empty.")

if "'" in value:
if "'" in value or '"' in value:
raise ValueError(
"Name cannot contain single quotes except at the start and end."
"Name cannot contain single or double quotes except at the start and end."
)

return value
Expand Down
14 changes: 11 additions & 3 deletions hydrolib/core/dflowfm/xyn/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,20 @@ def parse(filepath: Path) -> Dict:
Raises:
ValueError: if a line in the file cannot be parsed
or if the name contains whitespace while not surrounded with
single quotes.
single or double quotes.
"""

def is_surrounded_by_quotes(name: str) -> bool:
def is_surrounded_by_single_quotes(name: str) -> bool:
return name.startswith("'") and name.endswith("'")

def is_surrounded_by_double_quotes(name: str) -> bool:
return name.startswith('"') and name.endswith('"')

def is_surrounded_by_quotes(name: str) -> bool:
return is_surrounded_by_single_quotes(
name
) or is_surrounded_by_double_quotes(name)

def may_contain_whitespace(name: str) -> bool:
return is_surrounded_by_quotes(name)

Expand Down Expand Up @@ -58,7 +66,7 @@ def contains_whitespace_while_not_allowed(name: str) -> bool:

if contains_whitespace_while_not_allowed(n):
raise ValueError(
f"Error parsing XYN file '{filepath}', line {linenr+1}. Name `{n}` contains whitespace, so should be enclosed in single quotes."
f"Error parsing XYN file '{filepath}', line {linenr+1}. Name `{n}` contains whitespace, so should be enclosed in quotes."
)

if is_surrounded_by_quotes(n):
Expand Down
39 changes: 30 additions & 9 deletions tests/dflowfm/test_xyn.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def test_parse_xyn_file(self):
file_content = """
*This is a comment and should not be parsed.
1.1 2.2 'ObservationPoint_2D_01'
3.3 4.4 'ObservationPoint_2D_02'
3.3 4.4 "ObservationPoint_2D_02"
"""

expected_result = {
Expand All @@ -31,30 +31,50 @@ def test_parse_xyn_file(self):

with create_temp_file(file_content, "test.xyn") as xyn_file:
parsed_contents = XYNParser.parse(xyn_file)
assert expected_result == parsed_contents
assert expected_result == parsed_contents

def test_parse_xyn_file_with_quoted_name_removes_quotes(self):
def test_parse_xyn_file_with_single_quoted_name_removes_quotes_and_keeps_whitespace(
self,
):
file_content = """
1.1 2.2 'ObservationPoint_2D_01'
1.1 2.2 'ObservationPoint 2D 01'
"""

expected_result = {
"points": [
{"x": "1.1", "y": "2.2", "n": "ObservationPoint_2D_01"},
{"x": "1.1", "y": "2.2", "n": "ObservationPoint 2D 01"},
]
}

with create_temp_file(file_content, "test.xyn") as xyn_file:
parsed_contents = XYNParser.parse(xyn_file)
assert expected_result == parsed_contents

def test_parse_xyn_file_with_double_quoted_name_removes_quotes_and_keeps_whitespace(
self,
):
file_content = """
1.1 2.2 "ObservationPoint 2D 01"
"""

expected_result = {
"points": [
{"x": "1.1", "y": "2.2", "n": "ObservationPoint 2D 01"},
]
}

with create_temp_file(file_content, "test.xyn") as xyn_file:
parsed_contents = XYNParser.parse(xyn_file)
assert expected_result == parsed_contents

assert expected_result == parsed_contents

def test_parse_xyn_file_with_too_many_columns_raises_error(self):
name = "'ObservationPoint_2D_01' This is too much content"
file_content = f"1.1 2.2 {name}"

with pytest.raises(ValueError) as error:
with create_temp_file(file_content, "test.xyn") as xyn_file:
expected_message = f"Error parsing XYN file '{xyn_file}', line 1. Name `{name}` contains whitespace, so should be enclosed in single quotes."
expected_message = f"Error parsing XYN file '{xyn_file}', line 1. Name `{name}` contains whitespace, so should be enclosed in quotes."
_ = XYNParser.parse(xyn_file)

assert expected_message in str(error.value)
Expand All @@ -79,7 +99,7 @@ def test_serialize_xyn_point(self):

with open(xyn_file) as file:
file_content = file.readlines()
assert file_content == expected_file_content
assert file_content == expected_file_content


class TestXYNModel:
Expand Down Expand Up @@ -131,7 +151,8 @@ class TestXYNPoint:
@pytest.mark.parametrize(
("name"),
[
pytest.param("'nameWithQuote", id="Name with quote"),
pytest.param("nameWith'SingleQuote", id="Name with single quote"),
pytest.param('nameWith"DoubleQuote', id="Name with double quote"),
pytest.param(None, id="None value"),
pytest.param("", id="Empty string"),
pytest.param(" ", id="Whitespace only"),
Expand Down