Skip to content

Commit 75e6e48

Browse files
fix: attribute error when logging non-strings (python-semantic-release#711)
1 parent 6b288f2 commit 75e6e48

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

semantic_release/cli/masking_filter.py

+5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ def filter(self, record: logging.LogRecord) -> bool:
5757
return True
5858

5959
def mask(self, msg: str) -> str:
60+
if not isinstance(msg, str):
61+
log.debug( # type: ignore[unreachable]
62+
"cannot mask object of type %s", type(msg)
63+
)
64+
return msg
6065
for mask, values in self._redact_patterns.items():
6166
repl_string = (
6267
self.REPLACE_STR

tests/unit/semantic_release/cli/test_masking_filter.py

+42-15
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,25 @@ def default_masking_filter():
2727
return MaskingFilter()
2828

2929

30+
@pytest.fixture
31+
def logging_output_stream():
32+
return io.StringIO()
33+
34+
35+
@pytest.fixture
36+
def logger(logging_output_stream, default_masking_filter):
37+
root = logging.getLogger()
38+
root.setLevel(logging.DEBUG)
39+
root.addHandler(logging.StreamHandler(logging_output_stream))
40+
log = logging.getLogger(__name__)
41+
log.setLevel(logging.DEBUG)
42+
43+
for h in root.handlers:
44+
h.addFilter(default_masking_filter)
45+
46+
return log
47+
48+
3049
@pytest.mark.parametrize(
3150
"unwanted", [f(obj) for f in (repr, str) for obj in ("", None)]
3251
)
@@ -183,24 +202,32 @@ def test_log_record_is_masked_with_nontrivial_args(default_masking_filter, rec,
183202
logging.CRITICAL,
184203
),
185204
)
186-
def test_log_messages_are_masked(default_masking_filter, log_level, tmp_path):
187-
buffer = io.StringIO()
188-
189-
root = logging.getLogger()
190-
root.setLevel(logging.DEBUG)
191-
root.addHandler(logging.StreamHandler(buffer))
192-
log = logging.getLogger(__name__)
193-
log.setLevel(logging.DEBUG)
194-
195-
for h in root.handlers:
196-
h.addFilter(default_masking_filter)
197-
205+
def test_log_messages_are_masked(
206+
default_masking_filter, log_level, logging_output_stream, logger, tmp_path
207+
):
198208
for secret in _secrets:
199209
default_masking_filter.add_mask_for(secret)
200210

201-
log.log(log_level, ", ".join("%s" for _ in _secrets), *_secrets)
202-
for h in (*root.handlers, *log.handlers):
211+
logger.log(log_level, ", ".join("%s" for _ in _secrets), *_secrets)
212+
213+
root = logging.getLogger()
214+
for h in (*root.handlers, *logger.handlers):
203215
h.flush()
204216

205-
written = buffer.getvalue()
217+
written = logging_output_stream.getvalue()
206218
assert all(secret not in written for secret in _secrets)
219+
220+
221+
@pytest.mark.parametrize("obj", (object(), (), {}, AttributeError("whoopsie")))
222+
def test_non_strings_are_returned(default_masking_filter, obj):
223+
rec = LogRecord(
224+
name=__name__,
225+
level=logging.INFO,
226+
pathname=__file__,
227+
lineno=10,
228+
args=(),
229+
msg=obj,
230+
exc_info=None,
231+
)
232+
233+
assert default_masking_filter.mask(rec.getMessage()) == str(obj)

0 commit comments

Comments
 (0)