Skip to content

Commit f426161

Browse files
committed
Merge branch 'main' into document-dynamic-levels
# Conflicts: # adafruit_logging/__init__.py
2 parents 9b7859e + 34bcc68 commit f426161

File tree

10 files changed

+152
-50
lines changed

10 files changed

+152
-50
lines changed

.github/workflows/build.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ jobs:
4242
# (e.g. - apt-get: gettext, etc; pip: circuitpython-build-tools, requirements.txt; etc.)
4343
run: |
4444
source actions-ci/install.sh
45-
- name: Pip install pylint, Sphinx, pre-commit
45+
- name: Pip install Sphinx, pre-commit
4646
run: |
47-
pip install --force-reinstall pylint Sphinx sphinx-rtd-theme pre-commit
47+
pip install --force-reinstall Sphinx sphinx-rtd-theme pre-commit
4848
- name: Library version
4949
run: git describe --dirty --always --tags
5050
- name: Pre-commit hooks

.pre-commit-config.yaml

+17-9
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,25 @@ repos:
1818
- id: end-of-file-fixer
1919
- id: trailing-whitespace
2020
- repo: https://github.com/pycqa/pylint
21-
rev: pylint-2.7.1
21+
rev: v2.11.1
2222
hooks:
2323
- id: pylint
2424
name: pylint (library code)
2525
types: [python]
26-
exclude: "^(docs/|examples/|setup.py$)"
27-
- repo: local
28-
hooks:
29-
- id: pylint_examples
30-
name: pylint (examples code)
26+
args:
27+
- --disable=consider-using-f-string
28+
exclude: "^(docs/|examples/|tests/|setup.py$)"
29+
- id: pylint
30+
name: pylint (example code)
3131
description: Run pylint rules on "examples/*.py" files
32-
entry: /usr/bin/env bash -c
33-
args: ['([[ ! -d "examples" ]] || for example in $(find . -path "./examples/*.py"); do pylint --disable=missing-docstring,invalid-name $example; done)']
34-
language: system
32+
types: [python]
33+
files: "^examples/"
34+
args:
35+
- --disable=missing-docstring,invalid-name,consider-using-f-string,duplicate-code
36+
- id: pylint
37+
name: pylint (test code)
38+
description: Run pylint rules on "tests/*.py" files
39+
types: [python]
40+
files: "^tests/"
41+
args:
42+
- --disable=missing-docstring,consider-using-f-string,duplicate-code

.pylintrc

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ confidence=
5959
# no Warning level messages displayed, use"--disable=all --enable=classes
6060
# --disable=W"
6161
# disable=import-error,print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call
62-
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,bad-continuation
62+
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,import-error,bad-continuation,unspecified-encoding
6363

6464
# Enable the message, report, category or checker with the given id(s). You can
6565
# either give multiple identifier separated by comma (,) or put this option
@@ -256,7 +256,7 @@ ignore-docstrings=yes
256256
ignore-imports=yes
257257

258258
# Minimum lines number of a similarity.
259-
min-similarity-lines=12
259+
min-similarity-lines=4
260260

261261

262262
[BASIC]

.readthedocs.yaml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: Unlicense
4+
5+
# Read the Docs configuration file
6+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
7+
8+
# Required
9+
version: 2
10+
11+
python:
12+
version: "3.7"
13+
install:
14+
- requirements: docs/requirements.txt
15+
- requirements: requirements.txt

.readthedocs.yml

-11
This file was deleted.

README.rst

+5
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ Usage Example
4040
logger.error('Error message')
4141
4242
43+
Documentation
44+
=============
45+
46+
API documentation for this library can be found on `Read the Docs <https://circuitpython.readthedocs.io/projects/logging/en/latest/>`_.
47+
4348
Contributing
4449
============
4550

adafruit_logging.py renamed to adafruit_logging/__init__.py

+25-26
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@
8787
globals()[__name] = __value
8888

8989

90-
def level_for(value):
90+
def level_for(value: int) -> str:
9191
"""Convert a numeric level to the most appropriate name.
9292
9393
:param int value: a numeric level
@@ -104,7 +104,7 @@ def level_for(value):
104104
class LoggingHandler:
105105
"""Abstract logging message handler."""
106106

107-
def format(self, log_level, message):
107+
def format(self, log_level: int, message: str) -> str:
108108
"""Generate a timestamped message.
109109
110110
:param int log_level: the logging level
@@ -113,7 +113,7 @@ def format(self, log_level, message):
113113
"""
114114
return "{0}: {1} - {2}".format(time.monotonic(), level_for(log_level), message)
115115

116-
def emit(self, log_level, message):
116+
def emit(self, log_level: int, message: str):
117117
"""Send a message where it should go.
118118
Placeholder for subclass implementations.
119119
"""
@@ -123,8 +123,8 @@ def emit(self, log_level, message):
123123
class PrintHandler(LoggingHandler):
124124
"""Send logging messages to the console by using print."""
125125

126-
def emit(self, log_level, message):
127-
"""Send a message to teh console.
126+
def emit(self, log_level: int, message: str):
127+
"""Send a message to the console.
128128
129129
:param int log_level: the logging level
130130
:param str message: the message to log
@@ -136,12 +136,11 @@ def emit(self, log_level, message):
136136
# The level module-global variables get created when loaded
137137
# pylint:disable=undefined-variable
138138

139-
logger_cache = dict()
139+
logger_cache = {}
140140
null_logger = None
141141

142-
143142
# pylint:disable=global-statement
144-
def getLogger(logger_name):
143+
def getLogger(logger_name: str) -> "Logger":
145144
"""Create or retrieve a logger by name.
146145
147146
:param str logger_name: The name of the `Logger` to create/retrieve. `None`
@@ -170,23 +169,23 @@ def __init__(self):
170169
self._level = NOTSET
171170
self._handler = PrintHandler()
172171

173-
def setLevel(self, log_level):
172+
def setLevel(self, log_level: int):
174173
"""Set the logging cutoff level.
175174
176175
:param int log_level: the lowest level to output
177176
178177
"""
179178
self._level = log_level
180179

181-
def getEffectiveLevel(self):
180+
def getEffectiveLevel(self) -> int:
182181
"""Get the effective level for this logger.
183182
184183
:return: the lowest level to output
185184
186185
"""
187186
return self._level
188187

189-
def addHandler(self, handler):
188+
def addHandler(self, handler: LoggingHandler):
190189
"""Sets the handler of this logger to the specified handler.
191190
*NOTE* this is slightly different from the CPython equivalent which adds
192191
the handler rather than replacing it.
@@ -196,7 +195,7 @@ def addHandler(self, handler):
196195
"""
197196
self._handler = handler
198197

199-
def log(self, log_level, format_string, *args):
198+
def log(self, log_level: int, format_string: str, *args):
200199
"""Log a message.
201200
202201
:param int log_level: the priority level at which to log
@@ -208,7 +207,7 @@ def log(self, log_level, format_string, *args):
208207
if log_level >= self._level:
209208
self._handler.emit(log_level, format_string % args)
210209

211-
def debug(self, format_string, *args):
210+
def debug(self, format_string: str, *args):
212211
"""Log a debug message.
213212
214213
:param str format_string: the core message string with embedded
@@ -218,7 +217,7 @@ def debug(self, format_string, *args):
218217
"""
219218
self.log(DEBUG, format_string, *args)
220219

221-
def info(self, format_string, *args):
220+
def info(self, format_string: str, *args):
222221
"""Log a info message.
223222
224223
:param str format_string: the core message string with embedded
@@ -228,7 +227,7 @@ def info(self, format_string, *args):
228227
"""
229228
self.log(INFO, format_string, *args)
230229

231-
def warning(self, format_string, *args):
230+
def warning(self, format_string: str, *args):
232231
"""Log a warning message.
233232
234233
:param str format_string: the core message string with embedded
@@ -238,7 +237,7 @@ def warning(self, format_string, *args):
238237
"""
239238
self.log(WARNING, format_string, *args)
240239

241-
def error(self, format_string, *args):
240+
def error(self, format_string: str, *args):
242241
"""Log a error message.
243242
244243
:param str format_string: the core message string with embedded
@@ -248,7 +247,7 @@ def error(self, format_string, *args):
248247
"""
249248
self.log(ERROR, format_string, *args)
250249

251-
def critical(self, format_string, *args):
250+
def critical(self, format_string: str, *args):
252251
"""Log a critical message.
253252
254253
:param str format_string: the core message string with embedded
@@ -267,30 +266,30 @@ class NullLogger:
267266
def __init__(self):
268267
"""Dummy implementation."""
269268

270-
def setLevel(self, log_level):
269+
def setLevel(self, log_level: int):
271270
"""Dummy implementation."""
272271

273-
def getEffectiveLevel(self):
272+
def getEffectiveLevel(self) -> int:
274273
"""Dummy implementation."""
275274
return NOTSET
276275

277-
def addHandler(self, handler):
276+
def addHandler(self, handler: LoggingHandler):
278277
"""Dummy implementation."""
279278

280-
def log(self, log_level, format_string, *args):
279+
def log(self, log_level: int, format_string: str, *args):
281280
"""Dummy implementation."""
282281

283-
def debug(self, format_string, *args):
282+
def debug(self, format_string: str, *args):
284283
"""Dummy implementation."""
285284

286-
def info(self, format_string, *args):
285+
def info(self, format_string: str, *args):
287286
"""Dummy implementation."""
288287

289-
def warning(self, format_string, *args):
288+
def warning(self, format_string: str, *args):
290289
"""Dummy implementation."""
291290

292-
def error(self, format_string, *args):
291+
def error(self, format_string: str, *args):
293292
"""Dummy implementation."""
294293

295-
def critical(self, format_string, *args):
294+
def critical(self, format_string: str, *args):
296295
"""Dummy implementation."""

adafruit_logging/extensions.py

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# SPDX-FileCopyrightText: 2021 Alec Delaney for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
"""
6+
`extensions`
7+
====================================================
8+
9+
CircuitPython logging extension for logging to files
10+
11+
* Author(s): Alec Delaney
12+
"""
13+
14+
from . import LoggingHandler
15+
16+
__version__ = "0.0.0-auto.0"
17+
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Logging.git"
18+
19+
20+
class FileHandler(LoggingHandler):
21+
"""File handler for working with log files off of the microcontroller (like
22+
an SD card)
23+
24+
:param filepath: The filepath to the log file
25+
:param mode: Whether to write ('w') or append ('a'); default is to append
26+
"""
27+
28+
def __init__(self, filepath: str, mode: str = "a"):
29+
self.logfile = open( # pylint: disable=consider-using-with
30+
filepath, mode, encoding="utf-8"
31+
)
32+
33+
def close(self):
34+
"""Closes the file"""
35+
self.logfile.close()
36+
37+
def format(self, level: int, msg: str):
38+
"""Generate a string to log
39+
40+
:param level: The level of the message
41+
:param msg: The message to format
42+
"""
43+
return super().format(level, msg) + "\r\n"
44+
45+
def emit(self, level: int, msg: str):
46+
"""Generate the message and write it to the UART.
47+
48+
:param level: The level of the message
49+
:param msg: The message to log
50+
"""
51+
self.logfile.write(self.format(level, msg))

docs/requirements.txt

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries
2+
#
3+
# SPDX-License-Identifier: Unlicense
4+
5+
sphinx>=4.0.0

examples/logging_filehandler.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# SPDX-FileCopyrightText: 2021 Alec Delaney
2+
# SPDX-License-Identifier: MIT
3+
4+
import board
5+
import busio
6+
from digitalio import DigitalInOut
7+
import storage
8+
import adafruit_sdcard
9+
import adafruit_logging as logging
10+
from adafruit_logging.extensions import FileHandler
11+
12+
# Get chip select pin depending on the board, this one is for the Feather M4 Express
13+
sd_cs = board.D10
14+
15+
# Set up an SD card to write to
16+
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
17+
cs = DigitalInOut(sd_cs)
18+
sdcard = adafruit_sdcard.SDCard(spi, cs)
19+
vfs = storage.VfsFat(sdcard)
20+
storage.mount(vfs, "/sd")
21+
22+
# Initialize log functionality
23+
log_filepath = "/sd/testlog.log"
24+
logger = logging.getLogger("testlog")
25+
file_handler = FileHandler(log_filepath)
26+
logger.addHandler(file_handler)
27+
logger.setLevel(logging.INFO)
28+
29+
logger.info("Logger initialized!")
30+
logger.debug("You can even add debug statements to the log!")

0 commit comments

Comments
 (0)