Skip to content
Open
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
20 changes: 17 additions & 3 deletions epinterface/sbem/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from typing import Annotated

from pydantic import BaseModel, BeforeValidator, Field
from pydantic import BaseModel, BeforeValidator, Field, field_validator

from epinterface.sbem.annotations import (
nan_to_none_or_str,
Expand All @@ -11,16 +11,30 @@
)


def _ascii_safe(s: str) -> str:
"""Return an ascii-only string suitable for idf names."""
return s.encode("ascii", "ignore").decode("ascii")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it definitely ascii and not, say, utf-8 or some such that we want?

What does the ignore arg do?



class NamedObject(BaseModel):
"""A Named object (with a name field)."""

Name: str = Field(..., title="Name of the object used in referencing.")

@field_validator("Name", mode="before")
@classmethod
def sanitize_name(cls, v: str) -> str:
"""Sanitize name to ascii-only, replacing spaces and commas with underscores."""
if not isinstance(v, str):
return v
sanitized = _ascii_safe(v).replace(" ", "_").replace(",", "_")
return sanitized

# TODO: this is potentially a confusing footgun, but it's probably necessary.
@property
def safe_name(self) -> str:
"""Get the safe name of the object."""
return self.Name.replace(" ", "_").replace(",", "_")
"""Get the safe name of the object (same as Name after validation)."""
return self.Name


NanStr = Annotated[str | None, BeforeValidator(nan_to_none_or_str)]
Expand Down
10 changes: 4 additions & 6 deletions epinterface/sbem/components/envelope.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ def add_to_idf(self, idf: IDF) -> IDF:
IDF: The updated IDF object.
"""
glazing_mat = SimpleGlazingMaterial(
Name=self.Name,
Name=self.safe_name,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have this change? Shouldn't Name be safe by default now?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, see below comment. These two were using Name not safe_name, so I just updated to safe_name to stay in convention with the Name of the other objects. We can poentially remove safe_name altogether

UFactor=self.UValue,
Solar_Heat_Gain_Coefficient=self.SHGF,
Visible_Transmittance=self.TVis,
)

construction = Construction(
name=self.Name,
name=self.safe_name,
layers=[glazing_mat],
)

Expand Down Expand Up @@ -127,11 +127,9 @@ def add_infiltration_to_idf_zone(
return idf

infiltration_schedule_name = (
f"{target_zone_or_zone_list_name}_{self.safe_name}_INFILTRATION_Schedule"
)
infiltration_name = (
f"{target_zone_or_zone_list_name}_{self.safe_name}_INFILTRATION"
f"{target_zone_or_zone_list_name}_{self.Name}_INFILTRATION_Schedule"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact, can we get rid of safe_name entirely now?

Are there negative implications of the renaming at the instance level?

My main fear is with references breaking in the IDF etc

Let's maybe review together in person at some pt

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I originally removed safe_name from everywhere and just kept name in place there, since that class method should take care of the sanitization, but was worried it may break some logic so opted for the less invasive change for now. Let's discuss though!

)
infiltration_name = f"{target_zone_or_zone_list_name}_{self.Name}_INFILTRATION"
schedule = Schedule.constant_schedule(
value=1, Name=infiltration_schedule_name, Type="Fraction"
)
Expand Down
Loading