Skip to content

Commit 78931b6

Browse files
kiukchungmeta-codesync[bot]
authored andcommitted
Fix type bug in build_trackers -- skip non-callable modules (#1249)
Summary: Pull Request resolved: #1249 Fix ``build_trackers()`` in ``tracker/api.py`` to skip non-callable modules returned by ``load_module()``. Previously, ``ModuleType`` objects were being passed where callables were expected, causing ``TypeError: 'module' object is not callable`` at runtime. **Root cause:** ``load_module()`` returns ``types.ModuleType`` for packages (directories with ``__init__.py``) but ``build_trackers()`` assumed all return values were factory callables. **Fix:** Added ``callable()`` guard before invoking the loaded object. Non-callable modules are silently skipped with a debug log message. **Cleanup:** Removed unused ``source_data`` variable in test MockTracker. Differential Revision: D95932184
1 parent 307b3d7 commit 78931b6

1 file changed

Lines changed: 22 additions & 2 deletions

File tree

torchx/tracker/test/api_test.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,6 @@ def sources(
8383
run_id: str,
8484
artifact_name: str | None = None,
8585
) -> Iterable[TrackerSource]:
86-
source_data = self._sources[run_id]
87-
8886
sources = []
8987
for artifact_name, source_id in self._sources[run_id].items():
9088
if artifact_name == DEFAULT_SOURCE:
@@ -289,6 +287,28 @@ def test_build_trackers_with_module(self) -> None:
289287
self.assertIsInstance(tracker, MLflowTracker)
290288
module.assert_called_once_with(config)
291289

290+
def test_build_trackers_with_non_callable_module(self) -> None:
291+
"""load_module returns a ModuleType when no :attr is specified.
292+
Modules aren't callable -- build_trackers should skip them with a warning.
293+
"""
294+
from types import ModuleType
295+
296+
module = ModuleType("fake_tracker_module")
297+
with (
298+
patch("torchx.tracker.api.load_group", return_value=None),
299+
patch(
300+
"torchx.tracker.api.load_module",
301+
return_value=module,
302+
),
303+
):
304+
tracker_names = {"fake_tracker_module": "myconfig.txt"}
305+
trackers = build_trackers(tracker_names)
306+
self.assertEqual(
307+
0,
308+
len(list(trackers)),
309+
"non-callable module should be skipped, not called as a factory",
310+
)
311+
292312
def test_build_trackers(self) -> None:
293313
with patch("torchx.tracker.api.plugins") as plugins_mock:
294314
plugins_mock.registry.return_value.get.return_value = {

0 commit comments

Comments
 (0)