From 215146bf596eab360381415cf5953425c2410da8 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Sun, 28 Jun 2026 13:55:03 +0800 Subject: [PATCH] feat: support save feature for dataset --- legacy/src/lcr_connector/__init__.py | 2 +- legacy/src/lcr_connector/dataset.py | 131 +++++++++++++++++++++++---- legacy/src/lcr_connector/query.py | 2 +- 3 files changed, 116 insertions(+), 19 deletions(-) diff --git a/legacy/src/lcr_connector/__init__.py b/legacy/src/lcr_connector/__init__.py index 98fa7d2..6e7993c 100644 --- a/legacy/src/lcr_connector/__init__.py +++ b/legacy/src/lcr_connector/__init__.py @@ -26,7 +26,7 @@ class AppResolver(enum.StrEnum): """The BFS resolver.""" -@dataclass +@dataclass(frozen=True) class AppConfig: """ The configuration for the app. diff --git a/legacy/src/lcr_connector/dataset.py b/legacy/src/lcr_connector/dataset.py index 35aa1df..41c33fd 100644 --- a/legacy/src/lcr_connector/dataset.py +++ b/legacy/src/lcr_connector/dataset.py @@ -1,9 +1,26 @@ import enum -from typing import Iterable +from dataclasses import dataclass +from typing import Iterable, Iterator from pathlib import Path from .common import LcrConnException +@dataclass(frozen=True) +class DatasetItem: + value: float + """The actual value of this item.""" + str_value: str + """The string form of this value given from original input for re-saving.""" + + def __post_init__(self): + value = self.value + if value <= 0: + raise ValueError(f"Invalid value {value} in dataset") + str_value = self.str_value + if len(str_value) == 0: + raise ValueError(f"Unexpected empty string in dataset item") + + class Dataset: """ A list holding available standard values for resistor, capacitor or inductor. @@ -14,27 +31,34 @@ class Dataset: This list will only contain 100 and 4.7k. """ - __values: tuple[float, ...] + __values: tuple[DatasetItem, ...] """A list of available device gauge values""" - def __init__(self, values: tuple[float, ...]): - # Check redundant parts - valueset = set(values) - if len(valueset) != len(values): - raise LcrConnException(f"Duplicate item in standard value list") - if len(valueset) == 0: + def __init__(self, str_values: Iterable[str]): + # Check string form value one by one + value_items: list[DatasetItem] = [] + value_set: set[float] = set() + for str_value in str_values: + # Try parsing value + value = from_human_readable_value(str_value) + # Check and update set + if value in value_set: + raise LcrConnException( + f"Duplicate item {str_value} in standard value list" + ) + else: + value_set.add(value) + # Add into result + value_items.append(DatasetItem(value, str_value)) + # Check empty case + if len(value_items) == 0: raise LcrConnException(f"Empty standard value list is not allowed") # Ok, assign it - self.__values = values + self.__values = tuple(value_items) @staticmethod def from_iterable(stringfied_values: Iterable[str]) -> "Dataset": - return Dataset( - tuple( - from_human_readable_value(stringfied_value) - for stringfied_value in stringfied_values - ) - ) + return Dataset(stringfied_values) @staticmethod def from_text(text: str) -> "Dataset": @@ -48,14 +72,27 @@ class Dataset: legal_lines = filter(lambda line: line != "", (line.strip() for line in f)) return Dataset.from_iterable(legal_lines) + def __save(self) -> Iterator[str]: + return map(lambda i: i.str_value, self.__values) + + def save_iterator(self) -> Iterator[str]: + return self.__save() + + def save_text(self) -> str: + return "\n".join(self.__save()) + + def save_file(self, filename: Path) -> None: + with open(filename, "w", encoding="utf-8") as f: + f.write(self.save_text()) + @property - def values(self) -> tuple[float, ...]: + def values(self) -> Iterator[float]: """ Get the available standard values :return: A tuple of available standard values """ - return self.__values + return map(lambda i: i.value, self.__values) class DatasetCollection: @@ -79,6 +116,14 @@ class DatasetCollection: def from_iterable( resistor: Iterable[str], capacitor: Iterable[str], inductor: Iterable[str] ) -> "DatasetCollection": + """ + Load the standard values for resistor, capacitor and inductor respectively from iterables. + + :param resistor: The iterable to load available standard values for resistor + :param capacitor: The iterable to load available standard values for capacitor + :param inductor: The iterable to load available standard values for inductor + :return: The built dataset collection + """ return DatasetCollection( Dataset.from_iterable(resistor), Dataset.from_iterable(capacitor), @@ -87,6 +132,14 @@ class DatasetCollection: @staticmethod def from_text(resistor: str, capacitor: str, inductor: str) -> "DatasetCollection": + """ + Load the standard values for resistor, capacitor and inductor respectively from strings. + + :param resistor: The string to load available standard values for resistor + :param capacitor: The string to load available standard values for capacitor + :param inductor: The string to load available standard values for inductor + :return: The built dataset collection + """ return DatasetCollection( Dataset.from_text(resistor), Dataset.from_text(capacitor), @@ -97,12 +150,56 @@ class DatasetCollection: def from_file( resistor: Path, capacitor: Path, inductor: Path ) -> "DatasetCollection": + """ + Load the standard values for resistor, capacitor and inductor respectively from files. + + :param resistor: The file to load available standard values for resistor + :param capacitor: The file to load available standard values for capacitor + :param inductor: The file to load available standard values for inductor + :return: The built dataset collection + """ return DatasetCollection( Dataset.from_file(resistor), Dataset.from_file(capacitor), Dataset.from_file(inductor), ) + def save_iterator(self) -> tuple[Iterator[str], Iterator[str], Iterator[str]]: + """ + Get the iterator of available standard values for resistor, capacitor and inductor respectively. + + :return: A tuple of iterators of available standard values for resistor, capacitor and inductor respectively. + """ + return ( + self.__resistor.save_iterator(), + self.__capacitor.save_iterator(), + self.__inductor.save_iterator(), + ) + + def save_text(self) -> tuple[str, str, str]: + """ + Get the string form of available standard values for resistor, capacitor and inductor respectively. + + :return: A tuple of strings of available standard values for resistor, capacitor and inductor respectively. + """ + return ( + self.__resistor.save_text(), + self.__capacitor.save_text(), + self.__inductor.save_text(), + ) + + def save_file(self, resistor: Path, capacitor: Path, inductor: Path) -> None: + """ + Save the available standard values for resistor, capacitor and inductor respectively to files. + + :param resistor: The file to save available standard values for resistor + :param capacitor: The file to save available standard values for capacitor + :param inductor: The file to save available standard values for inductor + """ + self.__resistor.save_file(resistor) + self.__capacitor.save_file(capacitor) + self.__inductor.save_file(inductor) + @property def resistor_values(self) -> Dataset: """ diff --git a/legacy/src/lcr_connector/query.py b/legacy/src/lcr_connector/query.py index 0f676a0..2be23b7 100644 --- a/legacy/src/lcr_connector/query.py +++ b/legacy/src/lcr_connector/query.py @@ -20,7 +20,7 @@ MAX_RESPONSE_CNT: int = 50 """The maximum count for the response item count passed in request.""" -@dataclass +@dataclass(frozen=True) class Request: """ All request infomation for the resolver.