diff --git a/adafruit_logging.py b/adafruit_logging.py index f90ec5b..5c5d6d6 100644 --- a/adafruit_logging.py +++ b/adafruit_logging.py @@ -62,8 +62,22 @@ from collections import namedtuple try: - from typing import Optional, Union - from io import TextIOWrapper, StringIO + from typing import Optional + + try: + from typing import Protocol + except ImportError: + from typing_extensions import Protocol + + class WriteableStream(Protocol): + """Any stream that can ``write`` strings""" + + def write(self, buf: str) -> int: + """Write to the stream + + :param str buf: The string data to write to the stream + """ + except ImportError: pass @@ -143,8 +157,7 @@ class Handler: def format(self, record: LogRecord) -> str: """Generate a timestamped message. - :param int log_level: the logging level - :param str message: the message to log + :param record: The record (message object) to be logged """ return "{0:<0.3f}: {1} - {2}".format( @@ -154,6 +167,8 @@ def format(self, record: LogRecord) -> str: def emit(self, record: LogRecord) -> None: """Send a message where it should go. Placeholder for subclass implementations. + + :param record: The record (message object) to be logged """ raise NotImplementedError() @@ -164,10 +179,12 @@ class StreamHandler(Handler): """Send logging messages to a stream, `sys.stderr` (typically the serial console) by default. - :param stream: The stream to log to, default is `sys.stderr` + :param stream: The stream to log to, default is `sys.stderr`; + can accept any stream that implements ``stream.write()`` + with string inputs """ - def __init__(self, stream: Optional[Union[TextIOWrapper, StringIO]] = None) -> None: + def __init__(self, stream: Optional[WriteableStream] = None) -> None: super().__init__() if stream is None: stream = sys.stderr @@ -177,8 +194,7 @@ def __init__(self, stream: Optional[Union[TextIOWrapper, StringIO]] = None) -> N def emit(self, record: LogRecord) -> None: """Send a message to the console. - :param int log_level: the logging level - :param str message: the message to log + :param record: The record (message object) to be logged """ self.stream.write(self.format(record)) @@ -203,16 +219,14 @@ def close(self) -> None: def format(self, record: LogRecord) -> str: """Generate a string to log - :param level: The level of the message - :param msg: The message to format + :param record: The record (message object) to be logged """ return super().format(record) + "\r\n" def emit(self, record: LogRecord) -> None: """Generate the message and write it to the UART. - :param level: The level of the message - :param msg: The message to log + :param record: The record (message object) to be logged """ self.stream.write(self.format(record)) @@ -286,7 +300,7 @@ def addHandler(self, hdlr: Handler) -> None: *NOTE* This is slightly different from the CPython equivalent which adds the handler rather than replacing it. - :param Handler hdlr: the handler + :param Handler hdlr: The handler to add """ self._handler = hdlr diff --git a/requirements.txt b/requirements.txt index 5f97a2d..3396d72 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ # SPDX-License-Identifier: Unlicense Adafruit-Blinka +typing-extensions diff --git a/setup.py b/setup.py index 428e4c2..86b612c 100644 --- a/setup.py +++ b/setup.py @@ -32,9 +32,7 @@ # Author details author="Adafruit Industries", author_email="circuitpython@adafruit.com", - install_requires=[ - "Adafruit-Blinka", - ], + install_requires=["Adafruit-Blinka", "typing-extensions"], # Choose your license license="MIT", # See https://pypi.python.org/pypi?%3Aaction=list_classifiers