Skip to content

Type Reader

Types loads a type library (LV/MV cable and fuse types plus name aliases) from an Excel workbook, and resolves them by Name or alias.

python
from pyptp.type_reader import Types

types = Types()  # bundled workbook

cable = types.get_lv_cable("4* 50 VMvK/Alk")
fuse = types.get_lv_fuse("Voorbeeld 35 A")

Workbook resolution

The workbook path is resolved in this order:

  1. The path argument: Types("C:/data/my_types.xlsx")
  2. The PYPTP_TYPES_EXCEL environment variable
  3. The bundled types.xlsx shipped with the package

Expected sheet layout

Types reads the sheets Cable, Fuse, Cable alias and Fuse alias.

RowContent
0Column headers (Name, ShortName, Unom, ...)
1 (optional)Unit row (kV, MVA, ...)
2+Data rows

The unit row is detected by content, not position: a first row whose Name (or ShortName) cell is empty is treated as a unit row and skipped. Workbooks without a unit row work as-is, with the first data row preserved.

Custom column names

If your workbook uses different column headers, map them with column_renames. Keys select the loader ("lv_cable", "mv_cable", "lv_fuse", "mv_fuse") and values map source Excel header → expected header:

python
types = Types(
    "C:/data/my_types.xlsx",
    column_renames={
        "lv_cable": {"R_ohm": "R_c", "Naam": "Name"},
        "mv_fuse": {"Naam": "Name"},
    },
)

LV and MV cable types are read from the same Cable sheet, which is why renames are keyed per loader rather than per sheet.

Entries extend the built-in defaults (such as Shortname → ShortName), so those keep working unless you explicitly override them. Unknown keys are ignored with a warning.

Extending Types

For type categories Types does not load natively yet (transformers, coils, ...), subclass it and use the public helpers read_type_sheet and clean_row_dict:

python
from pyptp.elements.mv.transformer import TransformerMV
from pyptp.type_reader import Types, clean_row_dict, read_type_sheet


class CustomTypes(Types):
    def __init__(self, path: str | None = None) -> None:
        super().__init__(path)
        self._trafo_by_name: dict[str, TransformerMV.TransformerType] = {}
        for row in read_type_sheet(self._path, sheet_name="Trafo"):
            row_dict = clean_row_dict(row)
            name = str(row_dict.get("Name", "")).strip()
            if not name:
                continue
            self._trafo_by_name[name] = TransformerMV.TransformerType.deserialize(row_dict)

    def get_trafo(self, name: str) -> TransformerMV.TransformerType | None:
        return self._trafo_by_name.get(str(name).strip())

read_type_sheet applies the same unit-row detection as the built-in loaders and accepts a rename mapping; clean_row_dict drops empty cells so dataclass defaults apply.