Skip to content

Commit 60c3ad2

Browse files
committed
Patch: Document metaprogrammed module attributes
Expanded documentation to include dynamically-generated module-level attributes that cannot be detected or documented without running the code. Specifically: * adafruit_logging.NOTSET * adafruit_logging.DEBUG * adafruit_logging.INFO * adafruit_logging.WARNING * adafruit_logging.ERROR * adafruit_logging.CRITICAL are all module-level attributes that are generated using this block of metaprogramming (line 65): ``` LEVELS = [ (00, "NOTSET"), (10, "DEBUG"), (20, "INFO"), (30, "WARNING"), (40, "ERROR"), (50, "CRITICAL"), ] for level_value, level_name in LEVELS: globals()[level_name] = level_value ```
1 parent d579ea6 commit 60c3ad2

File tree

1 file changed

+99
-52
lines changed

1 file changed

+99
-52
lines changed

adafruit_logging.py

Lines changed: 99 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#
33
# SPDX-License-Identifier: MIT
44

5+
# noinspection PyUnresolvedReferences
56
"""
67
`adafruit_logging`
78
================================================================================
@@ -22,6 +23,30 @@
2223
* Adafruit CircuitPython firmware for the supported boards:
2324
https://github.com/adafruit/circuitpython/releases
2425
26+
Attributes
27+
----------
28+
LEVELS : list
29+
A list of tuples representing the valid logging levels used by
30+
this module. Each tuple contains exactly two elements: one int and one
31+
str. The int in each tuple represents the relative severity of that
32+
level (00 to 50). The str in each tuple is the string representation of
33+
that logging level ("NOTSET" to "CRITICAL"; see below).
34+
NOTSET : int
35+
The NOTSET logging level, which is a dummy logging level that can be
36+
used to indicate that a `Logger` should not print any logging messages,
37+
regardless of how severe those messages might be (including CRITICAL).
38+
DEBUG : int
39+
The DEBUG logging level, which is the lowest (least severe) real level.
40+
INFO : int
41+
The INFO logging level for informative/informational messages.
42+
WARNING : int
43+
The WARNING logging level for warnings that should be addressed/fixed.
44+
ERROR : int
45+
The ERROR logging level for Python exceptions that occur during runtime.
46+
CRITICAL : int
47+
The CRITICAL logging level, which is the highest (most severe) level for
48+
unrecoverable errors that have caused the code to halt and exit.
49+
2550
"""
2651
# pylint:disable=redefined-outer-name,consider-using-enumerate,no-self-use
2752
# pylint:disable=invalid-name
@@ -30,6 +55,11 @@
3055

3156
__version__ = "0.0.0-auto.0"
3257
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Logger.git"
58+
# noinspection PyUnresolvedReferences
59+
# pylint:disable=undefined-all-variable
60+
__all__ = ['LEVELS', 'NOTSET', 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL',
61+
'level_for', 'LoggingHandler', 'PrintHandler', 'logger_cache',
62+
'null_logger', 'getLogger', 'Logger', 'NullLogger']
3363

3464

3565
LEVELS = [
@@ -41,54 +71,56 @@
4171
(50, "CRITICAL"),
4272
]
4373

44-
for value, name in LEVELS:
45-
globals()[name] = value
74+
for __value, __name in LEVELS:
75+
globals()[__name] = __value
4676

4777

48-
def level_for(value):
49-
"""Convert a numberic level to the most appropriate name.
78+
def level_for(level_value):
79+
"""Convert a numeric level to the most appropriate name.
5080
51-
:param value: a numeric level
81+
:param int level_value: a numeric level
5282
5383
"""
5484
for i in range(len(LEVELS)):
55-
if value == LEVELS[i][0]:
85+
if level_value == LEVELS[i][0]:
5686
return LEVELS[i][1]
57-
if value < LEVELS[i][0]:
87+
if level_value < LEVELS[i][0]:
5888
return LEVELS[i - 1][1]
5989
return LEVELS[0][1]
6090

6191

6292
class LoggingHandler:
6393
"""Abstract logging message handler."""
6494

65-
def format(self, level, msg):
95+
def format(self, log_level, message):
6696
"""Generate a timestamped message.
6797
68-
:param level: the logging level
69-
:param msg: the message to log
98+
:param int log_level: the logging level
99+
:param str message: the message to log
70100
71101
"""
72-
return "{0}: {1} - {2}".format(time.monotonic(), level_for(level), msg)
102+
return "{0}: {1} - {2}".format(time.monotonic(),
103+
level_for(log_level),
104+
message)
73105

74-
def emit(self, level, msg):
106+
def emit(self, log_level, message):
75107
"""Send a message where it should go.
76-
Place holder for subclass implementations.
108+
Placeholder for subclass implementations.
77109
"""
78110
raise NotImplementedError()
79111

80112

81113
class PrintHandler(LoggingHandler):
82114
"""Send logging messages to the console by using print."""
83115

84-
def emit(self, level, msg):
116+
def emit(self, log_level, message):
85117
"""Send a message to teh console.
86118
87-
:param level: the logging level
88-
:param msg: the message to log
119+
:param int log_level: the logging level
120+
:param str message: the message to log
89121
90122
"""
91-
print(self.format(level, msg))
123+
print(self.format(log_level, message))
92124

93125

94126
# The level module-global variables get created when loaded
@@ -97,23 +129,24 @@ def emit(self, level, msg):
97129
logger_cache = dict()
98130
null_logger = None
99131

132+
100133
# pylint:disable=global-statement
101-
def getLogger(name):
134+
def getLogger(logger_name):
102135
"""Create or retrieve a logger by name.
103136
104-
:param name: the name of the logger to create/retrieve None will cause the
105-
NullLogger instance to be returned.
137+
:param str logger_name: The name of the `Logger` to create/retrieve. `None`
138+
will cause the `NullLogger` instance to be returned.
106139
107140
"""
108141
global null_logger
109-
if not name or name == "":
142+
if not logger_name or logger_name == "":
110143
if not null_logger:
111144
null_logger = NullLogger()
112145
return null_logger
113146

114-
if name not in logger_cache:
115-
logger_cache[name] = Logger()
116-
return logger_cache[name]
147+
if logger_name not in logger_cache:
148+
logger_cache[logger_name] = Logger()
149+
return logger_cache[logger_name]
117150

118151

119152
# pylint:enable=global-statement
@@ -124,16 +157,17 @@ class Logger:
124157

125158
def __init__(self):
126159
"""Create an instance."""
160+
# noinspection PyUnresolvedReferences
127161
self._level = NOTSET
128162
self._handler = PrintHandler()
129163

130-
def setLevel(self, value):
131-
"""Set the logging cuttoff level.
164+
def setLevel(self, log_level):
165+
"""Set the logging cutoff level.
132166
133-
:param value: the lowest level to output
167+
:param int log_level: the lowest level to output
134168
135169
"""
136-
self._level = value
170+
self._level = log_level
137171

138172
def getEffectiveLevel(self):
139173
"""Get the effective level for this logger.
@@ -143,91 +177,104 @@ def getEffectiveLevel(self):
143177
"""
144178
return self._level
145179

146-
def addHandler(self, hldr):
180+
def addHandler(self, handler):
147181
"""Sets the handler of this logger to the specified handler.
148182
*NOTE* this is slightly different from the CPython equivalent which adds
149-
the handler rather than replaceing it.
183+
the handler rather than replacing it.
150184
151-
:param hldr: the handler
185+
:param handler: the handler
152186
153187
"""
154-
self._handler = hldr
188+
self._handler = handler
155189

156-
def log(self, level, format_string, *args):
190+
def log(self, log_level, format_string, *args):
157191
"""Log a message.
158192
159-
:param level: the priority level at which to log
160-
:param format_string: the core message string with embedded formatting directives
161-
:param args: arguments to ``format_string.format()``, can be empty
193+
:param int log_level: the priority level at which to log
194+
:param str format_string: the core message string with embedded
195+
formatting directives
196+
:param args: arguments to ``format_string.format()``; can be empty
162197
163198
"""
164-
if level >= self._level:
165-
self._handler.emit(level, format_string % args)
199+
if log_level >= self._level:
200+
self._handler.emit(log_level, format_string % args)
166201

167202
def debug(self, format_string, *args):
168203
"""Log a debug message.
169204
170-
:param format_string: the core message string with embedded formatting directives
171-
:param args: arguments to ``format_string.format()``, can be empty
205+
:param str format_string: the core message string with embedded
206+
formatting directives
207+
:param args: arguments to ``format_string.format()``; can be empty
172208
173209
"""
210+
# noinspection PyUnresolvedReferences
174211
self.log(DEBUG, format_string, *args)
175212

176213
def info(self, format_string, *args):
177214
"""Log a info message.
178215
179-
:param format_string: the core message string with embedded formatting directives
180-
:param args: arguments to ``format_string.format()``, can be empty
216+
:param str format_string: the core message string with embedded
217+
formatting directives
218+
:param args: arguments to ``format_string.format()``; can be empty
181219
182220
"""
221+
# noinspection PyUnresolvedReferences
183222
self.log(INFO, format_string, *args)
184223

185224
def warning(self, format_string, *args):
186225
"""Log a warning message.
187226
188-
:param format_string: the core message string with embedded formatting directives
189-
:param args: arguments to ``format_string.format()``, can be empty
227+
:param str format_string: the core message string with embedded
228+
formatting directives
229+
:param args: arguments to ``format_string.format()``; can be empty
190230
191231
"""
232+
# noinspection PyUnresolvedReferences
192233
self.log(WARNING, format_string, *args)
193234

194235
def error(self, format_string, *args):
195236
"""Log a error message.
196237
197-
:param format_string: the core message string with embedded formatting directives
198-
:param args: arguments to ``format_string.format()``, can be empty
238+
:param str format_string: the core message string with embedded
239+
formatting directives
240+
:param args: arguments to ``format_string.format()``; can be empty
199241
200242
"""
243+
# noinspection PyUnresolvedReferences
201244
self.log(ERROR, format_string, *args)
202245

203246
def critical(self, format_string, *args):
204247
"""Log a critical message.
205248
206-
:param format_string: the core message string with embedded formatting directives
207-
:param args: arguments to ``format_string.format()``, can be empty
249+
:param str format_string: the core message string with embedded
250+
formatting directives
251+
:param args: arguments to ``format_string.format()``; can be empty
208252
209253
"""
254+
# noinspection PyUnresolvedReferences
210255
self.log(CRITICAL, format_string, *args)
211256

212257

213258
class NullLogger:
214259
"""Provide an empty logger.
215-
This can be used in place of a real logger to more efficiently disable logging."""
260+
This can be used in place of a real logger to more efficiently disable
261+
logging."""
216262

217263
def __init__(self):
218264
"""Dummy implementation."""
219265

220-
def setLevel(self, value):
266+
def setLevel(self, log_level):
221267
"""Dummy implementation."""
222268

223269
def getEffectiveLevel(self):
224270
"""Dummy implementation."""
271+
# noinspection PyUnresolvedReferences
225272
return NOTSET
226273

227-
def addHandler(self, hldr):
274+
def addHandler(self, handler):
228275
"""Dummy implementation."""
229276

230-
def log(self, level, format_string, *args):
277+
def log(self, log_level, format_string, *args):
231278
"""Dummy implementation."""
232279

233280
def debug(self, format_string, *args):

0 commit comments

Comments
 (0)