Skip to content

Commit

Permalink
Merge pull request NixOS#258165 from Mic92/nixos-tests-cleanup
Browse files Browse the repository at this point in the history
nixos/test-driver: modernize project setup and switch to new, stricter linting/type checking settings
  • Loading branch information
tfc authored Sep 30, 2023
2 parents cad9cf0 + f1450e6 commit 7b22218
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 71 deletions.
20 changes: 10 additions & 10 deletions nixos/lib/test-driver/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@
, qemu_pkg ? qemu_test
, coreutils
, imagemagick_light
, libtiff
, netpbm
, qemu_test
, socat
, ruff
, tesseract4
, vde2
, extraPythonPackages ? (_ : [])
}:

python3Packages.buildPythonApplication rec {
python3Packages.buildPythonApplication {
pname = "nixos-test-driver";
version = "1.1";
src = ./.;
format = "pyproject";

propagatedBuildInputs = [
coreutils
Expand All @@ -31,14 +32,13 @@ python3Packages.buildPythonApplication rec {
++ extraPythonPackages python3Packages;

doCheck = true;
nativeCheckInputs = with python3Packages; [ mypy pylint black ];
nativeCheckInputs = with python3Packages; [ mypy ruff black ];
checkPhase = ''
mypy --disallow-untyped-defs \
--no-implicit-optional \
--pretty \
--no-color-output \
--ignore-missing-imports ${src}/test_driver
pylint --errors-only --enable=unused-import ${src}/test_driver
black --check --diff ${src}/test_driver
echo -e "\x1b[32m## run mypy\x1b[0m"
mypy test_driver extract-docstrings.py
echo -e "\x1b[32m## run ruff\x1b[0m"
ruff .
echo -e "\x1b[32m## run black\x1b[0m"
black --check --diff .
'';
}
42 changes: 25 additions & 17 deletions nixos/lib/test-driver/extract-docstrings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import ast
import sys
from pathlib import Path

"""
This program takes all the Machine class methods and prints its methods in
Expand Down Expand Up @@ -40,27 +41,34 @@ def some_function(self, param1, param2):
"""

assert len(sys.argv) == 2

with open(sys.argv[1], "r") as f:
module = ast.parse(f.read())
def main() -> None:
if len(sys.argv) != 2:
print(f"Usage: {sys.argv[0]} <path-to-test-driver>")
sys.exit(1)

class_definitions = (node for node in module.body if isinstance(node, ast.ClassDef))
module = ast.parse(Path(sys.argv[1]).read_text())

machine_class = next(filter(lambda x: x.name == "Machine", class_definitions))
assert machine_class is not None
class_definitions = (node for node in module.body if isinstance(node, ast.ClassDef))

function_definitions = [
node for node in machine_class.body if isinstance(node, ast.FunctionDef)
]
function_definitions.sort(key=lambda x: x.name)
machine_class = next(filter(lambda x: x.name == "Machine", class_definitions))
assert machine_class is not None

for f in function_definitions:
docstr = ast.get_docstring(f)
if docstr is not None:
args = ", ".join((a.arg for a in f.args.args[1:]))
args = f"({args})"
function_definitions = [
node for node in machine_class.body if isinstance(node, ast.FunctionDef)
]
function_definitions.sort(key=lambda x: x.name)

docstr = "\n".join((f" {l}" for l in docstr.strip().splitlines()))
for function in function_definitions:
docstr = ast.get_docstring(function)
if docstr is not None:
args = ", ".join(a.arg for a in function.args.args[1:])
args = f"({args})"

print(f"{f.name}{args}\n\n:{docstr[1:]}\n")
docstr = "\n".join(f" {line}" for line in docstr.strip().splitlines())

print(f"{function.name}{args}\n\n:{docstr[1:]}\n")


if __name__ == "__main__":
main()
44 changes: 44 additions & 0 deletions nixos/lib/test-driver/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "nixos-test-driver"
version = "0.0.0"

[project.scripts]
nixos-test-driver = "test_driver:main"
generate-driver-symbols = "test_driver:generate_driver_symbols"

[tool.setuptools.packages]
find = {}

[tool.setuptools.package-data]
test_driver = ["py.typed"]

[tool.ruff]
line-length = 88

select = ["E", "F", "I", "U", "N"]
ignore = ["E501"]

# xxx: we can import https://pypi.org/project/types-colorama/ here
[[tool.mypy.overrides]]
module = "colorama.*"
ignore_missing_imports = true

[[tool.mypy.overrides]]
module = "ptpython.*"
ignore_missing_imports = true

[tool.black]
line-length = 88
target-version = ['py39']
include = '\.pyi?$'

[tool.mypy]
python_version = "3.10"
warn_redundant_casts = true
disallow_untyped_calls = true
disallow_untyped_defs = true
no_implicit_optional = true
14 changes: 0 additions & 14 deletions nixos/lib/test-driver/setup.py

This file was deleted.

2 changes: 2 additions & 0 deletions nixos/lib/test-driver/shell.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
with import ../../.. {};
pkgs.callPackage ./default.nix {}
11 changes: 5 additions & 6 deletions nixos/lib/test-driver/test_driver/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from pathlib import Path
import argparse
import ptpython.repl
import os
import time
from pathlib import Path

import ptpython.repl

from test_driver.logger import rootlog
from test_driver.driver import Driver
from test_driver.logger import rootlog


class EnvDefault(argparse.Action):
Expand All @@ -25,9 +26,7 @@ def __init__(self, envvar, required=False, default=None, nargs=None, **kwargs):
)
if required and default:
required = False
super(EnvDefault, self).__init__(
default=default, required=required, nargs=nargs, **kwargs
)
super().__init__(default=default, required=required, nargs=nargs, **kwargs)

def __call__(self, parser, namespace, values, option_string=None): # type: ignore
setattr(namespace, self.dest, values)
Expand Down
8 changes: 4 additions & 4 deletions nixos/lib/test-driver/test_driver/driver.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from contextlib import contextmanager
from pathlib import Path
from typing import Any, Dict, Iterator, List, Union, Optional, Callable, ContextManager
import os
import re
import tempfile
from contextlib import contextmanager
from pathlib import Path
from typing import Any, Callable, ContextManager, Dict, Iterator, List, Optional, Union

from test_driver.logger import rootlog
from test_driver.machine import Machine, NixStartScript, retry
from test_driver.vlan import VLan
from test_driver.polling_condition import PollingCondition
from test_driver.vlan import VLan


def get_tmp_dir() -> Path:
Expand Down
14 changes: 9 additions & 5 deletions nixos/lib/test-driver/test_driver/logger.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
from colorama import Style, Fore
from contextlib import contextmanager
from typing import Any, Dict, Iterator
from queue import Queue, Empty
from xml.sax.saxutils import XMLGenerator
# mypy: disable-error-code="no-untyped-call"
# drop the above line when mypy is upgraded to include
# https://github.com/python/typeshed/commit/49b717ca52bf0781a538b04c0d76a5513f7119b8
import codecs
import os
import sys
import time
import unicodedata
from contextlib import contextmanager
from queue import Empty, Queue
from typing import Any, Dict, Iterator
from xml.sax.saxutils import XMLGenerator

from colorama import Fore, Style


class Logger:
Expand Down
20 changes: 10 additions & 10 deletions nixos/lib/test-driver/test_driver/machine.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
from contextlib import _GeneratorContextManager, nullcontext
from pathlib import Path
from queue import Queue
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple
import base64
import io
import os
Expand All @@ -16,6 +12,10 @@
import tempfile
import threading
import time
from contextlib import _GeneratorContextManager, nullcontext
from pathlib import Path
from queue import Queue
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple

from test_driver.logger import rootlog

Expand Down Expand Up @@ -236,14 +236,14 @@ class LegacyStartCommand(StartCommand):

def __init__(
self,
netBackendArgs: Optional[str] = None,
netFrontendArgs: Optional[str] = None,
netBackendArgs: Optional[str] = None, # noqa: N803
netFrontendArgs: Optional[str] = None, # noqa: N803
hda: Optional[Tuple[Path, str]] = None,
cdrom: Optional[str] = None,
usb: Optional[str] = None,
bios: Optional[str] = None,
qemuBinary: Optional[str] = None,
qemuFlags: Optional[str] = None,
qemuBinary: Optional[str] = None, # noqa: N803
qemuFlags: Optional[str] = None, # noqa: N803
):
if qemuBinary is not None:
self._cmd = qemuBinary
Expand Down Expand Up @@ -599,7 +599,7 @@ def execute(
return (-1, output.decode())

# Get the return code
self.shell.send("echo ${PIPESTATUS[0]}\n".encode())
self.shell.send(b"echo ${PIPESTATUS[0]}\n")
rc = int(self._next_newline_closed_block_from_shell().strip())

return (rc, output.decode(errors="replace"))
Expand Down Expand Up @@ -1132,7 +1132,7 @@ def shutdown(self) -> None:
return

assert self.shell
self.shell.send("poweroff\n".encode())
self.shell.send(b"poweroff\n")
self.wait_for_shutdown()

def crash(self) -> None:
Expand Down
8 changes: 4 additions & 4 deletions nixos/lib/test-driver/test_driver/polling_condition.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Callable, Optional
from math import isfinite
import time
from math import isfinite
from typing import Callable, Optional

from .logger import rootlog


class PollingConditionFailed(Exception):
class PollingConditionError(Exception):
pass


Expand Down Expand Up @@ -60,7 +60,7 @@ def check(self, force: bool = False) -> bool:

def maybe_raise(self) -> None:
if not self.check():
raise PollingConditionFailed(self.status_message(False))
raise PollingConditionError(self.status_message(False))

def status_message(self, status: bool) -> str:
return f"Polling condition {'succeeded' if status else 'failed'}: {self.description}"
Expand Down
2 changes: 1 addition & 1 deletion nixos/lib/test-driver/test_driver/vlan.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from pathlib import Path
import io
import os
import pty
import subprocess
from pathlib import Path

from test_driver.logger import rootlog

Expand Down

0 comments on commit 7b22218

Please sign in to comment.