|
52 | 52 | from collections.abc import Iterable, Iterator |
53 | 53 | from dataclasses import dataclass, field |
54 | 54 | from datetime import timedelta |
55 | | -from typing import IO, Any, NoReturn, Union |
| 55 | +from typing import IO, Any, ClassVar, NoReturn, Union |
56 | 56 | from warnings import warn |
57 | 57 |
|
58 | 58 | from ._helpers import JSONDateEncoder, open_or_return |
@@ -401,6 +401,7 @@ def add( |
401 | 401 | super().__setitem__(name, entry) |
402 | 402 |
|
403 | 403 |
|
| 404 | +@dataclass |
404 | 405 | class Configuration: |
405 | 406 | r"""Holds a parsed configuration. |
406 | 407 |
|
@@ -457,29 +458,20 @@ class Configuration: |
457 | 458 |
|
458 | 459 | """ # noqa |
459 | 460 |
|
460 | | - lines: list[str] |
461 | | - entries: dict[str, Entry] |
462 | | - path: str | None |
463 | | - |
464 | | - _parameter_re = re.compile( |
465 | | - r"^(?P<name>[a-z_.]+)(?: +(?!=)| *= *)(?P<value>.*?)" |
466 | | - "[\\s\t]*" |
467 | | - r"(?P<comment>#.*)?$" |
468 | | - ) |
469 | | - |
470 | 461 | # Internally, lines property contains an updated list of all comments and |
471 | 462 | # entries serialized. When adding a setting or updating an existing one, |
472 | 463 | # the serialized line is updated accordingly. This allows to keep comments |
473 | 464 | # and serialize only what's needed. Other lines are just written as-is. |
474 | 465 |
|
475 | | - def __init__(self, path: str | None = None) -> None: |
476 | | - self.__dict__.update( |
477 | | - dict( |
478 | | - lines=[], |
479 | | - entries=OrderedDict(), |
480 | | - path=path, |
481 | | - ) |
482 | | - ) |
| 466 | + path: str | None = None |
| 467 | + lines: list[str] = field(default_factory=list, init=False) |
| 468 | + entries: dict[str, Entry] = field(default_factory=OrderedDict, init=False) |
| 469 | + |
| 470 | + _parameter_re: ClassVar = re.compile( |
| 471 | + r"^(?P<name>[a-z_.]+)(?: +(?!=)| *= *)(?P<value>.*?)" |
| 472 | + "[\\s\t]*" |
| 473 | + r"(?P<comment>#.*)?$" |
| 474 | + ) |
483 | 475 |
|
484 | 476 | def parse(self, fo: Iterable[str]) -> Iterator[tuple[pathlib.Path, IncludeType]]: |
485 | 477 | for raw_line in fo: |
@@ -552,13 +544,13 @@ def __iadd__(self, other: Any) -> Configuration: |
552 | 544 |
|
553 | 545 | def __getattr__(self, name: str) -> Value: |
554 | 546 | try: |
555 | | - return self[name] |
| 547 | + return self.entries[name].value |
556 | 548 | except KeyError: |
557 | 549 | raise AttributeError(name) |
558 | 550 |
|
559 | 551 | def __setattr__(self, name: str, value: Value) -> None: |
560 | | - if name in self.__dict__: |
561 | | - self.__dict__[name] = value |
| 552 | + if name in self.__dataclass_fields__: |
| 553 | + super().__setattr__(name, value) |
562 | 554 | else: |
563 | 555 | self[name] = value |
564 | 556 |
|
|
0 commit comments