Full type coverage with mypy

This commit is contained in:
Cian Hughes
2023-11-01 16:41:15 +00:00
parent baf5962f34
commit df07bc2bc4
7 changed files with 70 additions and 29 deletions

17
poetry.lock generated
View File

@@ -328,6 +328,21 @@ websocket-client = ">=0.32.0"
[package.extras]
ssh = ["paramiko (>=2.4.3)"]
[[package]]
name = "docker-stubs"
version = "0.1.0"
description = "Stubs package for the Python Docker API."
optional = false
python-versions = "^3.8"
files = []
develop = false
[package.source]
type = "git"
url = "https://github.com/rdozier-work/docker-stubs"
reference = "HEAD"
resolved_reference = "9de7906804ae912f1d644c97b617ac77e784fca8"
[[package]]
name = "executing"
version = "2.0.1"
@@ -1092,4 +1107,4 @@ h11 = ">=0.9.0,<1"
[metadata]
lock-version = "2.0"
python-versions = "^3.12"
content-hash = "c74d1dcf762e5266d41c81b62bef444f065124fede9b3a34176cd9a6b93d9c2b"
content-hash = "0da96ff6654ff4c33b776829e34f78ba2725a0de30980ec5eaab86a8b7abbead"

View File

@@ -25,6 +25,7 @@ black = "^23.10.1"
snoop = "^0.4.3"
pytest = "^7.4.3"
mypy = "^1.6.1"
docker-stubs = {git = "https://github.com/rdozier-work/docker-stubs"}
[tool.poetry.scripts]
node_deployer = "node_deployer.__main__:main"

View File

@@ -81,8 +81,11 @@ def convert_json_via_fuelignition(
bytestream = io.BytesIO(b"".join(chunk for chunk in filestream))
bytestream.seek(0)
tar = tarfile.open(fileobj=bytestream)
container_image = tar.extractfile(tar.getmembers()[0].name)
if container_image is None:
raise Exception("Failed to extract image from tarfile")
with open(host_image_path, "wb+") as f:
f.write(tar.extractfile(tar.getmembers()[0].name).read())
f.write(container_image.read())
def build_fuelignition() -> docker.models.images.Image:

View File

@@ -1,5 +1,6 @@
from pathlib import Path
from types import SimpleNamespace
from typing import Union
import docker
import tomllib
@@ -9,7 +10,7 @@ CLIENT = docker.from_env(version="auto")
MAX_PORT: int = 65535
PROJECT_ROOT: Path = Path(__file__).parent.parent.parent.absolute()
type ConfigLabel = str | list[str]
ConfigLabel = Union[str, list[str]] # After PEP695 support: type ConfigLabel = str | list[str]
class Config(SimpleNamespace):

View File

@@ -1,19 +1,20 @@
from fnmatch import fnmatch
import ipaddress
from typing import Annotated
from typing import Annotated, Optional, Union
from docker.types import Mount
import typer
from typing import Tuple
from .config import config
from .cli import cli_spinner
from .config import config
from .create_img import create_img
from .debug import debug_guard
from .utils import ensure_build_dir
type IPAddress = ipaddress.IPv4Address | ipaddress.IPv6Address
# When PEP695 is supported this line should be:
# type IPAddress = ipaddress.IPv4Address | ipaddress.IPv6Address
IPAddress = Union[ipaddress.IPv4Address, ipaddress.IPv6Address]
def filter_validation_response(response: str) -> str:
@@ -60,18 +61,18 @@ def validation_result() -> str:
)
if config.CLEANUP_IMAGES:
image.remove(force=True)
return response
return response.decode()
@cli_spinner(description="Validating ignition image", total=None)
def validate() -> Tuple[bool, str]:
def validate() -> tuple[bool, str]:
"""Validates the ignition image
Returns:
Tuple[bool, str]: A tuple containing a boolean indicating whether
tuple[bool, str]: A tuple containing a boolean indicating whether
the validation was successful and the response from the validation
"""
response = validation_result().decode()
response = validation_result()
response = filter_validation_response(response)
return (not bool(response), response)
@@ -96,7 +97,7 @@ def write_disk(disk: str) -> None:
@ensure_build_dir
def create_ignition_disk(
disk: Annotated[
str,
Optional[str],
typer.Option(
"--disk",
"-d",
@@ -114,7 +115,7 @@ def create_ignition_disk(
),
] = "node",
password: Annotated[
str,
Optional[str],
typer.Option(
"--password",
"-p",
@@ -125,7 +126,7 @@ def create_ignition_disk(
),
] = None,
switch_ip: Annotated[
IPAddress,
Optional[IPAddress],
typer.Option(
"--switch-ip",
"-ip",
@@ -146,7 +147,7 @@ def create_ignition_disk(
),
] = 4789,
swarm_token: Annotated[
str,
Optional[str],
typer.Option(
"--swarm-token",
"-t",
@@ -194,6 +195,10 @@ def create_ignition_disk(
Raises:
typer.Exit: Exit CLI if the ignition image is invalid
"""
# Guard against the user specifying no disk
if disk is None:
raise typer.BadParameter("No disk specified")
create_img(
hostname = hostname,
password = password,

View File

@@ -1,18 +1,19 @@
import ipaddress
import json
from pathlib import Path
from typing import Annotated
from typing import Annotated, Optional, Union
import typer
from .config import config
from .autoignition import json_to_img
from .cli import cli_spinner
from .config import config
from .debug import debug_guard
from .utils import ensure_build_dir
type IPAddress = ipaddress.IPv4Address | ipaddress.IPv6Address
# When PEP695 is supported this line should be:
# type IPAddress = ipaddress.IPv4Address | ipaddress.IPv6Address
IPAddress = Union[ipaddress.IPv4Address, ipaddress.IPv6Address]
def load_template() -> dict:
@@ -99,7 +100,7 @@ def create_img(
),
] = "node",
password: Annotated[
str,
Optional[str],
typer.Option(
"--password",
"-p",
@@ -110,7 +111,7 @@ def create_img(
),
] = None,
switch_ip: Annotated[
IPAddress,
Optional[IPAddress],
typer.Option(
"--switch-ip",
"-ip",
@@ -131,7 +132,7 @@ def create_img(
),
] = 4789,
swarm_token: Annotated[
str,
Optional[str],
typer.Option(
"--swarm-token",
"-t",
@@ -194,10 +195,13 @@ def create_img(
}
)
# Guards against the user not specifying a password
if password is None:
raise typer.BadParameter("Password must be specified")
# Create ignition configuration
ignition_config = load_template()
ignition_config = apply_ignition_settings(
ignition_config,
load_template(),
hostname,
password,
swarm_config,

View File

@@ -1,12 +1,14 @@
from typing import Any, Dict
import typer
from .config import config
from .autoignition import json_to_img
from .config import config
from .create_disk import create_ignition_disk
from .create_img import create_img
cmd_params = {
cmd_params: Dict[Any, Any] = {
"no_args_is_help": True,
}
@@ -15,9 +17,19 @@ app = typer.Typer(
**cmd_params,
)
app.command(**cmd_params)(create_img)
app.command(**cmd_params)(create_ignition_disk)
app.command(**cmd_params)(json_to_img)
# Register commands
app.command(
help = str(create_ignition_disk.__doc__).split("Args:")[0].strip(),
**cmd_params
)(create_ignition_disk)
app.command(
help = str(create_img.__doc__).split("Args:")[0].strip(),
**cmd_params
)(create_img)
app.command(
help = str(json_to_img.__doc__).split("Args:")[0].strip(),
**cmd_params
)(json_to_img)
if __name__ == "__main__":
config.update_config("cli")