Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The del-task command implemented. #192

Merged
merged 1 commit into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions dem/cli/command/add_task_cmd.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""add-task CLI command implementation."""
# dem/cli/command/add_task_cmd.py

from dem.core.platform import Platform
from dem.cli.console import stderr

Expand Down
26 changes: 26 additions & 0 deletions dem/cli/command/del_task_cmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
"""del-task CLI command implementation."""
# dem/cli/command/del_task_cmd.py

from dem.core.platform import Platform
from dem.cli.console import stderr

def execute(platform: Platform, dev_env_name: str, task_name: str) -> None:
""" Delete a task from a Development Environment.

Args:
platform -- the Platform
dev_env_name -- the Development Environment name
task_name -- the task name
"""
dev_env = platform.get_dev_env_by_name(dev_env_name)
if dev_env is None:
stderr.print(f"[red]Error: Development Environment '{dev_env_name}' not found![/]")
return

try:
dev_env.del_task(task_name)
except KeyError as e:
stderr.print(f"[red] Error: {str(e)}[/]")
return

platform.flush_dev_env_properties()
34 changes: 33 additions & 1 deletion dem/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
delete_cmd, rename_cmd, run_cmd, export_cmd, clone_cmd, add_reg_cmd, \
list_reg_cmd, del_reg_cmd, add_cat_cmd, list_cat_cmd, del_cat_cmd, \
add_host_cmd, set_default_cmd, uninstall_cmd, install_cmd, assign_cmd, \
init_cmd, list_host_cmd, del_host_cmd, list_tools_cmd, add_task_cmd
init_cmd, list_host_cmd, del_host_cmd, list_tools_cmd, add_task_cmd, \
del_task_cmd
from dem.cli.console import stdout
from dem.core.platform import Platform
from dem.core.exceptions import InternalError
Expand Down Expand Up @@ -89,6 +90,23 @@ def autocomplete_host_name(incomplete: str) -> Generator:
if host_config["name"].startswith(incomplete) or (incomplete == ""):
yield host_config["name"]

def autocomplete_task_name(ctx: typer.Context, incomplete: str) -> Generator:
"""
Autocomplete the input Task name with the available matching Task names.

Return with the matching Task name by a Generator.

Args:
incomplete -- the parameter the user supplied so far when the tab was pressed
"""
dev_env_name = ctx.params.get("dev_env_name", None)
if platform is not None and dev_env_name is not None:
for dev_env in platform.local_dev_envs:
if dev_env.name == dev_env_name:
for task_name in dev_env.tasks:
if task_name.startswith(incomplete) or (incomplete == ""):
yield task_name

# DEM commands
@typer_cli.command()
def add_task(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to add the task to.",
Expand All @@ -105,6 +123,20 @@ def add_task(dev_env_name: Annotated[str, typer.Argument(help="Name of the Devel
add_task_cmd.execute(platform, dev_env_name, task_name, command)
else:
raise InternalError("Error: The platform hasn't been initialized properly!")

@typer_cli.command()
def del_task(dev_env_name: Annotated[str, typer.Argument(help="Name of the Development Environment to delete the task from.",
autocompletion=autocomplete_dev_env_name)],
task_name: Annotated[str, typer.Argument(help="Name of the task to delete.",
autocompletion=autocomplete_task_name)]) -> None:
"""
Delete a task from the Development Environment.
"""
if platform:
del_task_cmd.execute(platform, dev_env_name, task_name)
else:
raise InternalError("Error: The platform hasn't been initialized properly!")

@typer_cli.command()
def set_default(dev_env_name: Annotated[str,
typer.Argument(help="The name of the Development Environment to set as default.",
Expand Down
22 changes: 22 additions & 0 deletions dem/core/dev_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,30 @@ def assign_tool_image_instances(self, tool_images: ToolImages) -> None:
self.tool_images.append(tool_image)

def add_task(self, task_name: str, command: str) -> None:
""" Add a task to the Development Environment.

If the task already exists, it will be overwritten.

Args:
task_name -- the task name
command -- the command
"""
self.tasks[task_name] = command

def del_task(self, task_name: str) -> None:
""" Delete a task from the Development Environment.

Args:
task_name -- the task name

Exceptions:
KeyError -- if the task doesn't exist
"""
if task_name in self.tasks:
del self.tasks[task_name]
else:
raise KeyError(f"Task [bold]{task_name}[/] not found.")

def get_tool_image_status(self) -> Status:
""" Get the status of the Tool Images.

Expand Down
15 changes: 15 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,21 @@ Delete the Dev Env descriptor from the local descriptor storage. If the Dev Env

---

## **`dem del-task DEV_ENV_NAME TASK_NAME`**

**Description:**

Delete a task from the Development Environment.

**Arguments:**

| Argument | Description | Required |
|------------------|---------------------------------------------------------|:---------------:|
| `DEV_ENV_NAME` | Name of the Development Environment. | :material-check:|
| `TASK_NAME` | Name of the task to delete. | :material-check:|

---

## **`dem export DEV_ENV_NAME [PATH_TO_EXPORT]`**

**Description:**
Expand Down
2 changes: 2 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,13 @@ nav:
- 'basics.md'
- Commands:
- 'DevEnv Management':
- 'add-task': 'commands/#dem-add-task-dev_env_name-task_name-command'
- 'assign': 'commands/#dem-assign-dev_env_name-project_path'
- 'clone': 'commands/#dem-clone-dev_env_name'
- 'cp': 'commands/#dem-cp-dev_env_name-new_dev_env_name'
- 'create': 'commands/#dem-create-dev_env_name'
- 'delete': 'commands/#dem-delete-dev_env_name'
- 'del-task': 'commands/#dem-del-task-dev_env_name-task_name'
- 'export': 'commands/#dem-export-dev_env_name-path_to_export'
- 'import': 'commands/#dem-import-path_to_dev_env'
- 'info': 'commands/#dem-info-dev_env_name-options-catalog_names'
Expand Down
2 changes: 1 addition & 1 deletion tests/cli/test_add_task_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

# Test framework
from typer.testing import CliRunner
from unittest.mock import patch, MagicMock, call
from unittest.mock import patch, MagicMock

## Global test variables

Expand Down
71 changes: 71 additions & 0 deletions tests/cli/test_del_task_cmd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""Unit tests for the del-task CLI command."""
# tests/cli/test_del_task_cmd.py

# Unit under test:
import dem.cli.main as main
import dem.cli.command.del_task_cmd as del_task_cmd

# Test framework
from typer.testing import CliRunner
from unittest.mock import patch, MagicMock, call

## Global test variables

# In order to test stdout and stderr separately, the stderr can't be mixed into
# the stdout.
runner = CliRunner(mix_stderr=False)

def test_del_task_cmd() -> None:
# Setup
mock_platform = MagicMock()
main.platform = mock_platform

mock_dev_env = MagicMock()
mock_platform.get_dev_env_by_name.return_value = mock_dev_env

# Run
result = runner.invoke(main.typer_cli, ["del-task", "my-dev-env", "my-task"])

# Check
assert result.exit_code == 0

mock_platform.get_dev_env_by_name.assert_called_once_with("my-dev-env")
mock_dev_env.del_task.assert_called_once_with("my-task")
mock_platform.flush_dev_env_properties.assert_called_once()

@patch("dem.cli.command.del_task_cmd.stderr")
def test_del_task_cmd_dev_env_not_found(mock_stderr: MagicMock) -> None:
# Setup
mock_platform = MagicMock()
main.platform = mock_platform

mock_platform.get_dev_env_by_name.return_value = None

# Run
result = runner.invoke(main.typer_cli, ["del-task", "my-dev-env", "my-task"])

# Check
assert result.exit_code == 0

mock_platform.get_dev_env_by_name.assert_called_once_with("my-dev-env")
mock_stderr.print.assert_called_once_with("[red]Error: Development Environment 'my-dev-env' not found![/]")

@patch("dem.cli.command.del_task_cmd.stderr")
def test_del_task_cmd_task_not_found(mock_stderr: MagicMock) -> None:
# Setup
mock_platform = MagicMock()
main.platform = mock_platform

mock_dev_env = MagicMock()
mock_platform.get_dev_env_by_name.return_value = mock_dev_env
mock_dev_env.del_task.side_effect = KeyError("Task [bold]my-task[/] not found.")

# Run
result = runner.invoke(main.typer_cli, ["del-task", "my-dev-env", "my-task"])

# Check
assert result.exit_code == 0

mock_platform.get_dev_env_by_name.assert_called_once_with("my-dev-env")
mock_dev_env.del_task.assert_called_once_with("my-task")
mock_stderr.print.assert_called_once_with("[red] Error: \'Task [bold]my-task[/] not found.\'[/]")
34 changes: 34 additions & 0 deletions tests/cli/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,39 @@ def test_autocomplete_host_name() -> None:

mock_platform.hosts.list_host_configs.assert_called_once()

def test_autocomplete_task_name() -> None:
# Test setup
mock_platform = MagicMock()
mock_dev_env1 = MagicMock()
mock_dev_env1.name = "dev_env_1"
mock_dev_env1.tasks = {
"test": "test",
"task": "command"
}
mock_dev_env2 = MagicMock()
mock_dev_env2.name = "dev_env_2"
mock_platform.local_dev_envs = [
mock_dev_env1,
mock_dev_env2
]

mock_ctx = MagicMock()
mock_ctx.params = {
"dev_env_name": "dev_env_1"
}

main.platform = mock_platform

expected_completions = [mock_dev_env1.tasks["test"]]

# Run unit under test
actual_completions = []
for result in main.autocomplete_task_name(mock_ctx, "tes"):
actual_completions.append(result)

# Check expectations
assert expected_completions == actual_completions

@patch("dem.cli.main.__app_name__", "axem-dem")
@patch("dem.cli.main.stdout.print")
@patch("dem.cli.main.importlib.metadata.version")
Expand Down Expand Up @@ -199,6 +232,7 @@ def test_platform_not_initialized() -> None:

units_to_test = {
main.add_task: [test_dev_env_name, test_name, test_command],
main.del_task: [test_dev_env_name, test_name],
main.set_default: [test_dev_env_name],
main.list_: [],
main.list_tools: [],
Expand Down
45 changes: 45 additions & 0 deletions tests/core/test_dev_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,51 @@ def test_DevEnv_add_task() -> None:
# Check expectations
assert test_dev_env.tasks[test_task_name] == test_command

def test_DevEnv_del_task() -> None:
# Test setup
test_descriptor = {
"name": "test_name",
"installed": "True",
"tools": [MagicMock()],
"tasks": {
"test_task_name1": "test_task_command1",
"test_task_name2": "test_task_command2",
"test_task_name3": "test_task_command3"
}
}
test_dev_env = dev_env.DevEnv(test_descriptor)

test_task_name = "test_task_name2"

# Run unit under test
test_dev_env.del_task(test_task_name)

# Check expectations
assert test_task_name not in test_dev_env.tasks

def test_DevEnv_del_task_not_existing() -> None:
# Test setup
test_descriptor = {
"name": "test_name",
"installed": "True",
"tools": [MagicMock()],
"tasks": {
"test_task_name1": "test_task_command1",
"test_task_name2": "test_task_command2",
"test_task_name3": "test_task_command3"
}
}
test_dev_env = dev_env.DevEnv(test_descriptor)

test_task_name = "test_task_name4"

# Run unit under test
with pytest.raises(KeyError) as exc_info:
test_dev_env.del_task(test_task_name)

# Check expectations
assert str(exc_info.value) == f"\'Task [bold]{test_task_name}[/] not found.\'"

@patch.object(dev_env.DevEnv, "__init__")
def test_DevEnv_get_tool_image_status(mock___init__: MagicMock) -> None:
# Test setup
Expand Down
Loading