Skip to content

Commit 77c67eb

Browse files
authored
(torchx/tracker) Allow AppRun.run_from_env() to be used without launching the app with torchx (#698)
1 parent 084479f commit 77c67eb

File tree

3 files changed

+48
-6
lines changed

3 files changed

+48
-6
lines changed

docs/source/app_best_practices.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ model definition from a python file and then you'll load the weights and state
105105
dict from a ``.ckpt`` or ``.pt`` file.
106106

107107
This is how Pytorch Lightning's
108-
`ModelCheckpoint <https://pytorch-lightning.readthedocs.io/en/latest/api/pytorch_lightning.callbacks.ModelCheckpoint.html>`__ hook works.
108+
`ModelCheckpoint <https://pytorch-lightning.readthedocs.io/en/stable/api/pytorch_lightning.callbacks.ModelCheckpoint.html>`__ hook works.
109109

110110
This is the most common but makes it harder to make a reusable app since your
111111
trainer app needs to include the model definition code.

torchx/tracker/api.py

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -240,13 +240,39 @@ class AppRun:
240240
@staticmethod
241241
@lru_cache(maxsize=1) # noqa: B019
242242
def run_from_env() -> AppRun:
243-
"""Factory method do build AppRun that uses environment variabes to build it.
243+
"""
244+
Creates an :py:class:`AppRun` from environment variables. The environment variables are set by
245+
the torchx runner. Hence if the application is launched via the torchx CLI as:
246+
247+
.. code-block:: shell-session
248+
249+
$ torchx run utils_python --script main.py
250+
251+
252+
And the tracker settings are configured in ``.torchxconfig``, then this function returns an
253+
``AppRun`` with the configured tracker backends. This function returns a singleton ``AppRun``
254+
hence the same instances of the tracker backend objects.
255+
256+
.. note::
257+
When the application is NOT launched via torchx, this function
258+
will return an "empty" ``AppRun`` with the ``job_id`` set to a constant
259+
``<UNDEFINED>`` since the app was not "launched" (e.g. submitted as a job)
260+
and hence no canonical ``job_id`` exists.
261+
No trackers are hooked up to the ``AppRun`` hence
262+
calling ``add_*()`` (write) methods on the returned apprun will be a no-op.
263+
264+
Usage:
265+
266+
.. doctest::
267+
268+
>>> from torchx.tracker.api import AppRun
269+
>>> apprun = AppRun.run_from_env()
270+
>>> apprun.add_metadata(md_1 = "foo", md_2 = "bar")
271+
244272
245-
Single instance of AppRun will be available for the duration of the application, thus expect that calling
246-
this method will retorn same AppRun and hence same instances of the backend implementations.
247273
"""
248274

249-
torchx_job_id = os.environ["TORCHX_JOB_ID"]
275+
torchx_job_id = os.getenv("TORCHX_JOB_ID", default="<UNDEFINED>")
250276

251277
trackers = trackers_from_environ()
252278
if TRACKER_PARENT_RUN_ENV_VAR_NAME in os.environ:

torchx/tracker/test/api_test.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,14 @@ def run_ids(self, **kwargs: str) -> Iterable[str]:
9898

9999
class AppRunApiTest(TestCase):
100100
def setUp(self) -> None:
101-
os.environ["TORCHX_JOB_ID"] = "scheduler://sesison/app_id"
101+
os.environ["TORCHX_JOB_ID"] = "scheduler://session/app_id"
102102
self.tracker = TestTrackerBackend()
103103
self.run_id = "run_id"
104104
self.model_run = AppRun(self.run_id, [self.tracker])
105105

106+
def tearDown(self) -> None:
107+
del os.environ["TORCHX_JOB_ID"]
108+
106109
@mock.patch.dict(
107110
os.environ,
108111
{
@@ -266,3 +269,16 @@ def test_build_trackers(self) -> None:
266269
self.assertEqual(1, len(trackers))
267270
tracker = trackers[0]
268271
self.assertEqual(tracker.config_path, "myconfig.txt") # pyre-ignore[16]
272+
273+
@mock.patch.dict(os.environ, {}, clear=True)
274+
def test_run_from_env_not_launched_with_torchx(self) -> None:
275+
# asserts that an empty AppRun (with no trackers and job_id defaulted to program name)
276+
# is created if not launched from torchx
277+
# makes it possible to use `torchx.tracker.app_run_from_env()` without being tightly coupled with
278+
# the torchx launcher
279+
280+
AppRun.run_from_env.cache_clear()
281+
apprun = AppRun.run_from_env()
282+
self.assertEqual("<UNDEFINED>", apprun.job_id())
283+
# no backends configured if not launched via torchx
284+
self.assertEqual([], list(apprun.backends))

0 commit comments

Comments
 (0)