Skip to content

Commit

Permalink
Refactor chapter_06 pattern to pass mypy and flake8 checks
Browse files Browse the repository at this point in the history
  • Loading branch information
balancy committed Oct 3, 2023
1 parent ca869a1 commit a9be0d3
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 6 deletions.
1 change: 1 addition & 0 deletions patterns/chapter_06_command/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Init file for chapter_06_command package."""
22 changes: 22 additions & 0 deletions 06_command/commands.py → patterns/chapter_06_command/commands.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,61 @@
"""Abstract base command class and two implementations."""

from abc import ABC, abstractmethod

from .receivers import Receiver


class Command(ABC):
"""Abstract base command class."""

def __init__(self, receiver: Receiver) -> None:
"""Initialize with a receiver instance."""
self._receiver = receiver

@abstractmethod
def execute(self) -> None:
"""Execute the command."""
...

@abstractmethod
def undo(self) -> None:
"""Undo the command."""
...

def __repr__(self) -> str:
"""Return the command representation."""
return self.__class__.__name__


class TurnDeviceOnCommand(Command):
"""Abstract command class implementation.
Command is reponsible for turning device on.
"""

def execute(self) -> None:
"""Execute the command."""
print(f'Executing "{self._receiver}" turning on.')
self._receiver.on()

def undo(self) -> None:
"""Undo the command."""
print(f'Undoing "{self._receiver}" turning on.')
self._receiver.off()


class TurnDeviceOffCommand(Command):
"""Abstract command class implementation.
Command is reponsible for turning device off.
"""

def execute(self) -> None:
"""Execute the command."""
print(f'Executing "{self._receiver}" turning off.')
self._receiver.off()

def undo(self) -> None:
"""Undo the command."""
print(f'Undoing "{self._receiver}" turning off.')
self._receiver.on()
11 changes: 11 additions & 0 deletions 06_command/invokers.py → patterns/chapter_06_command/invokers.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
"""Invoker class. It will handle commands queue and execute them one by one."""


from collections import deque

from .commands import Command


class Invoker:
"""Invoker class."""

def __init__(self) -> None:
"""Initialize with empty commands queue."""
self._commands: deque[Command] = deque()
self._executed_commands: deque[Command] = deque()

def set_commands(self, commands: deque[Command]) -> None:
"""Set commands queue."""
self._commands = commands

def set_command(self, command: Command) -> None:
"""Add a single command to the command queue."""
self._commands.append(command)

def execute_command(self) -> None:
"""Execute the first command in the command queue."""
if self._commands:
command = self._commands.popleft()
print(f'"{command}" is executing')
Expand All @@ -24,6 +33,7 @@ def execute_command(self) -> None:
print(f'"{command}" is executed')

def undo_command(self) -> None:
"""Undo the last executed command."""
if self._executed_commands:
last_command = self._executed_commands.pop()
print(f'"{last_command}" is undoing')
Expand All @@ -34,4 +44,5 @@ def undo_command(self) -> None:

@property
def commands(self) -> deque[Command]:
"""Return commands queue."""
return self._commands
12 changes: 8 additions & 4 deletions 06_command/main.py → patterns/chapter_06_command/main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
"""Main entrypoint for the Command pattern example."""

from collections import deque

from .commands import Command, TurnDeviceOffCommand, TurnDeviceOnCommand
from .invokers import Invoker
from .receivers import TV, BedroomLight, KitchenLight, Receiver


def run() -> None:
def run_pattern_example() -> None:
"""Test command pattern example.
Commands called by Invoker should work correctly.
"""
bedroom_light: Receiver = BedroomLight()
kitchen_light: Receiver = KitchenLight()
tv: Receiver = TV()
Expand All @@ -21,19 +27,17 @@ def run() -> None:

auto_remote_control: Invoker = Invoker()

# executing sentence of commands
auto_remote_control.set_commands(commands)

for _ in range(len(commands)):
auto_remote_control.execute_command()
print('-' * 20)

# trying to undo and reexecute the last command
auto_remote_control.undo_command()
print('-' * 20)

auto_remote_control.execute_command()


if __name__ == '__main__':
run()
run_pattern_example()
Original file line number Diff line number Diff line change
@@ -1,38 +1,57 @@
"""Abstract receiver class and 3 its implementations."""

from abc import ABC, abstractmethod


class Receiver(ABC):
"""Abstract receiver class."""

@abstractmethod
def on(self) -> None:
"""Abstract method for turning the receiver on."""
...

@abstractmethod
def off(self) -> None:
"""Abstract method for turning the receiver off."""
...

def __repr__(self) -> str:
"""Return the receiver representation."""
return self.__class__.__name__


class KitchenLight(Receiver):
"""Kitchen light as receiver class implementation."""

def on(self) -> None:
"""Turn the kitchen light on."""
print('Kitchen light is turned on.')

def off(self) -> None:
"""Turn the kitchen light off."""
print('Kitchen light is turned off.')


class BedroomLight(Receiver):
"""Bedroom light as receiver class implementation."""

def on(self) -> None:
"""Turn the bedroom light on."""
print('Bedroom light is turned on.')

def off(self) -> None:
"""Turn the bedroom light off."""
print('Bedroom light is turned off.')


class TV(Receiver):
"""TV as receiver class implementation."""

def on(self) -> None:
"""Turn the TV on."""
print('TV is turned on.')

def off(self) -> None:
"""Turn the TV off."""
print('TV is turned off.')
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ addopts = [
[tool.coverage.run]
omit = [
"*/main.py",
"patterns/chapter_06_command/*",
]
parallel = true

Expand All @@ -42,7 +43,6 @@ show_missing = true

[tool.mypy]
exclude = [
"06_command/*",
"07_adapter/*",
"08_facade/*",
"09_template_method/*",
Expand Down
1 change: 0 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ exclude =
.git,
__pycache__,
.venv,
06_command/*,
07_adapter/*,
08_facade/*,
09_template_method/*

0 comments on commit a9be0d3

Please sign in to comment.