File: commands.py

package info (click to toggle)
pytest-watcher 0.4.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 856 kB
  • sloc: python: 925; makefile: 28; sh: 13
file content (154 lines) | stat: -rw-r--r-- 4,191 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
from __future__ import annotations

import abc
import sys
from typing import Dict, Optional, Type

from .config import Config
from .terminal import Terminal
from .trigger import Trigger


class Manager:
    _registry: Dict[str, Command] = {}

    @classmethod
    def list_commands(cls):
        return cls._registry.values()

    @classmethod
    def get_command(cls, character: str) -> Optional[Command]:
        return cls._registry.get(character)

    @classmethod
    def register(cls, command: Type[Command]):
        if command.character in cls._registry:
            raise ValueError(f"Duplicate character {repr(command.character)}")

        cls._registry[command.character] = command()

    @classmethod
    def run_command(
        cls, character: str, trigger: Trigger, term: Terminal, config: Config
    ) -> None:
        command = cls.get_command(character)
        if command:
            command.run(trigger, term, config)


class Command(abc.ABC):
    character: str
    caption: str
    description: str
    show_in_menu: bool = True

    def __init_subclass__(cls, **kwargs) -> None:
        for field in ("character", "caption", "description"):
            if not hasattr(cls, field):
                raise NotImplementedError(f"{cls.__name__}: {field} not specified")

        super().__init_subclass__(**kwargs)
        Manager.register(cls)

    @abc.abstractmethod
    def run(self, trigger: Trigger, term: Terminal, config: Config) -> None:
        """
        Modify runner_args in-place if needed and return a bool indicating whether
        tests should be triggered instantly
        """


class OpenMenuCommand(Command):
    character = "w"
    caption = "w"
    description = "show menu"
    show_in_menu = False

    def run(self, trigger: Trigger, term: Terminal, config: Config) -> None:
        term.clear()
        term.print_menu(config.runner_args)


class InvokeCommand(Command):
    character = "\n"
    caption = "Enter"
    description = "Invoke test runner"

    def run(self, trigger: Trigger, term: Terminal, config: Config) -> None:
        trigger.emit_now()


class ResetRunnerArgsCommand(Command):
    character = "r"
    caption = "r"
    description = "reset all runner args"

    def run(self, trigger: Trigger, term: Terminal, config: Config) -> None:
        config.runner_args.clear()
        trigger.emit_now()


class ChangeRunnerArgsCommand(Command):
    character = "c"
    caption = "c"
    description = "change runner args"

    def run(self, trigger: Trigger, term: Terminal, config: Config) -> None:
        term.reset()
        raw = input("\nEnter new runner args: ")
        new_args = raw.strip().split()
        config.runner_args.clear()
        config.runner_args.extend(new_args)
        trigger.emit_now()


class OnlyFailedCommand(Command):
    character = "f"
    caption = "f"
    description = "run only failed tests (--lf)"

    def run(self, trigger: Trigger, term: Terminal, config: Config) -> None:
        if "--lf" not in config.runner_args:
            config.runner_args.append("--lf")
        trigger.emit_now()


class PDBCommand(Command):
    character = "p"
    caption = "p"
    description = "drop to pdb on fail (--pdb)"

    def run(self, trigger: Trigger, term: Terminal, config: Config) -> None:
        if "--pdb" not in config.runner_args:
            config.runner_args.append("--pdb")
        trigger.emit_now()


class VerboseCommand(Command):
    character = "v"
    caption = "v"
    description = "increase verbosity (-v)"

    def run(self, trigger: Trigger, term: Terminal, config: Config) -> None:
        if "-v" not in config.runner_args:
            config.runner_args.append("-v")
        trigger.emit_now()


class EraseScreenCommand(Command):
    character = "e"
    caption = "e"
    description = "Erase terminal screen"

    def run(self, trigger: Trigger, term: Terminal, config: Config) -> None:
        term.clear()
        term.print_short_menu(config.runner_args)


class QuitCommand(Command):
    character = "q"
    caption = "q"
    description = "quit pytest-watcher"

    def run(self, trigger: Trigger, term: Terminal, config: Config) -> None:
        sys.exit(0)