Skip to content

Commit 5588326

Browse files
committed
Initial fixes with weak references
1 parent 670bbee commit 5588326

File tree

3 files changed

+40
-5
lines changed

3 files changed

+40
-5
lines changed

ignite/engine/engine.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,8 @@ def execute_something():
328328

329329
try:
330330
_check_signature(handler, "handler", self, *(event_args + args), **kwargs)
331-
self._event_handlers[event_name].append((handler, (self,) + args, kwargs))
331+
# Use weak reference to break circular reference
332+
self._event_handlers[event_name].append((handler, (weakref.ref(self),) + args, kwargs))
332333
except ValueError:
333334
_check_signature(handler, "handler", *(event_args + args), **kwargs)
334335
self._event_handlers[event_name].append((handler, args, kwargs))
@@ -432,7 +433,15 @@ def _fire_event(self, event_name: Any, *event_args: Any, **event_kwargs: Any) ->
432433
self.last_event_name = event_name
433434
for func, args, kwargs in self._event_handlers[event_name]:
434435
kwargs.update(event_kwargs)
435-
first, others = ((args[0],), args[1:]) if (args and args[0] == self) else ((), args)
436+
# Resolve weak references if present
437+
if args and isinstance(args[0], weakref.ref):
438+
resolved_engine = args[0]()
439+
if resolved_engine is None:
440+
# Engine was garbage collected, skip this handler
441+
continue
442+
first, others = ((resolved_engine,), args[1:])
443+
else:
444+
first, others = ((args[0],), args[1:]) if (args and args[0] == self) else (tuple(), args)
436445
func(*first, *(event_args + others), **kwargs)
437446

438447
def fire_event(self, event_name: Any) -> None:

ignite/handlers/base_logger.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import collections.abc as collections
44
import numbers
55
import warnings
6+
import weakref
67
from abc import ABCMeta, abstractmethod
78
from collections import OrderedDict
89
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union
@@ -261,18 +262,34 @@ def attach(
261262
:class:`~ignite.engine.events.RemovableEventHandle`, which can be used to remove the handler.
262263
"""
263264
if isinstance(event_name, EventsList):
265+
# Use weak reference to break circular reference: engine -> _event_handlers -> BaseLogger
266+
weak_self = weakref.ref(self)
267+
268+
def weak_log_handler(engine, event_name):
269+
logger_obj = weak_self()
270+
if logger_obj is not None:
271+
log_handler(engine, logger_obj, event_name)
272+
264273
for name in event_name:
265274
if name not in State.event_to_attr:
266275
raise RuntimeError(f"Unknown event name '{name}'")
267-
engine.add_event_handler(name, log_handler, self, name)
276+
engine.add_event_handler(name, weak_log_handler, name)
268277

269278
return RemovableEventHandle(event_name, log_handler, engine)
270279

271280
else:
272281
if event_name not in State.event_to_attr:
273282
raise RuntimeError(f"Unknown event name '{event_name}'")
274283

275-
return engine.add_event_handler(event_name, log_handler, self, event_name, *args, **kwargs)
284+
# Use weak reference to break circular reference: engine -> _event_handlers -> BaseLogger
285+
weak_self = weakref.ref(self)
286+
287+
def weak_log_handler(engine):
288+
logger_obj = weak_self()
289+
if logger_obj is not None:
290+
log_handler(engine, logger_obj, event_name, *args, **kwargs)
291+
292+
return engine.add_event_handler(event_name, weak_log_handler)
276293

277294
def attach_output_handler(self, engine: Engine, event_name: Any, *args: Any, **kwargs: Any) -> RemovableEventHandle:
278295
"""Shortcut method to attach `OutputHandler` to the logger.

ignite/handlers/tqdm_logger.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"""TQDM logger."""
33
from collections import OrderedDict
44
from typing import Any, Callable, List, Optional, Union
5+
import weakref
56

67
from ignite.engine import Engine, Events
78
from ignite.engine.events import CallableEventWithFilter, RemovableEventHandle
@@ -221,7 +222,15 @@ def attach( # type: ignore[override]
221222
)
222223

223224
super(ProgressBar, self).attach(engine, log_handler, event_name)
224-
engine.add_event_handler(closing_event_name, self._close)
225+
# Use weak reference to break circular reference: engine -> _event_handlers -> ProgressBar
226+
weak_self = weakref.ref(self)
227+
228+
def weak_close(engine):
229+
pbar_obj = weak_self()
230+
if pbar_obj is not None:
231+
pbar_obj._close(engine)
232+
233+
engine.add_event_handler(closing_event_name, weak_close)
225234

226235
def attach_opt_params_handler( # type: ignore[empty-body]
227236
self, engine: Engine, event_name: Union[str, Events], *args: Any, **kwargs: Any

0 commit comments

Comments
 (0)