Skip to content

Commit fe90bf8

Browse files
authored
Allow empty session name for APIs that take it
Differential Revision: D73799333 Pull Request resolved: #1057
1 parent b53d332 commit fe90bf8

File tree

3 files changed

+55
-2
lines changed

3 files changed

+55
-2
lines changed

torchx/runner/test/api_test.py

+27
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
AppDef,
2626
AppHandle,
2727
AppState,
28+
parse_app_handle,
2829
Resource,
2930
Role,
3031
UnknownAppException,
@@ -132,6 +133,32 @@ def test_session_id(self, record_mock: MagicMock) -> None:
132133
event = record_mock.call_args_list[i].args[0]
133134
self.assertEqual(event.session, CURRENT_SESSION_ID)
134135

136+
def test_empty_session_id(self, _: MagicMock) -> None:
137+
empty_session_name = ""
138+
with Runner(
139+
empty_session_name,
140+
{"local": cast(SchedulerFactory, create_scheduler)},
141+
) as runner:
142+
app = AppDef(
143+
"__unused_for_test__",
144+
roles=[
145+
Role(
146+
name="echo",
147+
image=str(self.tmpdir),
148+
resource=resource.SMALL,
149+
entrypoint="echo",
150+
args=["__unused_for_test__"],
151+
)
152+
],
153+
)
154+
155+
app_handle = runner.run(app, "local", self.cfg)
156+
157+
scheduler, session_name, app_id = parse_app_handle(app_handle)
158+
self.assertEqual(scheduler, "local")
159+
self.assertEqual(empty_session_name, session_name)
160+
self.assertEqual(app_handle, f"local:///{app_id}")
161+
135162
def test_run(self, record_mock: MagicMock) -> None:
136163
test_file = self.tmpdir / "test_file"
137164

torchx/specs/api.py

+19-2
Original file line numberDiff line numberDiff line change
@@ -1115,14 +1115,31 @@ def __init__(self, app_handle: "AppHandle") -> None:
11151115

11161116
def parse_app_handle(app_handle: AppHandle) -> ParsedAppHandle:
11171117
"""
1118-
parses the app handle into ```(scheduler_backend, session_name, and app_id)```
1118+
Parses the app handle into ```(scheduler_backend, session_name, and app_id)```.
1119+
1120+
Example:
1121+
1122+
.. doctest::
1123+
1124+
assert parse_app_handle("k8s://default/foo_bar") == ("k8s", "default", "foo_bar")
1125+
assert parse_app_handle("k8s:///foo_bar") == ("k8s", "", "foo_bar")
1126+
1127+
Args:
1128+
app_handle: a URI of the form ``{scheduler}://{session_name}/{app_id}``,
1129+
where the ``session_name`` is optional. In this case the app handle is
1130+
of the form ``{scheduler}:///{app_id}`` (notice the triple slashes).
1131+
1132+
Returns: A ``Tuple`` of three elements, ``(scheduler, session_name, app_id)``
1133+
parsed from the app_handle URI str. If the session name is not present then
1134+
an empty string is returned in its place in the tuple.
1135+
11191136
"""
11201137

11211138
# parse it manually b/c currently torchx does not
11221139
# define allowed characters nor length for session name and app_id
11231140
import re
11241141

1125-
pattern = r"(?P<scheduler_backend>.+)://(?P<session_name>.+)/(?P<app_id>.+)"
1142+
pattern = r"(?P<scheduler_backend>.+)://(?P<session_name>.*)/(?P<app_id>.+)"
11261143
match = re.match(pattern, app_handle)
11271144
if not match:
11281145
raise MalformedAppHandleException(app_handle)

torchx/specs/test/api_test.py

+9
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,15 @@ def test_parse_malformed_app_handles(self) -> None:
377377
with self.assertRaises(MalformedAppHandleException):
378378
parse_app_handle(handle)
379379

380+
def test_parse_app_handle_empty_session_name(self) -> None:
381+
# missing session name is not OK but an empty one is
382+
app_handle = "local:///my_application_id"
383+
handle = parse_app_handle(app_handle)
384+
385+
self.assertEqual(handle.app_id, "my_application_id")
386+
self.assertEqual("local", handle.scheduler_backend)
387+
self.assertEqual("", handle.session_name)
388+
380389
def test_parse(self) -> None:
381390
(scheduler_backend, session_name, app_id) = parse_app_handle(
382391
"local://my_session/my_app_id_1234"

0 commit comments

Comments
 (0)