Skip to content

Commit 255dfff

Browse files
authored
Merge pull request #28 from tekktrik/dev/cpython-subset
Make true CPython subset
2 parents 1815d54 + 85ad94c commit 255dfff

File tree

5 files changed

+134
-125
lines changed

5 files changed

+134
-125
lines changed

adafruit_logging/__init__.py renamed to adafruit_logging.py

Lines changed: 124 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
# pylint:disable=invalid-name
5252

5353
import time
54+
import sys
5455

5556
__version__ = "0.0.0-auto.0"
5657
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Logger.git"
@@ -63,14 +64,14 @@
6364
"WARNING",
6465
"ERROR",
6566
"CRITICAL",
66-
"level_for",
67-
"LoggingHandler",
68-
"PrintHandler",
67+
"_level_for",
68+
"Handler",
69+
"StreamHandler",
6970
"logger_cache",
70-
"null_logger",
7171
"getLogger",
7272
"Logger",
73-
"NullLogger",
73+
"NullHandler",
74+
"FileHandler",
7475
]
7576

7677

@@ -87,7 +88,7 @@
8788
globals()[__name] = __value
8889

8990

90-
def level_for(value: int) -> str:
91+
def _level_for(value: int) -> str:
9192
"""Convert a numeric level to the most appropriate name.
9293
9394
:param int value: a numeric level
@@ -101,62 +102,80 @@ def level_for(value: int) -> str:
101102
return LEVELS[0][1]
102103

103104

104-
class LoggingHandler:
105+
# pylint: disable=too-few-public-methods
106+
class Handler:
105107
"""Abstract logging message handler."""
106108

107-
def format(self, log_level: int, message: str) -> str:
109+
def __init__(self, level=NOTSET): # pylint: disable=undefined-variable
110+
self.level = level
111+
"""Level of the handler; this is currently unused, and
112+
only the level of the logger is used"""
113+
114+
def _format(self, log_level: int, message: str) -> str:
108115
"""Generate a timestamped message.
109116
110117
:param int log_level: the logging level
111118
:param str message: the message to log
112119
113120
"""
114121
return "{0:<0.3f}: {1} - {2}".format(
115-
time.monotonic(), level_for(log_level), message
122+
time.monotonic(), _level_for(log_level), message
116123
)
117124

118-
def emit(self, log_level: int, message: str):
125+
def _emit(self, log_level: int, message: str):
119126
"""Send a message where it should go.
120127
Placeholder for subclass implementations.
121128
"""
122129
raise NotImplementedError()
123130

124131

125-
class PrintHandler(LoggingHandler):
126-
"""Send logging messages to the console by using print."""
132+
# pylint: disable=too-few-public-methods
133+
class StreamHandler(Handler):
134+
"""Send logging messages to a stream, `sys.stderr` (typically
135+
the serial console) by default.
136+
137+
:param stream: The stream to log to, default is `sys.stderr`
138+
"""
139+
140+
def __init__(self, stream=None):
141+
super().__init__()
142+
if stream is None:
143+
stream = sys.stderr
144+
self.stream = stream
145+
"""The stream to log to"""
127146

128-
def emit(self, log_level: int, message: str):
147+
def _emit(self, log_level: int, message: str):
129148
"""Send a message to the console.
130149
131150
:param int log_level: the logging level
132151
:param str message: the message to log
133152
134153
"""
135-
print(self.format(log_level, message))
154+
print(self._format(log_level, message))
136155

137156

138157
# The level module-global variables get created when loaded
139158
# pylint:disable=undefined-variable
140159

141160
logger_cache = {}
142-
null_logger = None
161+
162+
163+
def _addLogger(logger_name: str):
164+
"""Adds the logger if it doesn't already exist"""
165+
if logger_name not in logger_cache:
166+
logger_cache[logger_name] = Logger(logger_name)
167+
143168

144169
# pylint:disable=global-statement
145170
def getLogger(logger_name: str) -> "Logger":
146-
"""Create or retrieve a logger by name.
171+
"""Create or retrieve a logger by name; only retrieves loggers
172+
made using this function; if a Logger with this name does not
173+
exist it is created
147174
148-
:param str logger_name: The name of the `Logger` to create/retrieve. `None`
149-
will cause the `NullLogger` instance to be returned.
175+
:param str logger_name: The name of the `Logger` to create/retrieve.
150176
151177
"""
152-
global null_logger
153-
if not logger_name or logger_name == "":
154-
if not null_logger:
155-
null_logger = NullLogger()
156-
return null_logger
157-
158-
if logger_name not in logger_cache:
159-
logger_cache[logger_name] = Logger()
178+
_addLogger(logger_name)
160179
return logger_cache[logger_name]
161180

162181

@@ -166,10 +185,13 @@ def getLogger(logger_name: str) -> "Logger":
166185
class Logger:
167186
"""Provide a logging api."""
168187

169-
def __init__(self):
188+
def __init__(self, name: str, level=NOTSET):
170189
"""Create an instance."""
171-
self._level = NOTSET
172-
self._handler = PrintHandler()
190+
self._level = level
191+
self.name = name
192+
"""The name of the logger, this should be unique for proper
193+
functionality of `getLogger()`"""
194+
self._handler = None
173195

174196
def setLevel(self, log_level: int):
175197
"""Set the logging cutoff level.
@@ -187,86 +209,89 @@ def getEffectiveLevel(self) -> int:
187209
"""
188210
return self._level
189211

190-
def addHandler(self, handler: LoggingHandler):
212+
def addHandler(self, hdlr: Handler):
191213
"""Sets the handler of this logger to the specified handler.
214+
192215
*NOTE* this is slightly different from the CPython equivalent which adds
193216
the handler rather than replacing it.
194217
195218
:param LoggingHandler handler: the handler
196219
197220
"""
198-
self._handler = handler
221+
self._handler = hdlr
199222

200-
def log(self, log_level: int, format_string: str, *args):
223+
def hasHandlers(self) -> bool:
224+
"""Whether any handlers have been set for this logger"""
225+
return self._handler is not None
226+
227+
def log(self, level: int, msg: str, *args):
201228
"""Log a message.
202229
203-
:param int log_level: the priority level at which to log
204-
:param str format_string: the core message string with embedded
230+
:param int level: the priority level at which to log
231+
:param str msg: the core message string with embedded
205232
formatting directives
206233
:param args: arguments to ``format_string.format()``; can be empty
207234
208235
"""
209-
if log_level >= self._level:
210-
self._handler.emit(log_level, format_string % args)
236+
if level >= self._level:
237+
self._handler._emit(level, msg % args) # pylint: disable=protected-access
211238

212-
def debug(self, format_string: str, *args):
239+
def debug(self, msg: str, *args):
213240
"""Log a debug message.
214241
215-
:param str format_string: the core message string with embedded
242+
:param str fmsg: the core message string with embedded
216243
formatting directives
217244
:param args: arguments to ``format_string.format()``; can be empty
218245
219246
"""
220-
self.log(DEBUG, format_string, *args)
247+
self.log(DEBUG, msg, *args)
221248

222-
def info(self, format_string: str, *args):
249+
def info(self, msg: str, *args):
223250
"""Log a info message.
224251
225-
:param str format_string: the core message string with embedded
252+
:param str msg: the core message string with embedded
226253
formatting directives
227254
:param args: arguments to ``format_string.format()``; can be empty
228255
229256
"""
230-
self.log(INFO, format_string, *args)
257+
self.log(INFO, msg, *args)
231258

232-
def warning(self, format_string: str, *args):
259+
def warning(self, msg: str, *args):
233260
"""Log a warning message.
234261
235-
:param str format_string: the core message string with embedded
262+
:param str msg: the core message string with embedded
236263
formatting directives
237264
:param args: arguments to ``format_string.format()``; can be empty
238265
239266
"""
240-
self.log(WARNING, format_string, *args)
267+
self.log(WARNING, msg, *args)
241268

242-
def error(self, format_string: str, *args):
269+
def error(self, msg: str, *args):
243270
"""Log a error message.
244271
245-
:param str format_string: the core message string with embedded
272+
:param str msg: the core message string with embedded
246273
formatting directives
247274
:param args: arguments to ``format_string.format()``; can be empty
248275
249276
"""
250-
self.log(ERROR, format_string, *args)
277+
self.log(ERROR, msg, *args)
251278

252-
def critical(self, format_string: str, *args):
279+
def critical(self, msg: str, *args):
253280
"""Log a critical message.
254281
255-
:param str format_string: the core message string with embedded
282+
:param str msg: the core message string with embedded
256283
formatting directives
257284
:param args: arguments to ``format_string.format()``; can be empty
258285
259286
"""
260-
self.log(CRITICAL, format_string, *args)
287+
self.log(CRITICAL, msg, *args)
261288

262289

263-
class NullLogger:
264-
"""Provide an empty logger.
265-
This can be used in place of a real logger to more efficiently disable
266-
logging."""
290+
class NullHandler(Handler):
291+
"""Provide an empty log handler.
267292
268-
def __init__(self):
269-
"""Dummy implementation."""
293+
This can be used in place of a real log handler to more efficiently disable
294+
logging."""
270295

271296
def setLevel(self, log_level: int):
272297
"""Dummy implementation."""
@@ -275,23 +300,59 @@ def getEffectiveLevel(self) -> int:
275300
"""Dummy implementation."""
276301
return NOTSET
277302

278-
def addHandler(self, handler: LoggingHandler):
303+
def addHandler(self, handler: Handler):
279304
"""Dummy implementation."""
280305

281306
def log(self, log_level: int, format_string: str, *args):
282307
"""Dummy implementation."""
283308

284-
def debug(self, format_string: str, *args):
309+
def debug(self, msg: str, *args):
285310
"""Dummy implementation."""
286311

287-
def info(self, format_string: str, *args):
312+
def info(self, msg: str, *args):
288313
"""Dummy implementation."""
289314

290-
def warning(self, format_string: str, *args):
315+
def warning(self, msg: str, *args):
291316
"""Dummy implementation."""
292317

293-
def error(self, format_string: str, *args):
318+
def error(self, msg: str, *args):
294319
"""Dummy implementation."""
295320

296-
def critical(self, format_string: str, *args):
321+
def critical(self, msg: str, *args):
297322
"""Dummy implementation."""
323+
324+
def _emit(self, log_level: int, message: str):
325+
"""Dummy implementation"""
326+
327+
328+
class FileHandler(StreamHandler):
329+
"""File handler for working with log files off of the microcontroller (like
330+
an SD card)
331+
332+
:param str filename: The filename of the log file
333+
:param str mode: Whether to write ('w') or append ('a'); default is to append
334+
"""
335+
336+
def __init__(self, filename: str, mode: str = "a") -> None:
337+
# pylint: disable=consider-using-with
338+
super().__init__(open(filename, mode=mode))
339+
340+
def close(self):
341+
"""Closes the file"""
342+
self.stream.close()
343+
344+
def _format(self, log_level: int, message: str):
345+
"""Generate a string to log
346+
347+
:param level: The level of the message
348+
:param msg: The message to format
349+
"""
350+
return super()._format(log_level, message) + "\r\n"
351+
352+
def _emit(self, log_level: int, message: str):
353+
"""Generate the message and write it to the UART.
354+
355+
:param level: The level of the message
356+
:param msg: The message to log
357+
"""
358+
self.stream.write(self._format(log_level, message))

adafruit_logging/extensions.py

Lines changed: 0 additions & 51 deletions
This file was deleted.

0 commit comments

Comments
 (0)