Skip to content

Commit

Permalink
#5 adds pa schedule list command. by: Piotr
Browse files Browse the repository at this point in the history
  • Loading branch information
caseneuve committed Jan 29, 2021
1 parent c49990b commit e16a41b
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 5 deletions.
38 changes: 35 additions & 3 deletions cli/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import typer
from tabulate import tabulate

from pythonanywhere.scripts_commons import get_logger, get_task_from_id
from pythonanywhere.scripts_commons import get_logger, get_task_from_id, tabulate_formats
from pythonanywhere.snakesay import snakesay
from pythonanywhere.task import Task, TaskList

Expand Down Expand Up @@ -194,9 +194,41 @@ def get(
logger.info(tabulate(table, tablefmt="simple"))


def tablefmt_callback(value: str):
if value not in tabulate_formats:
raise typer.BadParameter(f"Table format has to be one of: {', '.join(tabulate_formats)}")
return value


@app.command("list")
def list_():
raise NotImplementedError
def list_(
tablefmt: str = typer.Option(
"simple", "-f", "--format", help="Table format", callback=tablefmt_callback
)
):
"""Get list of user's scheduled tasks as a table with columns:
id, interval, at (hour:minute/minute past), status (enabled/disabled), command.
Note:
This script provides an overview of all tasks. Once a task id is
known and some specific data is required it's more convenient to get
it using `pa schedule get` command instead of parsing the table.
"""

logger = get_logger(set_info=True)

headers = "id", "interval", "at", "status", "command"
attrs = "task_id", "interval", "printable_time", "enabled", "command"

def stringify_values(task, attr):
value = getattr(task, attr)
if attr == "enabled":
value = "enabled" if value else "disabled"
return value

table = [[stringify_values(task, attr) for attr in attrs] for task in TaskList().tasks]
msg = tabulate(table, headers, tablefmt=tablefmt) if table else snakesay("No scheduled tasks")
logger.info(msg)


@app.command()
Expand Down
64 changes: 62 additions & 2 deletions tests/test_cli_schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,35 @@
from typer.testing import CliRunner

from cli.schedule import app, delete_app
from pythonanywhere.scripts_commons import tabulate_formats

runner = CliRunner()


@pytest.fixture
def task_list(mocker):
username = getpass.getuser()
specs1 = {
"can_enable": False,
"command": "echo foo",
"enabled": True,
"expiry": None,
"extend_url": f"/user/{username}/schedule/task/42/extend",
"hour": 16,
"task_id": 42,
"interval": "daily",
"logfile": "/user/{username}/files/var/log/tasklog-126708-daily-at-1600-echo_foo.log",
"minute": 0,
"printable_time": "16:00",
"url": f"/api/v0/user/{username}/schedule/42",
"user": username,
}
specs2 = {**specs1}
specs2.update({"task_id": 43, "enabled": False})
mock_task_list = mocker.patch("cli.schedule.TaskList")
mock_task_list.return_value.tasks = [Mock(task_id=1), Mock(task_id=2)]
mock_task_list.return_value.tasks = [Mock(**specs1), Mock(**specs2)]
return mock_task_list


@pytest.fixture
def mock_confirm(mocker):
return mocker.patch("cli.schedule.typer.confirm")
Expand Down Expand Up @@ -213,3 +231,45 @@ def test_logs_only_value_of_requested_task_spec(self, mocker, task_from_id):
assert task_from_id.call_args == call(42)
assert mock_logger.call_args == call(set_info=True)
assert mock_logger.return_value.info.call_args == call("10:23")
@pytest.mark.clischedulelist
class TestList:
def test_logs_table_with_correct_headers_and_values(self, mocker, task_list):
mock_logger = mocker.patch("cli.schedule.get_logger")
mock_tabulate = mocker.patch("cli.schedule.tabulate")

result = runner.invoke(app, ["list", "--format", "orgtbl"])

headers = "id", "interval", "at", "status", "command"
attrs = "task_id", "interval", "printable_time", "enabled", "command"
table = [[getattr(task, attr) for attr in attrs] for task in task_list.return_value.tasks]
table = [
["enabled" if spec == True else "disabled" if spec == False else spec for spec in row]
for row in table
]
assert mock_logger.call_args == call(set_info=True)
assert task_list.call_count == 1
assert mock_tabulate.call_args == call(table, headers, tablefmt="orgtbl")
assert mock_logger.return_value.info.call_args == call(mock_tabulate.return_value)

def test_snakesays_when_no_scheduled_tasks(self, mocker):
mock_logger = mocker.patch("cli.schedule.get_logger").return_value
mock_tabulate = mocker.patch("cli.schedule.tabulate")
mock_snakesay = mocker.patch("cli.schedule.snakesay")
mock_tasks = mocker.patch("cli.schedule.TaskList")
mock_tasks.return_value.tasks = []

runner.invoke(app, ["list"])

assert mock_tabulate.call_count == 0
assert mock_snakesay.call_args == call("No scheduled tasks")
assert mock_logger.info.call_args == call(mock_snakesay.return_value)

def test_warns_when_wrong_format_provided(self, mocker, task_list):
mock_tabulate = mocker.patch("cli.schedule.tabulate")
wrong_format = "excel"

result = runner.invoke(app, ["list", "--format", "excel"])

assert mock_tabulate.call_count == 0
assert wrong_format not in tabulate_formats
assert "Table format has to be one of" in result.stdout

0 comments on commit e16a41b

Please sign in to comment.