Skip to content

Commit

Permalink
Merge pull request #464 from mmaslowskicc/stricter-mypy
Browse files Browse the repository at this point in the history
Use a stricter mypy configuration and annotate test functions
  • Loading branch information
fizyk committed May 31, 2021
2 parents b28bcb8 + eeb1c55 commit 1cf1274
Show file tree
Hide file tree
Showing 15 changed files with 109 additions and 86 deletions.
24 changes: 17 additions & 7 deletions mypy.ini
@@ -1,16 +1,26 @@
[mypy]
allow_redefinition = False
allow_untyped_globals = False
check_untyped_defs = True
show_error_codes = True
mypy_path = src

[mypy-mirakuru.*]
disallow_incomplete_defs = True
disallow_subclassing_any = True
disallow_untyped_calls = True
disallow_untyped_decorators = True
disallow_untyped_defs = True
follow_imports = silent
ignore_missing_imports = False
implicit_reexport = False
no_implicit_optional = True
pretty = True
show_error_codes = True
strict_equality = True
warn_no_return = True
warn_return_any = True
warn_unreachable = True
warn_unused_ignores = True

[mypy-daemon.*]
ignore_missing_imports = True

[mypy-psutil.*]
ignore_missing_imports = True

[mypy-pytest.*]
ignore_missing_imports = True
8 changes: 4 additions & 4 deletions src/mirakuru/base.py
Expand Up @@ -101,7 +101,7 @@ def __init__( # pylint:disable=too-many-arguments
sleep: float = 0.1,
stop_signal: int = signal.SIGTERM,
kill_signal: int = SIGKILL,
expected_returncode: int = None,
expected_returncode: Optional[int] = None,
envvars: Optional[Dict[str, str]] = None,
stdin: Union[None, int, IO[Any]] = subprocess.PIPE,
stdout: Union[None, int, IO[Any]] = subprocess.PIPE,
Expand Down Expand Up @@ -310,8 +310,8 @@ def _kill_all_kids(self, sig: int) -> Set[int]:

def stop(
self: SimpleExecutorType,
stop_signal: int = None,
expected_returncode: int = None,
stop_signal: Optional[int] = None,
expected_returncode: Optional[int] = None,
) -> SimpleExecutorType:
"""
Stop process running.
Expand Down Expand Up @@ -358,7 +358,7 @@ def process_stopped() -> bool:
if self.process is None:
# the process has already been force killed and cleaned up by the
# `wait_for` above.
return self
return self # type: ignore[unreachable]
self._kill_all_kids(stop_signal)
exit_code = self.process.wait()
self._clear_process()
Expand Down
2 changes: 1 addition & 1 deletion src/mirakuru/http.py
Expand Up @@ -39,7 +39,7 @@ def __init__(
self,
command: Union[str, List[str], Tuple[str, ...]],
url: str,
status: str = r"^2\d\d$",
status: Union[str, int] = r"^2\d\d$",
method: str = "HEAD",
payload: Optional[Dict[str, str]] = None,
headers: Optional[Dict[str, str]] = None,
Expand Down
2 changes: 1 addition & 1 deletion tests/__init__.py
Expand Up @@ -18,7 +18,7 @@
HTTP_SERVER_CMD = f"{sys.executable} -m http.server"


def ps_aux():
def ps_aux() -> str:
"""
Return output of systems `ps aux -w` call.
Expand Down
43 changes: 22 additions & 21 deletions tests/executors/test_executor.py
Expand Up @@ -6,6 +6,7 @@
from subprocess import check_output
import uuid
from unittest import mock
from typing import Union, List

import pytest

Expand All @@ -20,7 +21,7 @@


@pytest.mark.parametrize("command", (SLEEP_300, SLEEP_300.split()))
def test_running_process(command):
def test_running_process(command: Union[str, List[str]]) -> None:
"""Start process and shuts it down."""
executor = SimpleExecutor(command)
executor.start()
Expand All @@ -34,15 +35,15 @@ def test_running_process(command):


@pytest.mark.parametrize("command", (SLEEP_300, SLEEP_300.split()))
def test_command(command):
def test_command(command: Union[str, List[str]]) -> None:
"""Check that the command and command parts are equivalent."""

executor = SimpleExecutor(command)
assert executor.command == SLEEP_300
assert executor.command_parts == SLEEP_300.split()


def test_custom_signal_stop():
def test_custom_signal_stop() -> None:
"""Start process and shuts it down using signal SIGQUIT."""
executor = SimpleExecutor(SLEEP_300, stop_signal=signal.SIGQUIT)
executor.start()
Expand All @@ -51,7 +52,7 @@ def test_custom_signal_stop():
assert executor.running() is False


def test_stop_custom_signal_stop():
def test_stop_custom_signal_stop() -> None:
"""Start process and shuts it down using signal SIGQUIT passed to stop."""
executor = SimpleExecutor(SLEEP_300)
executor.start()
Expand All @@ -60,7 +61,7 @@ def test_stop_custom_signal_stop():
assert executor.running() is False


def test_stop_custom_exit_signal_stop():
def test_stop_custom_exit_signal_stop() -> None:
"""Start process and expect it to finish with custom signal."""
executor = SimpleExecutor("false", shell=True)
executor.start()
Expand All @@ -73,7 +74,7 @@ def test_stop_custom_exit_signal_stop():
assert executor.running() is False


def test_stop_custom_exit_signal_context():
def test_stop_custom_exit_signal_context() -> None:
"""Start process and expect custom exit signal in context manager."""
with SimpleExecutor(
"false", expected_returncode=-3, shell=True
Expand All @@ -82,7 +83,7 @@ def test_stop_custom_exit_signal_context():
assert executor.running() is False


def test_running_context():
def test_running_context() -> None:
"""Start process and shuts it down."""
executor = SimpleExecutor(SLEEP_300)
with executor:
Expand All @@ -91,13 +92,13 @@ def test_running_context():
assert executor.running() is False


def test_executor_in_context_only():
def test_executor_in_context_only() -> None:
"""Start process and shuts it down only in context."""
with SimpleExecutor(SLEEP_300) as executor:
assert executor.running() is True


def test_context_stopped():
def test_context_stopped() -> None:
"""Start for context, and shuts it for nested context."""
executor = SimpleExecutor(SLEEP_300)
with executor:
Expand All @@ -113,7 +114,7 @@ def test_context_stopped():


@pytest.mark.parametrize("command", (ECHO_FOOBAR, shlex.split(ECHO_FOOBAR)))
def test_process_output(command):
def test_process_output(command: Union[str, List[str]]) -> None:
"""Start process, check output and shut it down."""
executor = SimpleExecutor(command)
executor.start()
Expand All @@ -123,7 +124,7 @@ def test_process_output(command):


@pytest.mark.parametrize("command", (ECHO_FOOBAR, shlex.split(ECHO_FOOBAR)))
def test_process_output_shell(command):
def test_process_output_shell(command: Union[str, List[str]]) -> None:
"""Start process, check output and shut it down with shell set to True."""
executor = SimpleExecutor(command, shell=True)
executor.start()
Expand All @@ -132,7 +133,7 @@ def test_process_output_shell(command):
executor.stop()


def test_start_check_executor():
def test_start_check_executor() -> None:
"""Validate Executor base class having NotImplemented methods."""
executor = Executor(SLEEP_300)
with pytest.raises(NotImplementedError):
Expand All @@ -141,7 +142,7 @@ def test_start_check_executor():
executor.after_start_check()


def test_stopping_not_yet_running_executor():
def test_stopping_not_yet_running_executor() -> None:
"""
Test if SimpleExecutor can be stopped even it was never running.
Expand All @@ -155,7 +156,7 @@ def test_stopping_not_yet_running_executor():
executor.stop()


def test_forgotten_stop():
def test_forgotten_stop() -> None:
"""
Test if SimpleExecutor subprocess is killed after an instance is deleted.
Expand Down Expand Up @@ -183,7 +184,7 @@ def test_forgotten_stop():
), "The test process should not be running at this point."


def test_executor_raises_if_process_exits_with_error():
def test_executor_raises_if_process_exits_with_error() -> None:
"""
Test process exit detection.
Expand Down Expand Up @@ -211,10 +212,10 @@ def test_executor_raises_if_process_exits_with_error():

# Pre-start check should have been called - after-start check might or
# might not have been called - depending on the timing.
assert failing_executor.pre_start_check.called is True # type: ignore
assert failing_executor.pre_start_check.called is True


def test_executor_ignores_processes_exiting_with_0():
def test_executor_ignores_processes_exiting_with_0() -> None:
"""
Test process exit detection.
Expand All @@ -232,11 +233,11 @@ def test_executor_ignores_processes_exiting_with_0():
executor.start()

# Both checks should have been called.
assert executor.pre_start_check.called is True # type: ignore
assert executor.after_start_check.called is True # type: ignore
assert executor.pre_start_check.called is True
assert executor.after_start_check.called is True


def test_executor_methods_returning_self():
def test_executor_methods_returning_self() -> None:
"""Test if SimpleExecutor lets to chain start, stop and kill methods."""
executor = SimpleExecutor(SLEEP_300).start().stop().kill().stop()
assert not executor.running()
Expand All @@ -251,7 +252,7 @@ def test_executor_methods_returning_self():
assert SimpleExecutor(SLEEP_300).start().stop().output


def test_mirakuru_cleanup():
def test_mirakuru_cleanup() -> None:
"""Test if cleanup_subprocesses is fired correctly on python exit."""
cmd = f"""
python -c 'from mirakuru import SimpleExecutor;
Expand Down
21 changes: 11 additions & 10 deletions tests/executors/test_executor_kill.py
Expand Up @@ -3,6 +3,7 @@
import signal
import time
import sys
from typing import NoReturn, Set

import errno

Expand All @@ -20,7 +21,7 @@
SLEEP_300 = "sleep 300"


def test_custom_signal_kill():
def test_custom_signal_kill() -> None:
"""Start process and shuts it down using signal SIGQUIT."""
executor = SimpleExecutor(SLEEP_300, kill_signal=signal.SIGQUIT)
executor.start()
Expand All @@ -29,7 +30,7 @@ def test_custom_signal_kill():
assert executor.running() is False


def test_kill_custom_signal_kill():
def test_kill_custom_signal_kill() -> None:
"""Start process and shuts it down using signal SIGQUIT passed to kill."""
executor = SimpleExecutor(SLEEP_300)
executor.start()
Expand All @@ -38,14 +39,14 @@ def test_kill_custom_signal_kill():
assert executor.running() is False


def test_already_closed():
def test_already_closed() -> None:
"""Check that the executor cleans after itself after it exited earlier."""
with pytest.raises(ProcessFinishedWithError) as excinfo:
with SimpleExecutor("python") as executor:
assert executor.running()
os.killpg(executor.process.pid, SIGKILL)

def process_stopped():
def process_stopped() -> bool:
"""Return True only only when self.process is not running."""
return executor.running() is False

Expand All @@ -55,7 +56,7 @@ def process_stopped():
assert not executor.process


def test_daemons_killing():
def test_daemons_killing() -> None:
"""
Test if all subprocesses of SimpleExecutor can be killed.
Expand All @@ -75,7 +76,7 @@ def test_daemons_killing():
assert SAMPLE_DAEMON_PATH not in ps_aux()


def test_stopping_brutally():
def test_stopping_brutally() -> None:
"""
Test if SimpleExecutor is stopping insubordinate process.
Expand All @@ -94,7 +95,7 @@ def test_stopping_brutally():
assert stop_at <= time.time(), "Subprocess killed earlier than in 10 secs"


def test_stopping_children_of_stopped_process():
def test_stopping_children_of_stopped_process() -> None:
"""
Check that children exiting between listing and killing are ignored.
Expand All @@ -108,14 +109,14 @@ def test_stopping_children_of_stopped_process():
We ignore and skip OsError indicates there's no such process.
"""
# pylint: disable=protected-access, missing-docstring
def raise_os_error(*_, **__):
def raise_os_error(*_: int, **__: int) -> NoReturn:

os_error = OSError()
os_error.errno = errno.ESRCH
raise os_error

def processes_with_env_mock(*_, **__):
return [1]
def processes_with_env_mock(*_: str, **__: str) -> Set[int]:
return {1}

with patch(
"mirakuru.base.processes_with_env", new=processes_with_env_mock
Expand Down

0 comments on commit 1cf1274

Please sign in to comment.