python-json-logger 4.0.0rc1__py3-none-any.whl → 4.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,50 +1,26 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-json-logger
3
- Version: 4.0.0rc1
3
+ Version: 4.2.0
4
4
  Summary: JSON Log Formatter for the Python Logging Package
5
5
  Author-email: Zakaria Zajac <zak@madzak.com>, Nicholas Hairs <info+python-json-logger@nicholashairs.com>
6
6
  Maintainer-email: Nicholas Hairs <info+python-json-logger@nicholashairs.com>
7
- License: BSD-2-Clause License
7
+ License-Expression: BSD-2-Clause
8
8
  Project-URL: Homepage, https://nhairs.github.io/python-json-logger
9
9
  Project-URL: GitHub, https://github.com/nhairs/python-json-logger
10
10
  Classifier: Development Status :: 6 - Mature
11
11
  Classifier: Intended Audience :: Developers
12
- Classifier: License :: OSI Approved :: BSD License
13
12
  Classifier: Operating System :: OS Independent
14
13
  Classifier: Programming Language :: Python :: 3 :: Only
15
- Classifier: Programming Language :: Python :: 3.8
16
- Classifier: Programming Language :: Python :: 3.9
17
14
  Classifier: Programming Language :: Python :: 3.10
18
15
  Classifier: Programming Language :: Python :: 3.11
19
16
  Classifier: Programming Language :: Python :: 3.12
20
17
  Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
21
19
  Classifier: Topic :: System :: Logging
22
20
  Classifier: Typing :: Typed
23
- Requires-Python: >=3.8
21
+ Requires-Python: >=3.10
24
22
  Description-Content-Type: text/markdown
25
23
  License-File: LICENSE
26
- License-File: NOTICE
27
- Requires-Dist: typing_extensions; python_version < "3.10"
28
- Provides-Extra: dev
29
- Requires-Dist: orjson; implementation_name != "pypy" and extra == "dev"
30
- Requires-Dist: msgspec; implementation_name != "pypy" and extra == "dev"
31
- Requires-Dist: validate-pyproject[all]; extra == "dev"
32
- Requires-Dist: black; extra == "dev"
33
- Requires-Dist: pylint; extra == "dev"
34
- Requires-Dist: mypy; extra == "dev"
35
- Requires-Dist: pytest; extra == "dev"
36
- Requires-Dist: freezegun; extra == "dev"
37
- Requires-Dist: backports.zoneinfo; python_version < "3.9" and extra == "dev"
38
- Requires-Dist: tzdata; extra == "dev"
39
- Requires-Dist: build; extra == "dev"
40
- Requires-Dist: mkdocs; extra == "dev"
41
- Requires-Dist: mkdocs-material>=8.5; extra == "dev"
42
- Requires-Dist: mkdocs-awesome-pages-plugin; extra == "dev"
43
- Requires-Dist: mdx_truly_sane_lists; extra == "dev"
44
- Requires-Dist: mkdocstrings[python]; extra == "dev"
45
- Requires-Dist: mkdocs-gen-files; extra == "dev"
46
- Requires-Dist: mkdocs-literate-nav; extra == "dev"
47
- Requires-Dist: mike; extra == "dev"
48
24
  Dynamic: license-file
49
25
 
50
26
  [![PyPi](https://img.shields.io/pypi/v/python-json-logger.svg)](https://pypi.python.org/pypi/python-json-logger/)
@@ -0,0 +1,15 @@
1
+ python_json_logger-4.2.0.dist-info/licenses/LICENSE,sha256=GOqVF546Xg4k62zhbED7--IxM8JQKTOi91-KPhoFW1Q,1329
2
+ pythonjsonlogger/__init__.py,sha256=2QcveuId10CyXff_BtJ_6kXIarHT5oq66XHHMFiaE8s,419
3
+ pythonjsonlogger/core.py,sha256=L41AmWK0t5n-QHazXeOlggNX7uzri750i7SFSpeXZ5Q,16268
4
+ pythonjsonlogger/defaults.py,sha256=muj4QzHgUMJH0UwRvgroHKSRfQgHcF9E-EJXhVzAi98,6461
5
+ pythonjsonlogger/exception.py,sha256=r3DXDk7TThscnMVNPpVRaRSFHTnY-ygea6nn-FgjwsI,804
6
+ pythonjsonlogger/json.py,sha256=6aJSqd2BeysAHkQkxb7dPgFpqsFRf4rvWYgaWF2MEC0,4064
7
+ pythonjsonlogger/jsonlogger.py,sha256=sfltkYGwRhRvqcpT-kxlPfcMuOc4ngEa4W4NVTiBpMI,417
8
+ pythonjsonlogger/msgspec.py,sha256=tdFes9rLrdns9I_C5ascK9a265iNc4UccLPzc8JbFDI,2159
9
+ pythonjsonlogger/orjson.py,sha256=XWM-jyl6g_40Em8kt188EOspD872xHvYy8aS_CLlssw,2354
10
+ pythonjsonlogger/py.typed,sha256=4RLptUHQuSqzK6CDbigff8uvWQjwPPQMxikWPkV4OtA,80
11
+ pythonjsonlogger/utils.py,sha256=qr04nb61TkVw7cJTXAtLBfyH_NBvyYUlR_mehH76-RM,1126
12
+ python_json_logger-4.2.0.dist-info/METADATA,sha256=kgcfdHSWOBb_eR3Xg4Or8GzyuDw9HbClYz9cTx4y5GU,2866
13
+ python_json_logger-4.2.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
14
+ python_json_logger-4.2.0.dist-info/top_level.txt,sha256=9G-OsTkbwPgM8t-bXKPmWDBRZv9cbzLIiEDE5EnGk2I,17
15
+ python_json_logger-4.2.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (84.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
pythonjsonlogger/core.py CHANGED
@@ -10,12 +10,8 @@ from datetime import datetime, timezone
10
10
  import logging
11
11
  import re
12
12
  import sys
13
- from typing import Optional, Union, List, Dict, Container, Any, Sequence
14
-
15
- if sys.version_info >= (3, 10):
16
- from typing import TypeAlias
17
- else:
18
- from typing_extensions import TypeAlias
13
+ from typing import TypeAlias, Any
14
+ from collections.abc import Container, Sequence
19
15
 
20
16
  ## Installed
21
17
 
@@ -24,7 +20,7 @@ else:
24
20
 
25
21
  ### CONSTANTS
26
22
  ### ============================================================================
27
- RESERVED_ATTRS: List[str] = [
23
+ RESERVED_ATTRS: list[str] = [
28
24
  "args",
29
25
  "asctime",
30
26
  "created",
@@ -65,13 +61,15 @@ if sys.version_info >= (3, 12):
65
61
  RESERVED_ATTRS.sort()
66
62
 
67
63
 
68
- STYLE_STRING_TEMPLATE_REGEX = re.compile(r"\$\{(.+?)\}", re.IGNORECASE) # $ style
64
+ STYLE_STRING_TEMPLATE_REGEX = re.compile(
65
+ r"\$(?:\$|\{(?P<braced>.+?)\}|(?P<named>[_a-z][_a-z0-9]*))", re.IGNORECASE
66
+ ) # $ style
69
67
  STYLE_STRING_FORMAT_REGEX = re.compile(r"\{(.+?)\}", re.IGNORECASE) # { style
70
68
  STYLE_PERCENT_REGEX = re.compile(r"%\((.+?)\)", re.IGNORECASE) # % style
71
69
 
72
70
  ## Type Aliases
73
71
  ## -----------------------------------------------------------------------------
74
- LogData: TypeAlias = Dict[str, Any]
72
+ LogData: TypeAlias = dict[str, Any]
75
73
  """Type alias
76
74
 
77
75
  *Changed in 4.0*: renamed from `LogRecord` to `LogData`
@@ -82,10 +80,10 @@ LogData: TypeAlias = Dict[str, Any]
82
80
  ### ============================================================================
83
81
  def merge_record_extra(
84
82
  record: logging.LogRecord,
85
- target: Dict,
83
+ target: dict[Any, Any],
86
84
  reserved: Container[str],
87
- rename_fields: Optional[Dict[str, str]] = None,
88
- ) -> Dict:
85
+ rename_fields: dict[str, str] | None = None,
86
+ ) -> dict[Any, Any]:
89
87
  """
90
88
  Merges extra attributes from LogRecord object into target dictionary
91
89
 
@@ -115,31 +113,27 @@ class BaseJsonFormatter(logging.Formatter):
115
113
  Must not be used directly.
116
114
 
117
115
  *New in 3.1*
118
-
119
- *Changed in 3.2*: `defaults` argument is no longer ignored.
120
-
121
- *Added in 3.3*: `exc_info_as_array` and `stack_info_as_array` options are added.
122
116
  """
123
117
 
124
- _style: Union[logging.PercentStyle, str] # type: ignore[assignment]
118
+ _style: logging.PercentStyle | str # type: ignore[assignment]
125
119
 
126
120
  ## Parent Methods
127
121
  ## -------------------------------------------------------------------------
128
122
  # pylint: disable=too-many-arguments,super-init-not-called
129
123
  def __init__(
130
124
  self,
131
- fmt: Optional[Union[str, Sequence[str]]] = None,
132
- datefmt: Optional[str] = None,
125
+ fmt: str | Sequence[str] | None = None,
126
+ datefmt: str | None = None,
133
127
  style: str = "%",
134
128
  validate: bool = True,
135
129
  *,
136
130
  prefix: str = "",
137
- rename_fields: Optional[Dict[str, str]] = None,
131
+ rename_fields: dict[str, str] | None = None,
138
132
  rename_fields_keep_missing: bool = False,
139
- static_fields: Optional[Dict[str, Any]] = None,
140
- reserved_attrs: Optional[Sequence[str]] = None,
141
- timestamp: Union[bool, str] = False,
142
- defaults: Optional[Dict[str, Any]] = None,
133
+ static_fields: dict[str, Any] | None = None,
134
+ reserved_attrs: Sequence[str] | None = None,
135
+ timestamp: bool | str = False,
136
+ defaults: dict[str, Any] | None = None,
143
137
  exc_info_as_array: bool = False,
144
138
  stack_info_as_array: bool = False,
145
139
  ) -> None:
@@ -176,16 +170,19 @@ class BaseJsonFormatter(logging.Formatter):
176
170
  missing fields. The original behaviour, missing fields have a value of `None`, is still
177
171
  available by setting `rename_fields_keep_missing` to `True`.
178
172
 
173
+ *Changed in 3.2*: `defaults` argument is no longer ignored.
174
+
175
+ *Added in 3.3*: `exc_info_as_array` and `stack_info_as_array` options are added.
176
+
179
177
  *Added in 4.0*:
180
178
 
181
- - `fmt` now supports comma seperated lists (`style=","`). Note that this style is specific
179
+ - `fmt` now supports comma separated lists (`style=","`). Note that this style is specific
182
180
  to `python-json-logger` and thus care should be taken to not to pass this format to other
183
181
  logging Formatter implementations.
184
182
  - `fmt` now supports sequences of strings (e.g. lists and tuples) of field names.
185
183
  """
186
184
  ## logging.Formatter compatibility
187
185
  ## ---------------------------------------------------------------------
188
- # Note: validate added in python 3.8, defaults added in 3.10
189
186
  if fmt is None or isinstance(fmt, str):
190
187
  if style in logging._STYLES:
191
188
  _style = logging._STYLES[style][0](fmt) # type: ignore[operator]
@@ -240,14 +237,20 @@ class BaseJsonFormatter(logging.Formatter):
240
237
  def format(self, record: logging.LogRecord) -> str:
241
238
  """Formats a log record and serializes to json
242
239
 
240
+ When `record.msg` is a `dict`, adding `exc_info` and `stack_info` does not
241
+ modify the caller's dict.
242
+
243
243
  Args:
244
244
  record: the record to format
245
+
246
+ *Changed in 4.2.0*: a `dict` `record.msg` is copied instead of modified
247
+ in place.
245
248
  """
246
- message_dict: Dict[str, Any] = {}
249
+ message_dict: dict[str, Any] = {}
247
250
  # TODO: logging.LogRecord.msg and logging.LogRecord.message in typeshed
248
251
  # are always type of str. We shouldn't need to override that.
249
252
  if isinstance(record.msg, dict):
250
- message_dict = record.msg
253
+ message_dict = record.msg.copy()
251
254
  record.message = ""
252
255
  else:
253
256
  record.message = record.getMessage()
@@ -276,7 +279,7 @@ class BaseJsonFormatter(logging.Formatter):
276
279
 
277
280
  ## JSON Formatter Specific Methods
278
281
  ## -------------------------------------------------------------------------
279
- def parse(self) -> List[str]:
282
+ def parse(self) -> list[str]:
280
283
  """Parses format string looking for substitutions
281
284
 
282
285
  This method is responsible for returning a list of fields (as strings)
@@ -300,20 +303,22 @@ class BaseJsonFormatter(logging.Formatter):
300
303
  raise ValueError(f"Style {self._style!r} is not supported")
301
304
 
302
305
  if isinstance(self._style, logging.StringTemplateStyle):
303
- formatter_style_pattern = STYLE_STRING_TEMPLATE_REGEX
306
+ # String templates support both ${name} and $name, and $$ is an escaped literal
307
+ return [
308
+ match.group("braced") or match.group("named")
309
+ for match in STYLE_STRING_TEMPLATE_REGEX.finditer(self._fmt)
310
+ if match.group("braced") or match.group("named")
311
+ ]
304
312
 
305
- elif isinstance(self._style, logging.StrFormatStyle):
306
- formatter_style_pattern = STYLE_STRING_FORMAT_REGEX
313
+ if isinstance(self._style, logging.StrFormatStyle):
314
+ return STYLE_STRING_FORMAT_REGEX.findall(self._fmt)
307
315
 
308
- elif isinstance(self._style, logging.PercentStyle):
316
+ if isinstance(self._style, logging.PercentStyle):
309
317
  # PercentStyle is parent class of StringTemplateStyle and StrFormatStyle
310
318
  # so it must be checked last.
311
- formatter_style_pattern = STYLE_PERCENT_REGEX
312
-
313
- else:
314
- raise ValueError(f"Style {self._style!r} is not supported")
319
+ return STYLE_PERCENT_REGEX.findall(self._fmt)
315
320
 
316
- return formatter_style_pattern.findall(self._fmt)
321
+ raise ValueError(f"Style {self._style!r} is not supported")
317
322
 
318
323
  def serialize_log_record(self, log_data: LogData) -> str:
319
324
  """Returns the final representation of the data to be logged
@@ -327,9 +332,9 @@ class BaseJsonFormatter(logging.Formatter):
327
332
 
328
333
  def add_fields(
329
334
  self,
330
- log_data: Dict[str, Any],
335
+ log_data: dict[str, Any],
331
336
  record: logging.LogRecord,
332
- message_dict: Dict[str, Any],
337
+ message_dict: dict[str, Any],
333
338
  ) -> None:
334
339
  """Extract fields from a LogRecord for logging
335
340
 
@@ -402,7 +407,7 @@ class BaseJsonFormatter(logging.Formatter):
402
407
  """
403
408
  return log_data
404
409
 
405
- def formatException(self, ei) -> Union[str, list[str]]: # type: ignore
410
+ def formatException(self, ei) -> str | list[str]: # type: ignore[override]
406
411
  """Format and return the specified exception information.
407
412
 
408
413
  If exc_info_as_array is set to True, This method returns an array of strings.
@@ -410,7 +415,7 @@ class BaseJsonFormatter(logging.Formatter):
410
415
  exception_info_str = super().formatException(ei)
411
416
  return exception_info_str.splitlines() if self.exc_info_as_array else exception_info_str
412
417
 
413
- def formatStack(self, stack_info) -> Union[str, list[str]]: # type: ignore
418
+ def formatStack(self, stack_info) -> str | list[str]: # type: ignore[override]
414
419
  """Format and return the specified stack information.
415
420
 
416
421
  If stack_info_as_array is set to True, This method returns an array of strings.
@@ -16,17 +16,11 @@ import base64
16
16
  import dataclasses
17
17
  import datetime
18
18
  import enum
19
- import sys
20
19
  from types import TracebackType
21
- from typing import Any
20
+ from typing import Any, TypeGuard
22
21
  import traceback
23
22
  import uuid
24
23
 
25
- if sys.version_info >= (3, 10):
26
- from typing import TypeGuard
27
- else:
28
- from typing_extensions import TypeGuard
29
-
30
24
  ## Installed
31
25
 
32
26
  ## Application
pythonjsonlogger/json.py CHANGED
@@ -12,7 +12,8 @@ from __future__ import annotations
12
12
  ## Standard Library
13
13
  import datetime
14
14
  import json
15
- from typing import Any, Callable, Optional, Union
15
+ from typing import Any
16
+ from collections.abc import Callable
16
17
  import warnings
17
18
 
18
19
  ## Application
@@ -67,10 +68,10 @@ class JsonFormatter(core.BaseJsonFormatter):
67
68
  def __init__(
68
69
  self,
69
70
  *args,
70
- json_default: Optional[Callable] = None,
71
- json_encoder: Optional[Callable] = None,
71
+ json_default: Callable | None = None,
72
+ json_encoder: Callable | None = None,
72
73
  json_serializer: Callable = json.dumps,
73
- json_indent: Optional[Union[int, str]] = None,
74
+ json_indent: int | str | None = None,
74
75
  json_ensure_ascii: bool = True,
75
76
  **kwargs,
76
77
  ) -> None:
@@ -6,7 +6,8 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  ## Standard Library
9
- from typing import Any, Optional, Callable
9
+ from typing import Any
10
+ from collections.abc import Callable
10
11
 
11
12
  ## Installed
12
13
 
@@ -43,7 +44,7 @@ class MsgspecFormatter(core.BaseJsonFormatter):
43
44
  def __init__(
44
45
  self,
45
46
  *args,
46
- json_default: Optional[Callable] = msgspec_default,
47
+ json_default: Callable | None = msgspec_default,
47
48
  **kwargs,
48
49
  ) -> None:
49
50
  """
@@ -6,7 +6,8 @@
6
6
  from __future__ import annotations
7
7
 
8
8
  ## Standard Library
9
- from typing import Any, Optional, Callable
9
+ from typing import Any
10
+ from collections.abc import Callable
10
11
 
11
12
  ## Installed
12
13
 
@@ -15,7 +16,7 @@ from . import core
15
16
  from . import defaults as d
16
17
  from .utils import package_is_available
17
18
 
18
- # We import msgspec after checking it is available
19
+ # We import orjson after checking it is available
19
20
  package_is_available("orjson", throw_error=True)
20
21
  import orjson # pylint: disable=wrong-import-position,wrong-import-order
21
22
 
@@ -45,7 +46,7 @@ class OrjsonFormatter(core.BaseJsonFormatter):
45
46
  def __init__(
46
47
  self,
47
48
  *args,
48
- json_default: Optional[Callable] = orjson_default,
49
+ json_default: Callable | None = orjson_default,
49
50
  json_indent: bool = False,
50
51
  **kwargs,
51
52
  ) -> None:
@@ -1,16 +0,0 @@
1
- python_json_logger-4.0.0rc1.dist-info/licenses/LICENSE,sha256=GOqVF546Xg4k62zhbED7--IxM8JQKTOi91-KPhoFW1Q,1329
2
- python_json_logger-4.0.0rc1.dist-info/licenses/NOTICE,sha256=uRQnFcGZCwuIBR2AIHVvhKi9w1KkiI_vAyralfxCsk4,209
3
- pythonjsonlogger/__init__.py,sha256=2QcveuId10CyXff_BtJ_6kXIarHT5oq66XHHMFiaE8s,419
4
- pythonjsonlogger/core.py,sha256=7n2y-jUpLO_D826OYq0eA8u4PAQcKr3vJWeQbsP604E,15988
5
- pythonjsonlogger/defaults.py,sha256=-XgxIj8ioq7CsnBBMsQhTRpU-lKbLrpQLJTCaT3iH38,6577
6
- pythonjsonlogger/exception.py,sha256=r3DXDk7TThscnMVNPpVRaRSFHTnY-ygea6nn-FgjwsI,804
7
- pythonjsonlogger/json.py,sha256=jiVE029rsnuXUUNghNwHaWsuQQ6rSZGRHVx8FKvVV_c,4069
8
- pythonjsonlogger/jsonlogger.py,sha256=sfltkYGwRhRvqcpT-kxlPfcMuOc4ngEa4W4NVTiBpMI,417
9
- pythonjsonlogger/msgspec.py,sha256=xZLqPwS8MqjtOwdnMY8tgCq5yMtKaytY5tXEV_YLhLo,2145
10
- pythonjsonlogger/orjson.py,sha256=Fd8eurRQsMZ6JB9zdClfjogWJ5J15NOTsbjH7p9jzsE,2341
11
- pythonjsonlogger/py.typed,sha256=4RLptUHQuSqzK6CDbigff8uvWQjwPPQMxikWPkV4OtA,80
12
- pythonjsonlogger/utils.py,sha256=qr04nb61TkVw7cJTXAtLBfyH_NBvyYUlR_mehH76-RM,1126
13
- python_json_logger-4.0.0rc1.dist-info/METADATA,sha256=B9XwbhoBT005SoTqtLmq71eJXnRQ0KtLMKvO_NT9L50,3994
14
- python_json_logger-4.0.0rc1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
- python_json_logger-4.0.0rc1.dist-info/top_level.txt,sha256=9G-OsTkbwPgM8t-bXKPmWDBRZv9cbzLIiEDE5EnGk2I,17
16
- python_json_logger-4.0.0rc1.dist-info/RECORD,,
@@ -1,5 +0,0 @@
1
- This software includes the following licenced software:
2
- - mkdocstrings-python
3
- Copyright (c) 2021, Timothée Mazzucotelli
4
- Licenced under ISC Licence
5
- Source: https://github.com/mkdocstrings/python