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

#308: Improve file float formatting #417

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d2ab0db
#308: Pass SerializerConfig to the serialization function of PolyObje…
priscavdsluis Nov 14, 2022
287c0e2
autoformat: isort & black
priscavdsluis Nov 14, 2022
15e1b30
#308: Pass SerializerConfig to the serialization function of a point
priscavdsluis Nov 14, 2022
c3955b9
autoformat: isort & black
priscavdsluis Nov 14, 2022
4627f88
#308: Refactor serialize_point function.
priscavdsluis Nov 14, 2022
a3d5799
autoformat: isort & black
priscavdsluis Nov 14, 2022
80f3ff4
#308: Add formatting for poly file
priscavdsluis Nov 14, 2022
e090c32
autoformat: isort & black
priscavdsluis Nov 14, 2022
87a483a
#308: Add configuration to test cases.
priscavdsluis Nov 14, 2022
b312966
autoformat: isort & black
priscavdsluis Nov 14, 2022
9cd5e96
Merge branch 'feat/308-improve-bc-file-formatting' into feat/308-impr…
priscavdsluis Nov 14, 2022
41bab71
#308: Add SerializerConfig as to _get_serializer callable
priscavdsluis Nov 14, 2022
4c0c353
autoformat: isort & black
priscavdsluis Nov 14, 2022
de5de22
#308: Add formatting for xyz file
priscavdsluis Nov 14, 2022
79a19da
autoformat: isort & black
priscavdsluis Nov 14, 2022
1e9e3ee
#308: Add extra test case
priscavdsluis Nov 14, 2022
25f4b1f
#308: Add formatting for dimr file
priscavdsluis Nov 14, 2022
d38d960
autoformat: isort & black
priscavdsluis Nov 14, 2022
9fc8418
#308: Add formatting for bui file
priscavdsluis Nov 15, 2022
c7c0d07
autoformat: isort & black
priscavdsluis Nov 15, 2022
8c4aea6
Merge branch 'feat/308-improve-bc-file-formatting' into feat/308-impr…
priscavdsluis Nov 16, 2022
efc3711
#308: Add docs.
priscavdsluis Nov 16, 2022
ffec907
autoformat: isort & black
priscavdsluis Nov 16, 2022
c7bbbfc
#308: Add formatting for rr node topology file
priscavdsluis Nov 16, 2022
54caffa
#308: Fix test
priscavdsluis Nov 17, 2022
1f3dbfe
autoformat: isort & black
priscavdsluis Nov 17, 2022
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/basemodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,7 @@ def _serialize(self, data: dict) -> None:
return

path.parent.mkdir(parents=True, exist_ok=True)
self._get_serializer()(path, data)
self._get_serializer()(path, data, self.serializer_config)

def dict(self, *args, **kwargs):
kwargs["exclude"] = self._exclude_fields()
Expand Down Expand Up @@ -1114,7 +1114,7 @@ def _ext(cls) -> str:
return ".test"

@abstractclassmethod
def _get_serializer(cls) -> Callable[[Path, Dict], None]:
def _get_serializer(cls) -> Callable[[Path, Dict, SerializerConfig], None]:
return DummySerializer.serialize

@abstractclassmethod
Expand Down
2 changes: 1 addition & 1 deletion hydrolib/core/io/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def parse(filepath: Path) -> Dict:

class DummySerializer:
@staticmethod
def serialize(path: Path, data: Dict) -> None:
def serialize(path: Path, data: Dict, config) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
with path.open("w") as f:
f.write(str(data))
2 changes: 1 addition & 1 deletion hydrolib/core/io/dflowfm/polyfile/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def _serialize(self, _: dict) -> None:
from .serializer import write_polyfile

# We skip the passed dict for a better one.
write_polyfile(self._resolved_filepath, self.objects)
write_polyfile(self._resolved_filepath, self.objects, self.serializer_config)

@classmethod
def _ext(cls) -> str:
Expand Down
48 changes: 38 additions & 10 deletions hydrolib/core/io/dflowfm/polyfile/serializer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from itertools import chain
from pathlib import Path
from typing import Dict, Iterable, Optional, Sequence
from typing import Generator, Iterable, Optional, Sequence

from hydrolib.core.basemodel import SerializerConfig
from hydrolib.core.io.dflowfm.polyfile.models import (
Description,
Metadata,
Expand Down Expand Up @@ -40,41 +41,68 @@ def serialize_metadata(metadata: Metadata) -> Iterable[str]:
return [metadata.name, f"{metadata.n_rows} {metadata.n_columns}"]

@staticmethod
def serialize_point(point: Point) -> str:
def serialize_point(point: Point, config: SerializerConfig) -> str:
"""Serialize this Point to a string which can be used within a polyfile.

the point data is indented with 4 spaces, and the individual values are
separated by 4 spaces as well.

Args:
point (Point): The point to serialize.
config (SerializerConfig): The serialization configuration.

Returns:
str: The serialised equivalent of this Point
"""
z_val = f"{point.z} " if point.z is not None else ""
data_vals = " ".join(str(v) for v in point.data)
return f" {point.x} {point.y} {z_val}{data_vals}".rstrip()
space = 4 * " "
format = lambda v: f"{v:{config.float_format}}"
return space + space.join(
format(v) for v in Serializer._get_point_values(point)
)

@staticmethod
def _get_point_values(point: Point) -> Generator[float, None, None]:
yield point.x
yield point.y
if point.z:
yield point.z
for value in point.data:
yield value

@staticmethod
def serialize_poly_object(obj: PolyObject) -> Iterable[str]:
def serialize_poly_object(
obj: PolyObject, config: SerializerConfig
) -> Iterable[str]:
"""Serialize this PolyObject to a string which can be used within a polyfile.

Args:
obj (PolyObject): The poly object to serializer.
config (SerializerConfig): The serialization configuration.

Returns:
str: The serialised equivalent of this Point
str: The serialised equivalent of this PolyObject
"""

description = Serializer.serialize_description(obj.description)
metadata = Serializer.serialize_metadata(obj.metadata)
points = map(Serializer.serialize_point, obj.points)
points = [Serializer.serialize_point(obj, config) for obj in obj.points]
return chain(description, metadata, points)


def write_polyfile(path: Path, data: Sequence[PolyObject]) -> None:
def write_polyfile(
path: Path, data: Sequence[PolyObject], config: SerializerConfig
) -> None:
"""Write the data to a new file at path

Args:
path (Path): The path to write the data to
data (Sequence[PolyObject]): The poly objects to write
config (SerializerConfig): The serialization configuration.
"""
serialized_data = chain.from_iterable(map(Serializer.serialize_poly_object, data))
serialized_poly_objects = [
Serializer.serialize_poly_object(poly_object, config) for poly_object in data
]
serialized_data = chain.from_iterable(serialized_poly_objects)

path.parent.mkdir(parents=True, exist_ok=True)

Expand Down
7 changes: 4 additions & 3 deletions hydrolib/core/io/dflowfm/xyz/models.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from typing import Callable, List, Optional
from pathlib import Path
from typing import Callable, Dict, List, Optional

from pydantic import Field

from hydrolib.core.basemodel import BaseModel, ParsableFileModel
from hydrolib.core.basemodel import BaseModel, ParsableFileModel, SerializerConfig

from .parser import XYZParser
from .serializer import XYZSerializer
Expand Down Expand Up @@ -54,7 +55,7 @@ def _filename(cls) -> str:
return "sample"

@classmethod
def _get_serializer(cls) -> Callable:
def _get_serializer(cls) -> Callable[[Path, Dict, SerializerConfig], None]:
return XYZSerializer.serialize

@classmethod
Expand Down
31 changes: 27 additions & 4 deletions hydrolib/core/io/dflowfm/xyz/serializer.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
from pathlib import Path
from typing import Dict
from typing import Dict, Generator

from hydrolib.core.basemodel import SerializerConfig


class XYZSerializer:
@staticmethod
def serialize(path: Path, data: Dict) -> None:
def serialize(path: Path, data: Dict, config: SerializerConfig) -> None:
"""
Serializes the XYZ data to the file at the specified path.

Attributes:
path (Path): The path to the destination file.
data (Dict): The data to be serialized.
config (SerializerConfig): The serialization configuration.
"""
path.parent.mkdir(parents=True, exist_ok=True)

space = 1 * " "
format_float = lambda x: f"{x:{config.float_format}}"

with path.open("w") as f:
for point in data["points"]:
geometry: str = space.join(
[format_float(p) for p in XYZSerializer._get_point_values(point)]
)
if point.comment:
f.write(f"{point.x} {point.y} {point.z} # {point.comment}\n")
f.write(f"{geometry} # {point.comment}\n")
else:
f.write(f"{point.x} {point.y} {point.z}\n")
f.write(f"{geometry}\n")

@staticmethod
def _get_point_values(point) -> Generator[float, None, None]:
yield point.x
yield point.y
yield point.z
11 changes: 8 additions & 3 deletions hydrolib/core/io/dimr/models.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
from abc import ABC, abstractclassmethod
from datetime import datetime
from pathlib import Path
from typing import Callable, List, Literal, Optional, Type, Union
from typing import Callable, Dict, List, Literal, Optional, Type, Union

from pydantic import Field, validator

from hydrolib.core import __version__
from hydrolib.core.basemodel import BaseModel, FileModel, ParsableFileModel
from hydrolib.core.basemodel import (
BaseModel,
FileModel,
ParsableFileModel,
SerializerConfig,
)
from hydrolib.core.io.dflowfm.mdu.models import FMModel
from hydrolib.core.io.dimr.parser import DIMRParser
from hydrolib.core.io.dimr.serializer import DIMRSerializer
Expand Down Expand Up @@ -330,7 +335,7 @@ def _filename(cls) -> str:
return "dimr_config"

@classmethod
def _get_serializer(cls) -> Callable:
def _get_serializer(cls) -> Callable[[Path, Dict, SerializerConfig], None]:
return DIMRSerializer.serialize

@classmethod
Expand Down
15 changes: 10 additions & 5 deletions hydrolib/core/io/dimr/serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,21 @@

from lxml import etree as e

from hydrolib.core.basemodel import SerializerConfig


class DIMRSerializer:
"""A serializer for DIMR files."""

@staticmethod
def serialize(path: Path, data: dict):
def serialize(path: Path, data: dict, config: SerializerConfig):
"""
Serializes the DIMR data to the file at the specified path.

Attributes:
path (Path): The path to the destination file.
data (Dict): The data to be serialized.
config (SerializerConfig): The serialization configuration.
"""

path.parent.mkdir(parents=True, exist_ok=True)
Expand All @@ -33,7 +36,7 @@ def serialize(path: Path, data: dict):
attrib=attrib,
nsmap=namespaces,
)
DIMRSerializer._build_tree(root, data)
DIMRSerializer._build_tree(root, data, config)

to_string = minidom.parseString(e.tostring(root))
xml = to_string.toprettyxml(indent=" ", encoding="utf-8")
Expand All @@ -42,25 +45,27 @@ def serialize(path: Path, data: dict):
f.write(xml)

@staticmethod
def _build_tree(root, data: dict):
def _build_tree(root, data: dict, config: SerializerConfig):
name = data.pop("name", None)
if name:
root.set("name", name)

for key, val in data.items():
if isinstance(val, dict):
c = e.Element(key)
DIMRSerializer._build_tree(c, val)
DIMRSerializer._build_tree(c, val, config)
root.append(c)
elif isinstance(val, List):
for item in val:
c = e.Element(key)
DIMRSerializer._build_tree(c, item)
DIMRSerializer._build_tree(c, item, config)
root.append(c)
else:
c = e.Element(key)
if isinstance(val, datetime):
c.text = val.isoformat(sep="T", timespec="auto")
elif isinstance(val, float):
c.text = f"{val:{config.float_format}}"
else:
c.text = str(val)
root.append(c)
5 changes: 3 additions & 2 deletions hydrolib/core/io/rr/meteo/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from datetime import datetime, timedelta
from pathlib import Path
from typing import Callable, Dict, List, Tuple

from hydrolib.core.basemodel import BaseModel, ParsableFileModel
from hydrolib.core.basemodel import BaseModel, ParsableFileModel, SerializerConfig

from .parser import BuiParser
from .serializer import write_bui_file
Expand Down Expand Up @@ -64,7 +65,7 @@ def _ext(cls) -> str:
return ".bui"

@classmethod
def _get_serializer(cls) -> Callable:
def _get_serializer(cls) -> Callable[[Path, Dict, SerializerConfig], None]:
return write_bui_file

@classmethod
Expand Down
Loading