Skip to content

Commit 661269e

Browse files
committed
feature/type-checker-compatible-with-mypy
1 parent c0e1ffb commit 661269e

File tree

6 files changed

+437
-329
lines changed

6 files changed

+437
-329
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ __pycache__
66
/.tox
77
/.cache
88
/JSON_log_formatter.egg-info
9+
.mypy_cache/

.pre-commit-config.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
repos:
2+
- repo: https://github.com/pre-commit/mirrors-mypy
3+
rev: v1.9.0
4+
hooks:
5+
- id: mypy
6+
args: [--strict, --ignore-missing-imports]
7+
additional_dependencies: []
8+
# If your project uses third-party packages, add them here:
9+
# additional_dependencies:
10+
# - types-requests
11+
# - types-python-dateutil
12+
13+
- repo: https://github.com/psf/black
14+
rev: 24.3.0
15+
hooks:
16+
- id: black
17+
args: [--line-length=88]
18+
19+
- repo: https://github.com/PyCQA/isort
20+
rev: 5.13.2
21+
hooks:
22+
- id: isort
23+
args: ["--profile", "black", "--filter-files"]
24+
25+
- repo: https://github.com/PyCQA/flake8
26+
rev: 7.0.0
27+
hooks:
28+
- id: flake8
29+
additional_dependencies: [flake8-bugbear]
30+
31+
- repo: https://github.com/asottile/pyupgrade
32+
rev: v3.15.1
33+
hooks:
34+
- id: pyupgrade
35+
args: [--py37-plus]

json_log_formatter/__init__.py

Lines changed: 79 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,37 @@
1+
from __future__ import annotations # backward compatibility
2+
13
import logging
2-
from decimal import Decimal
34
from datetime import datetime, timezone
4-
5+
from decimal import Decimal
56
import json
6-
7-
BUILTIN_ATTRS = {
8-
'args',
9-
'asctime',
10-
'created',
11-
'exc_info',
12-
'exc_text',
13-
'filename',
14-
'funcName',
15-
'levelname',
16-
'levelno',
17-
'lineno',
18-
'module',
19-
'msecs',
20-
'message',
21-
'msg',
22-
'name',
23-
'pathname',
24-
'process',
25-
'processName',
26-
'relativeCreated',
27-
'stack_info',
28-
'taskName',
29-
'thread',
30-
'threadName',
7+
from types import ModuleType
8+
from typing import Any, Optional, Dict
9+
10+
11+
BUILTIN_ATTRS: set[str] = {
12+
"args",
13+
"asctime",
14+
"created",
15+
"exc_info",
16+
"exc_text",
17+
"filename",
18+
"funcName",
19+
"levelname",
20+
"levelno",
21+
"lineno",
22+
"module",
23+
"msecs",
24+
"message",
25+
"msg",
26+
"name",
27+
"pathname",
28+
"process",
29+
"processName",
30+
"relativeCreated",
31+
"stack_info",
32+
"taskName",
33+
"thread",
34+
"threadName",
3135
}
3236

3337

@@ -58,21 +62,21 @@ class JSONFormatter(logging.Formatter):
5862
5963
"""
6064

61-
json_lib = json
65+
json_lib: ModuleType = json
6266

63-
def format(self, record):
64-
message = record.getMessage()
65-
extra = self.extra_from_record(record)
66-
json_record = self.json_record(message, extra, record)
67-
mutated_record = self.mutate_json_record(json_record)
67+
def format(self, record: logging.LogRecord) -> Any | str:
68+
message: str = record.getMessage()
69+
extra: dict[str, Any] = self.extra_from_record(record)
70+
json_record: dict[str, Any] = self.json_record(message, extra, record)
71+
mutated_record: Optional[dict[str, Any]] = self.mutate_json_record(json_record)
6872
# Backwards compatibility: Functions that overwrite this but don't
6973
# return a new value will return None because they modified the
7074
# argument passed in.
7175
if mutated_record is None:
7276
mutated_record = json_record
7377
return self.to_json(mutated_record)
7478

75-
def to_json(self, record):
79+
def to_json(self, record: dict[str, Any]) -> Any | str:
7680
"""Converts record dict to a JSON string.
7781
7882
It makes best effort to serialize a record (represents an object as a string)
@@ -93,9 +97,9 @@ def to_json(self, record):
9397
try:
9498
return self.json_lib.dumps(record)
9599
except (TypeError, ValueError, OverflowError):
96-
return '{}'
100+
return "{}"
97101

98-
def extra_from_record(self, record):
102+
def extra_from_record(self, record: logging.LogRecord) -> dict[str, Any]:
99103
"""Returns `extra` dict you passed to logger.
100104
101105
The `extra` keyword argument is used to populate the `__dict__` of
@@ -108,7 +112,9 @@ def extra_from_record(self, record):
108112
if attr_name not in BUILTIN_ATTRS
109113
}
110114

111-
def json_record(self, message, extra, record):
115+
def json_record(
116+
self, message: str, extra: dict[str, Any], record: logging.LogRecord
117+
) -> dict[str, Any]:
112118
"""Prepares a JSON payload which will be logged.
113119
114120
Override this method to change JSON log format.
@@ -120,16 +126,18 @@ def json_record(self, message, extra, record):
120126
:return: Dictionary which will be passed to JSON lib.
121127
122128
"""
123-
extra['message'] = message
124-
if 'time' not in extra:
125-
extra['time'] = datetime.now(timezone.utc)
129+
extra["message"] = message
130+
if "time" not in extra:
131+
extra["time"] = datetime.now(timezone.utc)
126132

127133
if record.exc_info:
128-
extra['exc_info'] = self.formatException(record.exc_info)
134+
extra["exc_info"] = self.formatException(record.exc_info)
129135

130136
return extra
131137

132-
def mutate_json_record(self, json_record):
138+
def mutate_json_record(
139+
self, json_record: dict[str, Any]
140+
) -> Optional[Dict[str, Any]]:
133141
"""Override it to convert fields of `json_record` to needed types.
134142
135143
Default implementation converts `datetime` to string in ISO8601 format.
@@ -142,7 +150,7 @@ def mutate_json_record(self, json_record):
142150
return json_record
143151

144152

145-
def _json_serializable(obj):
153+
def _json_serializable(obj: Any) -> Any:
146154
try:
147155
return obj.__dict__
148156
except AttributeError:
@@ -189,23 +197,29 @@ class VerboseJSONFormatter(JSONFormatter):
189197
https://docs.python.org/3/library/logging.html#logrecord-attributes.
190198
191199
"""
192-
def json_record(self, message, extra, record):
193-
extra['filename'] = record.filename
194-
extra['funcName'] = record.funcName
195-
extra['levelname'] = record.levelname
196-
extra['lineno'] = record.lineno
197-
extra['module'] = record.module
198-
extra['name'] = record.name
199-
extra['pathname'] = record.pathname
200-
extra['process'] = record.process
201-
extra['processName'] = record.processName
202-
if hasattr(record, 'stack_info'):
203-
extra['stack_info'] = record.stack_info
204-
else:
205-
extra['stack_info'] = None
206-
extra['thread'] = record.thread
207-
extra['threadName'] = record.threadName
208-
return super(VerboseJSONFormatter, self).json_record(message, extra, record)
200+
201+
def json_record(
202+
self, message: str, extra: dict[str, Any], record: logging.LogRecord
203+
) -> dict[str, Any]:
204+
extra.update(
205+
{
206+
"filename": record.filename,
207+
"funcName": record.funcName,
208+
"levelname": record.levelname,
209+
"lineno": record.lineno,
210+
"module": record.module,
211+
"name": record.name,
212+
"pathname": record.pathname,
213+
"process": record.process,
214+
"processName": record.processName,
215+
"stack_info": record.stack_info
216+
if hasattr(record, "stack_info")
217+
else None,
218+
"thread": record.thread,
219+
"threadName": record.threadName,
220+
}
221+
)
222+
return super().json_record(message, extra, record)
209223

210224

211225
class FlatJSONFormatter(JSONFormatter):
@@ -230,10 +244,12 @@ class FlatJSONFormatter(JSONFormatter):
230244
231245
"""
232246

233-
keep = (bool, int, float, Decimal, complex, str, datetime)
247+
keep: tuple[type, ...] = (bool, int, float, Decimal, complex, str, datetime)
234248

235-
def json_record(self, message, extra, record):
236-
extra = super(FlatJSONFormatter, self).json_record(message, extra, record)
249+
def json_record(
250+
self, message: str, extra: dict[str, Any], record: logging.LogRecord
251+
) -> dict[str, Any]:
252+
extra = super().json_record(message, extra, record)
237253
return {
238254
k: v if v is None or isinstance(v, self.keep) else str(v)
239255
for k, v in extra.items()

mypy.ini

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[mypy]
2+
python_version = 3.11
3+
# To recognize all the files
4+
files = ['__init__.py', 'tests.py', 'setup.py' ]
5+
strict = True
6+
check_untyped_defs = True
7+
disallow_untyped_defs = True
8+
disallow_incomplete_defs = True
9+
no_implicit_optional = True
10+
warn_redundant_casts = True
11+
warn_unused_ignores = True
12+
show_error_codes = True
13+
show_column_numbers = True
14+
ignore_missing_imports = False

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from setuptools import setup
1+
from setuptools import setup # type: ignore
22

33
setup(
44
name='JSON-log-formatter',

0 commit comments

Comments
 (0)