diff --git a/annotated_logger/__init__.py b/annotated_logger/__init__.py index 4e0bfd4..ecac8be 100644 --- a/annotated_logger/__init__.py +++ b/annotated_logger/__init__.py @@ -33,7 +33,7 @@ # https://test.pypi.org/project/annotated-logger/ # The dev versions in testpypi can then be pulled in to whatever project needed # the new feature. -VERSION = "1.2.4" # pragma: no mutate +VERSION = "1.3.0" # pragma: no mutate T = TypeVar("T") P = ParamSpec("P") @@ -653,7 +653,7 @@ def annotate_logs( # Between the overloads and the two inner method definitions, # there's not much I can do to reduce the complexity more. # So, ignoring the complexity metric - def annotate_logs( # noqa: C901 + def annotate_logs( # noqa: C901 PLR0915 self, logger_name: str | None = None, *, @@ -787,6 +787,10 @@ def wrap_function(*args: P.args, **kwargs: P.kwargs) -> R: if post_call and not post_call_attempted: _attempt_post_call(post_call, logger, *new_args, **new_kwargs) # pyright: ignore[reportCallIssue] raise + finally: + # Remove the logger now that we are done with it, + # otherwise they build up and eat memory + logging.root.manager.loggerDict.pop(logger.logger.name, None) return result return wrap_function diff --git a/example/calculator.py b/example/calculator.py index bcca52e..1f0aa2e 100644 --- a/example/calculator.py +++ b/example/calculator.py @@ -148,7 +148,6 @@ def power( @annotate_logs(success_info=False, _typing_requested=True) def add(self, annotated_logger: AnnotatedAdapter) -> Number: - # def add(self, *args, annotated_logger: AnnotatedAdapter) -> Number: """Add self.first and self.second.""" annotated_logger.annotate(first=self.first, second=self.second, foo="bar") diff --git a/requirements/requirements-dev.txt b/requirements/requirements-dev.txt index c61e6e5..72a72fe 100644 --- a/requirements/requirements-dev.txt +++ b/requirements/requirements-dev.txt @@ -9,6 +9,7 @@ # - pytest-cov # - pytest-freezer # - pytest-github-actions-annotate-failures +# - pytest-memray # - pytest-mock # - pytest-randomly # - requests-mock @@ -44,6 +45,8 @@ idna==3.10 # via requests iniconfig==2.1.0 # via pytest +jinja2==3.1.6 + # via memray libcst==1.7.0 # via mutmut linkify-it-py==2.0.3 @@ -55,10 +58,14 @@ markdown-it-py==4.0.0 # mdit-py-plugins # rich # textual +markupsafe==3.0.3 + # via jinja2 mdit-py-plugins==0.5.0 # via markdown-it-py mdurl==0.1.2 # via markdown-it-py +memray==1.19.1 + # via pytest-memray mutmut==3.3.1 # via hatch.envs.dev nodeenv==1.9.1 @@ -93,6 +100,7 @@ pytest==8.4.2 # pytest-cov # pytest-freezer # pytest-github-actions-annotate-failures + # pytest-memray # pytest-mock # pytest-randomly pytest-cov==7.0.0 @@ -101,6 +109,8 @@ pytest-freezer==0.4.9 # via hatch.envs.dev pytest-github-actions-annotate-failures==0.3.0 # via hatch.envs.dev +pytest-memray==1.8.0 + # via hatch.envs.dev pytest-mock==3.15.1 # via hatch.envs.dev pytest-randomly==4.0.1 @@ -120,7 +130,9 @@ requests==2.32.5 requests-mock==1.12.1 # via hatch.envs.dev rich==14.2.0 - # via textual + # via + # memray + # textual ruff==0.14.0 # via hatch.envs.dev setproctitle==1.3.7 @@ -128,7 +140,9 @@ setproctitle==1.3.7 six==1.17.0 # via python-dateutil textual==6.2.1 - # via mutmut + # via + # memray + # mutmut typing-extensions==4.15.0 # via # hatch.envs.dev diff --git a/test/test_memory.py b/test/test_memory.py new file mode 100644 index 0000000..9c09840 --- /dev/null +++ b/test/test_memory.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +import contextlib +import logging + +import pytest + +import example.calculator + + +class TestMemory: + @pytest.mark.parametrize("denominator", [2, 0]) + def test_repeated_calls_do_not_accumulate_loggers(self, denominator): + calc = example.calculator.Calculator(1, denominator) + starting_loggers = len(logging.root.manager.loggerDict) + for _ in range(1000): + with contextlib.suppress(ZeroDivisionError): + calc.divide() + + ending_loggers = len(logging.root.manager.loggerDict) + assert starting_loggers == ending_loggers