Skip to content

Commit fde1e9c

Browse files
committed
[core,json,orjson,msgspec] Remove use of str_to_object
Fixes: #47
1 parent 1f0cbd0 commit fde1e9c

File tree

7 files changed

+48
-35
lines changed

7 files changed

+48
-35
lines changed

docs/changelog.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,18 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7-
## [UNRELEASED]
7+
## [4.0.0](https://github.com/nhairs/python-json-logger/compare/v3.3.3...v4.0.0) - UNRELEASED
88

99
### Added
1010
- Support `DictConfigurator` prefixes for `rename_fields` and `static_fields`. [#45](https://github.com/nhairs/python-json-logger/pull/45)
1111
- Allows using values like `ext://sys.stderr` in `fileConfig`/`dictConfig` value fields.
1212

13+
### Removed
14+
- Remove support for providing strings instead of objects when instantiating formatters. Instead use the `DictConfigurator` `ext://` prefix format when using `fileConfig`/`dictConfig`. [#47](https://github.com/nhairs/python-json-logger/issues/47)
15+
- Affects `pythonjsonlogger.json.JsonFormatter`: `json_default`, `json_encoder`, `json_serializer`.
16+
- Affects `pythonjsonlogger.orjson.OrjsonFormatter`: `json_default`.
17+
- Affects `pythonjsonlogger.msgspec.MsgspecFormatter`: `json_default`.
18+
1319
Thanks @rubensa
1420

1521
## [3.3.0](https://github.com/nhairs/python-json-logger/compare/v3.2.1...v3.3.0) - 2025-03-06

docs/cookbook.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ formatters:
148148
default:
149149
"()": pythonjsonlogger.json.JsonFormatter
150150
format: "%(asctime)s %(levelname)s %(name)s %(module)s %(funcName)s %(lineno)s %(message)s"
151+
json_default: ext://logging_config.my_json_default
151152
rename_fields:
152153
"asctime": "timestamp"
153154
"levelname": "status"
@@ -185,6 +186,16 @@ import importlib.metadata
185186
import os
186187
187188
189+
class Dummy:
190+
pass
191+
192+
193+
def my_json_default(obj: Any) -> Any:
194+
if isinstance(obj, Dummy):
195+
return "DUMMY"
196+
return obj
197+
198+
188199
def get_version_metadata():
189200
# https://stackoverflow.com/a/78082532
190201
version = importlib.metadata.version(PROJECT_NAME)

src/pythonjsonlogger/core.py

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@
77

88
## Standard Library
99
from datetime import datetime, timezone
10-
import importlib
1110
import logging
1211
import re
1312
import sys
14-
from typing import Optional, Union, Callable, List, Dict, Container, Any, Sequence
13+
from typing import Optional, Union, List, Dict, Container, Any, Sequence
1514

1615
if sys.version_info >= (3, 10):
1716
from typing import TypeAlias
@@ -72,31 +71,12 @@
7271

7372
## Type Aliases
7473
## -----------------------------------------------------------------------------
75-
OptionalCallableOrStr: TypeAlias = Optional[Union[Callable, str]]
76-
"""Type alias"""
77-
7874
LogRecord: TypeAlias = Dict[str, Any]
7975
"""Type alias"""
8076

8177

8278
### FUNCTIONS
8379
### ============================================================================
84-
def str_to_object(obj: Any) -> Any:
85-
"""Import strings to an object, leaving non-strings as-is.
86-
87-
Args:
88-
obj: the object or string to process
89-
90-
*New in 3.1*
91-
"""
92-
93-
if not isinstance(obj, str):
94-
return obj
95-
96-
module_name, attribute_name = obj.rsplit(".", 1)
97-
return getattr(importlib.import_module(module_name), attribute_name)
98-
99-
10080
def merge_record_extra(
10181
record: logging.LogRecord,
10282
target: Dict,

src/pythonjsonlogger/json.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ class JsonFormatter(core.BaseJsonFormatter):
6767
def __init__(
6868
self,
6969
*args,
70-
json_default: core.OptionalCallableOrStr = None,
71-
json_encoder: core.OptionalCallableOrStr = None,
72-
json_serializer: Union[Callable, str] = json.dumps,
70+
json_default: Optional[Callable] = None,
71+
json_encoder: Optional[Callable] = None,
72+
json_serializer: Callable = json.dumps,
7373
json_indent: Optional[Union[int, str]] = None,
7474
json_ensure_ascii: bool = True,
7575
**kwargs,
@@ -87,9 +87,9 @@ def __init__(
8787
"""
8888
super().__init__(*args, **kwargs)
8989

90-
self.json_default = core.str_to_object(json_default)
91-
self.json_encoder = core.str_to_object(json_encoder)
92-
self.json_serializer = core.str_to_object(json_serializer)
90+
self.json_default = json_default
91+
self.json_encoder = json_encoder
92+
self.json_serializer = json_serializer
9393
self.json_indent = json_indent
9494
self.json_ensure_ascii = json_ensure_ascii
9595
if not self.json_encoder and not self.json_default:

src/pythonjsonlogger/msgspec.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from __future__ import annotations
77

88
## Standard Library
9-
from typing import Any
9+
from typing import Any, Optional, Callable
1010

1111
## Installed
1212

@@ -43,7 +43,7 @@ class MsgspecFormatter(core.BaseJsonFormatter):
4343
def __init__(
4444
self,
4545
*args,
46-
json_default: core.OptionalCallableOrStr = msgspec_default,
46+
json_default: Optional[Callable] = msgspec_default,
4747
**kwargs,
4848
) -> None:
4949
"""
@@ -54,7 +54,7 @@ def __init__(
5454
"""
5555
super().__init__(*args, **kwargs)
5656

57-
self.json_default = core.str_to_object(json_default)
57+
self.json_default = json_default
5858
self._encoder = msgspec.json.Encoder(enc_hook=self.json_default)
5959
return
6060

src/pythonjsonlogger/orjson.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from __future__ import annotations
77

88
## Standard Library
9-
from typing import Any
9+
from typing import Any, Optional, Callable
1010

1111
## Installed
1212

@@ -45,7 +45,7 @@ class OrjsonFormatter(core.BaseJsonFormatter):
4545
def __init__(
4646
self,
4747
*args,
48-
json_default: core.OptionalCallableOrStr = orjson_default,
48+
json_default: Optional[Callable] = orjson_default,
4949
json_indent: bool = False,
5050
**kwargs,
5151
) -> None:
@@ -58,7 +58,7 @@ def __init__(
5858
"""
5959
super().__init__(*args, **kwargs)
6060

61-
self.json_default = core.str_to_object(json_default)
61+
self.json_default = json_default
6262
self.json_indent = json_indent
6363
return
6464

tests/test_dictconfig.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,24 @@
1919
_LOGGER_COUNT = 0
2020
EXT_VAL = 999
2121

22+
23+
class Dummy:
24+
pass
25+
26+
27+
def my_json_default(obj: Any) -> Any:
28+
if isinstance(obj, Dummy):
29+
return "DUMMY"
30+
return obj
31+
32+
2233
LOGGING_CONFIG = {
2334
"version": 1,
2435
"disable_existing_loggers": False,
2536
"formatters": {
2637
"default": {
2738
"()": "pythonjsonlogger.json.JsonFormatter",
39+
"json_default": "ext://tests.test_dictconfig.my_json_default",
2840
"static_fields": {"ext-val": "ext://tests.test_dictconfig.EXT_VAL"},
2941
}
3042
},
@@ -73,8 +85,12 @@ def env() -> Generator[LoggingEnvironment, None, None]:
7385
### TESTS
7486
### ============================================================================
7587
def test_external_reference_support(env: LoggingEnvironment):
76-
env.logger.info("hello")
88+
89+
assert logging.root.handlers[0].formatter.json_default is my_json_default # type: ignore[union-attr]
90+
91+
env.logger.info("hello", extra={"dummy": Dummy()})
7792
log_json = env.load_json()
7893

7994
assert log_json["ext-val"] == EXT_VAL
95+
assert log_json["dummy"] == "DUMMY"
8096
return

0 commit comments

Comments
 (0)