Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion python/lightning_sdk/cli/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def job() -> None:
"""Run batch jobs and sweeps."""


@click.group(name="mmt", cls=LightningGroup)
@click.group(name="mmt", cls=DeprecatedGroup, hidden=False, replacement="lightning job")
def mmt() -> None:
"""Multi-node distributed training."""

Expand Down
8 changes: 8 additions & 0 deletions python/lightning_sdk/mmt.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import warnings
from typing import TYPE_CHECKING, Dict, Optional, Protocol, Union

from lightning_sdk.job import Job, JobDict
Expand All @@ -12,6 +13,11 @@

__all__ = ["MMT", "MMTMachine"]

_MMT_DEPRECATION_MESSAGE = (
"lightning_sdk.MMT will be deprecated in a future release. "
"Prefer lightning_sdk.Job (use Job.run(..., num_machines=N) for multi-machine jobs)."
Comment thread
tejapulagam marked this conversation as resolved.
Resolved
)


class MMTMachine(Protocol):
"""A single machine in a multi-machine job."""
Expand Down Expand Up @@ -60,6 +66,7 @@ class MMT(Job):
"""Compatibility interface for multi-machine jobs.

Multi-machine functionality is implemented by :class:`lightning_sdk.job.Job`.
``MMT`` will be deprecated in a future release; prefer ``Job``.
"""

def __init__(
Expand All @@ -72,6 +79,7 @@ def __init__(
_fetch_job: bool = True,
_num_machines: int = 2,
) -> None:
warnings.warn(_MMT_DEPRECATION_MESSAGE, DeprecationWarning, stacklevel=3)
try:
super().__init__(
name=name,
Expand Down
2 changes: 1 addition & 1 deletion python/tests/cli/mmt/test_logs.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def test_mmt_logs_follows_with_options() -> None:
)

assert result.exit_code == 0, result.output
assert result.output == "line 1\nline 2\n"
assert "line 1\nline 2\n" in result.output
mmt.logs.assert_called_once_with(
follow=True, tail=10, timestamps=True, since=None, until=None, query="loss", severity="error"
)
Expand Down
33 changes: 30 additions & 3 deletions python/tests/cli/mmt/test_mmt.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
import pytest

from tests.cli.help import assert_help_contains, mock_command_logging

_MMT_COMMANDS = ("run", "list", "inspect", "logs", "ssh", "stop", "delete")


@mock_command_logging
def test_mmt_help() -> None:
assert_help_contains("lightning mmt --help", "Usage: lightning mmt", "Multi-node distributed training.")
assert_help_contains(
"lightning mmt --help",
"Deprecation warning:",
"Use `lightning job` instead of `lightning mmt`.",
"Usage: lightning mmt",
"Multi-node distributed training.",
)


@mock_command_logging
def test_mmts_list_help_shows_deprecation() -> None:
# Plural alias shares the wrapped subcommands from the mmt group.
assert_help_contains(
"lightning mmts list --help",
"Deprecation warning:",
"Use `lightning job` instead of `lightning mmts list`.",
Comment thread
tejapulagam marked this conversation as resolved.
Resolved
"Usage: lightning mmts list",
)


@pytest.mark.parametrize("subcommand", _MMT_COMMANDS)
@mock_command_logging
def test_mmts_help() -> None:
assert_help_contains("lightning mmts --help", "Usage: lightning mmts", "Multi-node distributed training.")
def test_mmt_deprecation_propagates_to_subcommands(subcommand: str) -> None:
assert_help_contains(
f"lightning mmt {subcommand} --help",
"Deprecation warning:",
f"Use `lightning job` instead of `lightning mmt {subcommand}`.",
f"Usage: lightning mmt {subcommand}",
)
42 changes: 42 additions & 0 deletions python/tests/core/test_mmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,48 @@
from lightning_sdk.teamspace import Teamspace


def test_mmt_emits_deprecation_warning() -> None:
teamspace = mock.MagicMock()
teamspace.id = "teamspace-id"
teamspace.name = "teamspace"
teamspace.owner = mock.MagicMock(name="owner")
with mock.patch("lightning_sdk.job._resolve_teamspace", return_value=teamspace), mock.patch(
"lightning_sdk.job.JobApiV2"
), mock.patch("lightning_sdk.job.MMTApiV2") as multi_api, pytest.warns(
DeprecationWarning, match="lightning_sdk.MMT will be deprecated"
):
multi_api.return_value.get_job_by_name.return_value = V1MultiMachineJob(
id="mmt-id", name="test-job", machines=2, spec=V1JobSpec()
)
MMT("test-job", teamspace)


def test_mmt_run_emits_deprecation_warning() -> None:
teamspace = mock.MagicMock()
teamspace.id = "teamspace-id"
teamspace.name = "teamspace"
teamspace.owner = mock.MagicMock(name="owner")
teamspace.default_cloud_account = "default-cloud"
cloud_api = mock.MagicMock()
cloud_api.resolve_cloud_account.return_value = "cloud-id"
multi_api = mock.MagicMock()

with mock.patch("lightning_sdk.job._resolve_teamspace", return_value=teamspace), mock.patch(
"lightning_sdk.job._resolve_default_cloud_account", return_value=None
), mock.patch("lightning_sdk.job.CloudAccountApi", return_value=cloud_api), mock.patch(
"lightning_sdk.job.MMTApiV2", return_value=multi_api
), mock.patch.object(MMT, "_submit", return_value=None), pytest.warns(
DeprecationWarning, match="Prefer lightning_sdk.Job"
):
MMT.run(
name="test-job",
num_machines=2,
machine=Machine.CPU,
image="ubuntu",
teamspace=teamspace,
)


@pytest.mark.parametrize("machine", [Machine.CPU, Machine.T4_X_4])
@pytest.mark.parametrize("command", [None, "echo hello"])
@pytest.mark.parametrize("env", [None, {"key": "value"}])
Expand Down
Loading