Skip to content

Commit 9196dec

Browse files
kiukchungfacebook-github-bot
authored andcommitted
decouple torchx native scuba logging and ttfb (#1044)
Summary: Split out ttfb into its own logging handler and only hook it up to `torchx.runner.events.handler` if the module is included. Also splits out ttfb into its own BUCK target (`//torchx/runner/events/fb:ttfb`) NOTE: Dependants of //torchx/runner:lib will still get ttfb since I added an manual dep to //torchx/runner/events/fb:ttfb to it. Otherwise users now have to explicitly add a dep to ttfb. ## Motivation ttfb pulls unwanted deps such as quickflow (see output of `buck cquery "deps(//torchx/runner/events/fb:ttfb)"`). This prevents us from creating `torchx-lite` - a minimal set of torchx APIs (with no scheduler/workspace implementations pulled transitively). ## Other Notes Removed the unused `//torchx/runner/events:handlers_oss` targets which was confusing autodeps - hence requiring `autodeps-skip` in `//torchx/runner/events:lib` Reviewed By: hstonec Differential Revision: D73060221
1 parent 86e15e9 commit 9196dec

File tree

2 files changed

+57
-5
lines changed

2 files changed

+57
-5
lines changed

torchx/util/modules.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@
88

99
import importlib
1010
from types import ModuleType
11-
from typing import Callable, Optional, Union
11+
from typing import Callable, Optional, TypeVar, Union
1212

1313

1414
def load_module(path: str) -> Union[ModuleType, Optional[Callable[..., object]]]:
1515
"""
1616
Loads and returns the module/module attr represented by the ``path``: ``full.module.path:optional_attr``
1717
18-
::
19-
20-
2118
1. ``load_module("this.is.a_module:fn")`` -> equivalent to ``this.is.a_module.fn``
2219
1. ``load_module("this.is.a_module")`` -> equivalent to ``this.is.a_module``
2320
"""
@@ -33,3 +30,36 @@ def load_module(path: str) -> Union[ModuleType, Optional[Callable[..., object]]]
3330
return getattr(module, method) if method else module
3431
except Exception:
3532
return None
33+
34+
35+
T = TypeVar("T")
36+
37+
38+
def import_attr(name: str, attr: str, default: T) -> T:
39+
"""
40+
Imports ``name.attr`` and returns it if the module is found.
41+
Otherwise, returns the specified ``default``.
42+
Useful when getting an attribute from an optional dependency.
43+
44+
Note that the ``default`` parameter is intentionally not an optional
45+
since this function is intended to be used with modules that may not be
46+
installed as a dependency. Therefore the caller must ALWAYS provide a
47+
sensible default.
48+
49+
Usage:
50+
51+
.. code-block:: python
52+
53+
aws_resources = import_attr("torchx.specs.named_resources_aws", "NAMED_RESOURCES", default={})
54+
all_resources.update(aws_resources)
55+
56+
Raises:
57+
AttributeError: If the module exists (e.g. can be imported)
58+
but does not have an attribute with name ``attr``.
59+
"""
60+
try:
61+
mod = importlib.import_module(name)
62+
except ModuleNotFoundError:
63+
return default
64+
else:
65+
return getattr(mod, attr)

torchx/util/test/modules_test.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
# This source code is licensed under the BSD-style license found in the
55
# LICENSE file in the root directory of this source tree.
66

7+
# pyre-strict
8+
79
import unittest
810

9-
from torchx.util.modules import load_module
11+
from torchx.util.modules import import_attr, load_module
1012

1113

1214
class ModulesTest(unittest.TestCase):
@@ -21,3 +23,23 @@ def test_load_module_method(self) -> None:
2123
import os
2224

2325
self.assertEqual(result, os.path.join)
26+
27+
def test_try_import(self) -> None:
28+
def _join(_0: str, *_1: str) -> str:
29+
return "" # should never be called
30+
31+
os_path_join = import_attr("os.path", "join", default=_join)
32+
import os
33+
34+
self.assertEqual(os.path.join, os_path_join)
35+
36+
def test_try_import_non_existent_module(self) -> None:
37+
should_default = import_attr("non.existent", "foo", default="bar")
38+
self.assertEqual("bar", should_default)
39+
40+
def test_try_import_non_existent_attr(self) -> None:
41+
def _join(_0: str, *_1: str) -> str:
42+
return "" # should never be called
43+
44+
with self.assertRaises(AttributeError):
45+
import_attr("os.path", "joyin", default=_join)

0 commit comments

Comments
 (0)