Class that works a bit like a dictionary but can validate keys and has some extra features.
  Source code in navis/plotting/settings.py
 | 14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 | @dataclass
class Settings:
    """Class that works a bit like a dictionary but can validate keys and has some extra features."""
    # We can define synonyms for arguments, so that they can be used interchangeably
    _synonyms: List[Tuple] = field(default_factory=list)
    _name = "Settings"
    def __setattr__(self, key, value, check_valid=False):
        if check_valid and key not in self.properties:
            raise AttributeError(
                f"The '{key}' argument is invalid for {self._name}. Valid arguments are: {', '.join(self.properties)}"
            )
        self.__dict__[key] = value
    def __contains__(self, key):
        return key in self.properties
    @property
    def properties(self):
        return tuple(
            [
                p
                for p in dir(self)
                if not p.startswith("_")
                and (p != "properties")   # we need this to avoid infinite recursion
                and not callable(getattr(self, p, None))
            ]
        )
    def update_settings(self, **kwargs):
        # Deal with synonyms
        for syn in self._synonyms:
            present = [s for s in syn if s in kwargs]
            if len(present) > 1:
                raise ValueError(f"Multiple synonyms for the same argument: {present}")
            for s in syn[1:]:
                if s in kwargs:
                    kwargs[syn[0]] = kwargs.pop(s)
        for k, v in kwargs.items():
            self.__setattr__(k, v, check_valid=VALIDATE_SETTINGS)
        # For method chaining
        return self
    def to_dict(self):
        return {k: v for k, v in self.__dict__.items() if not k.startswith("_")}
    def get(self, key, default=None):
        value = self.__dict__.get(key, default)
        if value is None:
            value = default
        return value
    def pop(self, key, default=None):
        return self.__dict__.pop(key, default)
 |