Skip to content

Commit 5d3c405

Browse files
authored
Merge pull request #83 from github/memory-buildup
Clean up loggers in root manager's loggerDict to prevent memory buildup
2 parents 06392b3 + f540611 commit 5d3c405

File tree

4 files changed

+43
-5
lines changed

4 files changed

+43
-5
lines changed

annotated_logger/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
# https://test.pypi.org/project/annotated-logger/
3434
# The dev versions in testpypi can then be pulled in to whatever project needed
3535
# the new feature.
36-
VERSION = "1.2.4" # pragma: no mutate
36+
VERSION = "1.3.0" # pragma: no mutate
3737

3838
T = TypeVar("T")
3939
P = ParamSpec("P")
@@ -653,7 +653,7 @@ def annotate_logs(
653653
# Between the overloads and the two inner method definitions,
654654
# there's not much I can do to reduce the complexity more.
655655
# So, ignoring the complexity metric
656-
def annotate_logs( # noqa: C901
656+
def annotate_logs( # noqa: C901 PLR0915
657657
self,
658658
logger_name: str | None = None,
659659
*,
@@ -787,6 +787,10 @@ def wrap_function(*args: P.args, **kwargs: P.kwargs) -> R:
787787
if post_call and not post_call_attempted:
788788
_attempt_post_call(post_call, logger, *new_args, **new_kwargs) # pyright: ignore[reportCallIssue]
789789
raise
790+
finally:
791+
# Remove the logger now that we are done with it,
792+
# otherwise they build up and eat memory
793+
logging.root.manager.loggerDict.pop(logger.logger.name, None)
790794
return result
791795

792796
return wrap_function

example/calculator.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,6 @@ def power(
148148

149149
@annotate_logs(success_info=False, _typing_requested=True)
150150
def add(self, annotated_logger: AnnotatedAdapter) -> Number:
151-
# def add(self, *args, annotated_logger: AnnotatedAdapter) -> Number:
152151
"""Add self.first and self.second."""
153152
annotated_logger.annotate(first=self.first, second=self.second, foo="bar")
154153

requirements/requirements-dev.txt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
# - pytest-cov
1010
# - pytest-freezer
1111
# - pytest-github-actions-annotate-failures
12+
# - pytest-memray
1213
# - pytest-mock
1314
# - pytest-randomly
1415
# - requests-mock
@@ -44,6 +45,8 @@ idna==3.10
4445
# via requests
4546
iniconfig==2.1.0
4647
# via pytest
48+
jinja2==3.1.6
49+
# via memray
4750
libcst==1.7.0
4851
# via mutmut
4952
linkify-it-py==2.0.3
@@ -55,10 +58,14 @@ markdown-it-py==4.0.0
5558
# mdit-py-plugins
5659
# rich
5760
# textual
61+
markupsafe==3.0.3
62+
# via jinja2
5863
mdit-py-plugins==0.5.0
5964
# via markdown-it-py
6065
mdurl==0.1.2
6166
# via markdown-it-py
67+
memray==1.19.1
68+
# via pytest-memray
6269
mutmut==3.3.1
6370
# via hatch.envs.dev
6471
nodeenv==1.9.1
@@ -93,6 +100,7 @@ pytest==8.4.2
93100
# pytest-cov
94101
# pytest-freezer
95102
# pytest-github-actions-annotate-failures
103+
# pytest-memray
96104
# pytest-mock
97105
# pytest-randomly
98106
pytest-cov==7.0.0
@@ -101,6 +109,8 @@ pytest-freezer==0.4.9
101109
# via hatch.envs.dev
102110
pytest-github-actions-annotate-failures==0.3.0
103111
# via hatch.envs.dev
112+
pytest-memray==1.8.0
113+
# via hatch.envs.dev
104114
pytest-mock==3.15.1
105115
# via hatch.envs.dev
106116
pytest-randomly==4.0.1
@@ -120,15 +130,19 @@ requests==2.32.5
120130
requests-mock==1.12.1
121131
# via hatch.envs.dev
122132
rich==14.2.0
123-
# via textual
133+
# via
134+
# memray
135+
# textual
124136
ruff==0.14.0
125137
# via hatch.envs.dev
126138
setproctitle==1.3.7
127139
# via mutmut
128140
six==1.17.0
129141
# via python-dateutil
130142
textual==6.2.1
131-
# via mutmut
143+
# via
144+
# memray
145+
# mutmut
132146
typing-extensions==4.15.0
133147
# via
134148
# hatch.envs.dev

test/test_memory.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from __future__ import annotations
2+
3+
import contextlib
4+
import logging
5+
6+
import pytest
7+
8+
import example.calculator
9+
10+
11+
class TestMemory:
12+
@pytest.mark.parametrize("denominator", [2, 0])
13+
def test_repeated_calls_do_not_accumulate_loggers(self, denominator):
14+
calc = example.calculator.Calculator(1, denominator)
15+
starting_loggers = len(logging.root.manager.loggerDict)
16+
for _ in range(1000):
17+
with contextlib.suppress(ZeroDivisionError):
18+
calc.divide()
19+
20+
ending_loggers = len(logging.root.manager.loggerDict)
21+
assert starting_loggers == ending_loggers

0 commit comments

Comments
 (0)