|
68 | 68 | # Patterns: properties |
69 | 69 | VERSION_PATTERN: Final[Pattern[bytes]] = compile(rb"(\d\.\d)") |
70 | 70 | PURE_INT_PATTERN: Final[Pattern[str]] = compile(r"[-+]?\d+") |
71 | | -PURE_FLOAT_PATTERN: Final[Pattern[str]] = compile(r"[-+]?(?:\d+\.\d*|\.\d+)") |
| 71 | +PURE_FLOAT_PATTERN: Final[Pattern[str]] = compile( |
| 72 | + r"[-+]?(?:\d+\.\d*|\.\d+)(?:[eE][-+]?\d+)?" |
| 73 | +) |
72 | 74 | TEXT_PATTERN: Final[Pattern[bytes]] = compile(rb'"(.*?)"') |
73 | 75 | VARIANT_PATTERN: Final[Pattern[bytes]] = compile(rb"VAR\s+(.*?)=(.*)") |
74 | 76 | AXIS_X_PATTERN: Final[Pattern[bytes]] = compile(rb"SSTX\s+(.*)") |
@@ -219,17 +221,12 @@ def from_bytestream(cls, stream: BytesReadable, line: bytes) -> "Self": |
219 | 221 | def value_or_text(self) -> str | float: |
220 | 222 | return self.value if not isnan(self.value) else self.text |
221 | 223 |
|
222 | | - def as_number( |
223 | | - self, |
224 | | - raise_on_nan: bool = True, |
225 | | - int_pattern: Pattern[str] = PURE_INT_PATTERN, |
226 | | - float_pattern: Pattern[str] = PURE_FLOAT_PATTERN, |
227 | | - ) -> int | float | bool: |
| 224 | + def as_number(self, raise_on_nan: bool = True) -> int | float | bool: |
228 | 225 | if isnan(self.value): |
229 | 226 | text: str = self.text |
230 | | - if int_pattern.fullmatch(text): |
| 227 | + if PURE_INT_PATTERN.fullmatch(text): |
231 | 228 | return int(text) |
232 | | - elif float_pattern.fullmatch(text): |
| 229 | + elif PURE_FLOAT_PATTERN.fullmatch(text): |
233 | 230 | return float(text) |
234 | 231 | elif text == "true": |
235 | 232 | return True |
@@ -1415,48 +1412,46 @@ def shallow_transfer( |
1415 | 1412 | ) |
1416 | 1413 |
|
1417 | 1414 |
|
| 1415 | +@dataclass |
1418 | 1416 | class SystemConstants: |
1419 | | - __constants__: dict[str, int | float | bool] |
1420 | | - |
1421 | | - def __init__(self) -> None: |
1422 | | - self.__constants__ = {} |
| 1417 | + __constants__: dict[str, int | float | bool] = field( |
| 1418 | + default_factory=dict |
| 1419 | + ) |
1423 | 1420 |
|
1424 | 1421 | def __getattr__(self, name: str) -> int | float | bool: |
1425 | | - value: int | float | bool | None = self.__constants__.get(name) |
| 1422 | + value: Optional[int | float | bool] = self.__constants__.get(name) |
1426 | 1423 | if value is not None: |
1427 | 1424 | return value |
1428 | 1425 | warnings.warn( |
1429 | | - f"{name}라는 SYSTEM_CONSTANT가 없습니다. 대신 0을 반환합니다." |
| 1426 | + f"No System Constant found with name: {name}. Returning 0." |
1430 | 1427 | ) |
1431 | 1428 | return 0 |
1432 | 1429 |
|
1433 | | - def from_a2l(self, a2l_filepath: str) -> int: |
| 1430 | + def from_a2l(self, a2l_filepath: FileDescriptorOrPath) -> int: |
1434 | 1431 | total_constants: int = 0 |
1435 | | - pattern = compile(r'SYSTEM_CONSTANT\s+"(\w+)"\s+"([^"]+)"') |
1436 | | - with open(a2l_filepath, "r") as f: |
| 1432 | + pattern: Pattern[bytes] = compile( |
| 1433 | + rb'SYSTEM_CONSTANT\s+"(\w+)"\s+"([^"]+)"' |
| 1434 | + ) |
| 1435 | + with open(a2l_filepath, "rb") as f: |
1437 | 1436 | for line in f: |
1438 | | - match = pattern.search(line.strip()) |
1439 | | - if match: |
1440 | | - value: float | int | str | bool |
1441 | | - key, value = match.groups() |
1442 | | - value = str(value).strip('"') |
1443 | | - if "." in value: |
1444 | | - try: |
1445 | | - value = float(value) |
1446 | | - except ValueError: |
1447 | | - pass |
1448 | | - else: |
1449 | | - try: |
1450 | | - value = int(value) |
1451 | | - except ValueError: |
1452 | | - lower_value = value.lower() |
1453 | | - if lower_value == "true": |
1454 | | - value = True |
1455 | | - elif lower_value == "false": |
1456 | | - value = False |
1457 | | - if isinstance(value, (int, float, bool)): |
1458 | | - self.__constants__[key] = value |
1459 | | - total_constants += 1 |
| 1437 | + match: Optional[Match[bytes]] = pattern.search(line.strip()) |
| 1438 | + if match is None: |
| 1439 | + continue |
| 1440 | + bname, bvalue = match.groups() |
| 1441 | + name: str = bname.decode(errors="replace") |
| 1442 | + value: str = bvalue.decode(errors="replace") |
| 1443 | + if PURE_INT_PATTERN.fullmatch(value): |
| 1444 | + self.__constants__[name] = int(value) |
| 1445 | + elif PURE_FLOAT_PATTERN.fullmatch(value): |
| 1446 | + self.__constants__[name] = float(value) |
| 1447 | + elif value == "true": |
| 1448 | + self.__constants__[name] = True |
| 1449 | + elif value == "false": |
| 1450 | + self.__constants__[name] = False |
| 1451 | + else: |
| 1452 | + warnings.warn(f"Invalid SYSTEM_CONSTANT {name}: {value}") |
| 1453 | + continue |
| 1454 | + total_constants += 1 |
1460 | 1455 | return total_constants |
1461 | 1456 |
|
1462 | 1457 |
|
@@ -1529,3 +1524,6 @@ def _parse_name_without_keyword(line: bytes) -> str: |
1529 | 1524 |
|
1530 | 1525 | def _parse_values_without_keyword(line: bytes) -> Iterable[float]: |
1531 | 1526 | return (float(value) for value in line.strip().split()[1:]) |
| 1527 | + |
| 1528 | + |
| 1529 | +SC = SystemConstants() |
0 commit comments