File: verbosity_mgr.py

package info (click to toggle)
meep-mpi-default 1.29.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 79,148 kB
  • sloc: cpp: 32,541; python: 31,061; lisp: 1,225; makefile: 516; sh: 249; ansic: 131; javascript: 5
file content (189 lines) | stat: -rw-r--r-- 6,364 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
class Verbosity:
    """
    A class to help make accessing and setting the global verbosity level a bit
    more pythonic. It manages one or more verbosity flags that are located in
    the C/C++ libraries used by Meep.

    The verbosity levels are:

    * 0: minimal output
    * 1: a little
    * 2: a lot
    * 3: debugging

    An instance of `Verbosity` is created when meep is imported, and is
    accessible as `meep.verbosity`. The `meep.mpb` package also has a verbosity
    flag in its C library, and it can also be managed via the `Verbosity` class
    after `meep.mpb` is imported.

    Note that this class is a Singleton, meaning that each call to create a new
    `Verbosity` actually gives you the same instance. The new C `verbosity`
    flag will be added to a list of verbosity flags managed by this class.

    The `Verbosity` instance can be used as a global verbosity controller, and
    assignments to any instance of `Verbosity` will set the global verbosity
    level for all library components. For example, this:

    ```python
    meep.verbosity(2)
    # or meep.verbosity.set(2) if you prefer being more explicit
    ```

    will set all of the managed verbosity flags to level 2.

    Each managed verbosity flag can also be accessed individually if desired.
    Each time a new C/C++ library verbosity flag is added to this Python class a
    new property is added which can be used to access that individual flag.
    Currently the properties that are available are named simply `meep` and
    `mpb`. This means that you can set two different verbosity levels like this:

    ```python
    verbosity = meep.verbosity # not required, it's just to save some typing
    verbosity.meep = 2
    verbosity.mpb = 1
    ```
    """

    _instance = None

    def __new__(cls, *args, **kw):
        # Create the real instance only the first time, and return the same each
        # time Verbosity is called thereafter.
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._init()
        return cls._instance

    def _init(self):
        """
        Set up the initial state of the singleton. Called only when the first
        instance is created.
        """
        self._master_verbosity = -1
        self._cvars = {}

    @classmethod
    def reset(cls):
        # Probably just for testing. Drops the existing the singleton instance
        # so a new one will be created the next time a new Verbosity is
        # instantiated.
        if cls._instance is not None:
            cls._instance._init()
            cls._instance = None

    def __init__(self, cvar=None, name=None, initial_level=1):
        """See `add_verbosity_var()`"""
        self.add_verbosity_var(cvar, name, initial_level)

    def add_verbosity_var(self, cvar=None, name=None, initial_level=1):
        """
        Add a new verbosity flag to be managed. `cvar` should be some object
        that has a `verbosity` attribute, such as `meep.cvar` or `mpb.cvar`.
        """
        if cvar is None or not hasattr(cvar, "verbosity"):
            # If we're not given a module.cvar (e.g., while testing) or if the
            # cvar does not have a verbosity member (e.g. the lib hasn't been
            # updated to have a verbosity flag yet) then use a dummy object so
            # things can still run without it.
            class _dummy:
                def __init__(self):
                    self.verbosity = 1

            cvar = _dummy()

        # If a name is not given then manufacture one
        if name is None:
            name = f"cvar_{len(self._cvars)}"
        self._cvars[name] = cvar

        # And create a property for so it can be accessed like `verbosity.mpb`
        self.make_property(name)

        # The initial master (global) level is determined by the first instance created
        if self._master_verbosity == -1:
            self.set(initial_level)

    def get(self):
        """
        Returns the current global verbosity level.
        """
        return self._master_verbosity

    def get_all(self):
        """
        Return a list of the values of all verbosity flags being managed. This
        is mostly intended for debugging this class and won't likely be useful
        otherwise.
        """
        return [value.verbosity for value in self._cvars.values()]

    def set(self, level):
        """
        Validates the range, and sets the global verbosity level. Returns the
        former value.
        """
        if level < 0 or level > 3:
            raise ValueError("Only verbosity levels 0-3 are supported")
        old = self._master_verbosity
        for cvar in self._cvars.values():
            cvar.verbosity = level
        self._master_verbosity = level
        return old

    def __call__(self, level):
        """
        Convenience for setting the verbosity level. This lets you set the
        global level by calling the instance like a function. For example, if
        `verbosity` is an instance of this class, then its value can be changed
        like this:

        ```
        verbosity(0)
        ```
        """
        return self.set(level)

    def __int__(self):
        """
        A convenience for getting the global verbosity level anywhere an integer
        is expected.
        """
        return self.get()

    def __repr__(self):
        return f"Verbosity: level={self.get()}"

    # Some comparison operators
    def __gt__(self, o):
        return self.get() > o

    def __lt__(self, o):
        return self.get() < o

    def __eq__(self, o):
        return self.get() == o

    def __ne__(self, o):
        return self.get() != o

    def __le__(self, o):
        return self.get() <= o

    def __ge__(self, o):
        return self.get() >= o

    def make_property(self, name):
        """
        Add a property to the class with the given name that gets or sets the
        verbosity in the cvar with that name in self._cvars.
        """

        def _getter(self, name=name):
            return self._cvars[name].verbosity

        def _setter(self, level, name=name):
            if level < 0 or level > 3:
                raise ValueError("Only verbosity levels 0-3 are supported")
            self._cvars[name].verbosity = level

        setattr(Verbosity, name, property(_getter, _setter))