Coverage for pySDC / helpers / pysdc_helper.py: 95%
19 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-07 10:19 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-07 10:19 +0000
1import logging
4class FrozenClass(object):
5 """
6 Helper class to freeze a class, i.e. to avoid adding more attributes
8 Attributes:
9 __isfrozen: Flag to freeze a class
10 """
12 __isfrozen = False
14 def __init_subclass__(cls, **kwargs):
15 """
16 Called when a class inherits from FrozenClass.
17 Creates a separate attrs list for each subclass.
18 """
19 super().__init_subclass__(**kwargs)
20 # Create a new attrs list for this specific subclass
21 cls.attrs = []
23 def __setattr__(self, key, value):
24 """
25 Function called when setting attributes
27 Args:
28 key: the attribute
29 value: the value
30 """
32 # check if attribute exists and if class is frozen
33 if self.__isfrozen and not (key in type(self).attrs or hasattr(self, key)):
34 raise TypeError(f'{type(self).__name__!r} is a frozen class, cannot add attribute {key!r}')
36 object.__setattr__(self, key, value)
38 def __getattr__(self, key):
39 """
40 This is needed in case the variables have not been initialized after adding.
41 """
42 if key in type(self).attrs:
43 return None
44 else:
45 return super().__getattribute__(key)
47 @classmethod
48 def add_attr(cls, key, raise_error_if_exists=False):
49 """
50 Add a key to the allowed attributes of this class.
52 Args:
53 key (str): The key to add
54 raise_error_if_exists (bool): Raise an error if the attribute already exists in the class
55 """
56 logger = logging.getLogger(cls.__name__)
57 if key in cls.attrs:
58 if raise_error_if_exists:
59 raise TypeError(f'Attribute {key!r} already exists in {cls.__name__}!')
60 else:
61 logger.debug(f'Skip adding attribute {key!r} because it already exists in {cls.__name__}!')
62 else:
63 cls.attrs += [key]
64 logger.debug(f'Added attribute {key!r} to {cls.__name__}')
66 def _freeze(self):
67 """
68 Function to freeze the class
69 """
70 self.__isfrozen = True
72 def get(self, key, default=None):
73 """
74 Wrapper for `__dict__.get` to use when reading variables that might not exist, depending on the configuration
76 Args:
77 key (str): Name of the variable you wish to read
78 default: Value to be returned if the variable does not exist
80 Returns:
81 __dict__.get(key, default)
82 """
83 return self.__dict__.get(key, default)
85 def __dir__(self):
86 """
87 My hope is that some editors can use this for dynamic autocompletion.
88 """
89 return super().__dir__() + type(self).attrs