Skip to content

Commit

Permalink
switch to mypy strict mode
Browse files Browse the repository at this point in the history
  • Loading branch information
FriedrichFroebel committed Oct 28, 2023
1 parent afe701c commit 7c724c3
Show file tree
Hide file tree
Showing 25 changed files with 231 additions and 169 deletions.
2 changes: 1 addition & 1 deletion brother_ql_web/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
def main():
def main() -> None:
import logging

from brother_ql_web import cli, utils, web
Expand Down
13 changes: 9 additions & 4 deletions brother_ql_web/cli.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from __future__ import annotations

import logging
import random
import sys
from argparse import ArgumentParser, Namespace
from typing import cast

from brother_ql.devicedependent import models, label_sizes
from brother_ql_web.configuration import Configuration, Font
Expand All @@ -11,8 +14,8 @@
logger = logging.getLogger(__name__)


def log_level_type(value) -> int:
return getattr(logging, value.upper())
def log_level_type(value: str) -> int:
return cast(int, getattr(logging, value.upper()))


def get_parameters() -> Namespace:
Expand Down Expand Up @@ -73,7 +76,9 @@ class NoFontFound(SystemError):
pass


def _choose_default_font(fonts: dict, configuration: Configuration) -> None:
def _choose_default_font(
fonts: dict[str, dict[str, str]], configuration: Configuration
) -> None:
for font in configuration.label.default_fonts:
try:
fonts[font.family][font.style]
Expand All @@ -96,7 +101,7 @@ def _choose_default_font(fonts: dict, configuration: Configuration) -> None:

def update_configuration_from_parameters(
parameters: Namespace, configuration: Configuration
):
) -> None:
# Server configuration.
if parameters.port:
configuration.server.port = parameters.port
Expand Down
6 changes: 3 additions & 3 deletions brother_ql_web/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class Configuration:
website: WebsiteConfiguration

@classmethod
def from_json(cls, json_file: str):
def from_json(cls, json_file: str) -> Configuration:
with open(json_file, mode="r") as fd:
parsed: dict[str, Any] = json.load(fd)
kwargs: dict[str, Any] = {}
Expand Down Expand Up @@ -70,9 +70,9 @@ class LabelConfiguration:
default_fonts: list[Font] = dataclass_field(default_factory=list)
default_font: Font | None = None

def __post_init__(self):
def __post_init__(self) -> None:
self.default_fonts = [
font if isinstance(font, Font) else Font(**font)
font if isinstance(font, Font) else Font(**font) # type: ignore[arg-type]
for font in self.default_fonts
]

Expand Down
13 changes: 8 additions & 5 deletions brother_ql_web/labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
ROUND_DIE_CUT_LABEL,
label_type_specs,
)
from brother_ql.labels import FormFactor
from brother_ql_web.configuration import Configuration
from brother_ql_web import utils
from PIL import Image, ImageDraw, ImageFont
Expand Down Expand Up @@ -42,8 +43,8 @@ class LabelParameters:
high_quality: bool = True

@property
def kind(self):
return label_type_specs[self.label_size]["kind"]
def kind(self) -> FormFactor:
return cast(FormFactor, label_type_specs[self.label_size]["kind"])

def _scale_margin(self, margin: int) -> int:
return int(self.font_size * margin / 100.0)
Expand Down Expand Up @@ -83,7 +84,9 @@ def font_path(self) -> str:
@property
def width_height(self) -> tuple[int, int]:
try:
width, height = label_type_specs[self.label_size]["dots_printable"]
width, height = cast(
tuple[int, int], label_type_specs[self.label_size]["dots_printable"]
)
except KeyError:
raise LookupError("Unknown label_size")

Expand Down Expand Up @@ -158,7 +161,7 @@ def _determine_text_offsets(
return horizontal_offset, vertical_offset


def create_label_image(parameters: LabelParameters):
def create_label_image(parameters: LabelParameters) -> Image.Image:
image_font = ImageFont.truetype(parameters.font_path, parameters.font_size)

# Workaround for a bug in multiline_textsize()
Expand Down Expand Up @@ -190,7 +193,7 @@ def create_label_image(parameters: LabelParameters):
return image


def image_to_png_bytes(image):
def image_to_png_bytes(image: Image.Image) -> bytes:
image_buffer = BytesIO()
image.save(image_buffer, format="PNG")
image_buffer.seek(0)
Expand Down
20 changes: 14 additions & 6 deletions brother_ql_web/utils.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
from brother_ql.backends import backend_factory, guess_backend
from __future__ import annotations

from typing import cast

from brother_ql.backends import backend_factory, BrotherQLBackendGeneric, guess_backend
from brother_ql.devicedependent import label_type_specs, label_sizes
from brother_ql_web.configuration import Configuration
from brother_ql_web.font_helpers import get_fonts


def collect_fonts(configuration):
def collect_fonts(configuration: Configuration) -> dict[str, dict[str, str]]:
fonts = get_fonts()
if configuration.server.additional_font_folder:
fonts.update(get_fonts(configuration.server.additional_font_folder))
return fonts


def get_label_sizes():
return [(name, label_type_specs[name]["name"]) for name in label_sizes]
def get_label_sizes() -> list[tuple[str, str]]:
return [(name, cast(str, label_type_specs[name]["name"])) for name in label_sizes]


class BackendGuessingError(ValueError):
pass


def get_backend_class(configuration):
def get_backend_class(configuration: Configuration) -> type[BrotherQLBackendGeneric]:
try:
selected_backend = guess_backend(configuration.printer.printer)
except ValueError:
raise BackendGuessingError(
"Couln't guess the backend to use from the printer string descriptor"
)
return backend_factory(selected_backend)["backend_class"]
return cast(
type[BrotherQLBackendGeneric],
backend_factory(selected_backend)["backend_class"],
)
67 changes: 40 additions & 27 deletions brother_ql_web/web.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from __future__ import annotations

import logging
from pathlib import Path
from typing import Any, cast

import bottle
from brother_ql.backends import BrotherQLBackendGeneric
from brother_ql_web.configuration import Configuration
from brother_ql_web.labels import (
LabelParameters,
Expand All @@ -22,34 +26,33 @@ def get_config(key: str) -> object:
return bottle.request.app.config[key]


@bottle.route("/")
def index():
@bottle.route("/") # type: ignore[misc]
def index() -> None:
bottle.redirect("/labeldesigner")


@bottle.route("/static/<filename:path>")
def serve_static(filename):
return bottle.static_file(filename, root=CURRENT_DIRECTORY / "static")
@bottle.route("/static/<filename:path>") # type: ignore[misc]
def serve_static(filename: str) -> bottle.HTTPResponse:
return bottle.static_file(filename, root=str(CURRENT_DIRECTORY / "static"))


@bottle.route("/labeldesigner")
@bottle.jinja2_view("labeldesigner.jinja2")
def labeldesigner():
fonts = get_config("brother_ql_web.fonts")
@bottle.route("/labeldesigner") # type: ignore[misc]
@bottle.jinja2_view("labeldesigner.jinja2") # type: ignore[misc]
def labeldesigner() -> dict[str, Any]:
fonts = cast(dict[str, dict[str, str]], get_config("brother_ql_web.fonts"))
font_family_names = sorted(list(fonts.keys()))
configuration = cast(Configuration, get_config("brother_ql_web.configuration"))
return {
"font_family_names": font_family_names,
"fonts": fonts,
"label_sizes": get_config("brother_ql_web.label_sizes"),
"website": get_config("brother_ql_web.configuration").website,
"label": get_config("brother_ql_web.configuration").label,
"default_orientation": get_config(
"brother_ql_web.configuration"
).label.default_orientation,
"website": configuration.website,
"label": configuration.label,
"default_orientation": configuration.label.default_orientation,
}


def get_label_parameters(request):
def get_label_parameters(request: bottle.BaseRequest) -> LabelParameters:
"""
Might raise LookupError()
"""
Expand Down Expand Up @@ -79,9 +82,9 @@ def get_label_parameters(request):
return LabelParameters(**context)


@bottle.get("/api/preview/text")
@bottle.post("/api/preview/text")
def get_preview_image():
@bottle.get("/api/preview/text") # type: ignore[misc]
@bottle.post("/api/preview/text") # type: ignore[misc]
def get_preview_image() -> bytes:
parameters = get_label_parameters(bottle.request)
image = create_label_image(parameters=parameters)
return_format = bottle.request.query.get("return_format", "png")
Expand All @@ -95,20 +98,20 @@ def get_preview_image():
return image_to_png_bytes(image)


@bottle.post("/api/print/text")
@bottle.get("/api/print/text")
def print_text():
@bottle.post("/api/print/text") # type: ignore[misc]
@bottle.get("/api/print/text") # type: ignore[misc]
def print_text() -> dict[str, bool | str]:
"""
API to print a label
returns: JSON
"""
return_dict = {"success": False}
return_dict: dict[str, bool | str] = {"success": False}

try:
parameters = get_label_parameters(bottle.request)
except LookupError as e:
return_dict["error"] = e.msg
return_dict["error"] = str(e)
return return_dict

if parameters.text is None:
Expand All @@ -117,7 +120,7 @@ def print_text():

qlr = generate_label(
parameters=parameters,
configuration=get_config("brother_ql_web.configuration"),
configuration=cast(Configuration, get_config("brother_ql_web.configuration")),
save_image_to="sample-out.png" if bottle.DEBUG else None,
)

Expand All @@ -126,8 +129,13 @@ def print_text():
print_label(
parameters=parameters,
qlr=qlr,
configuration=get_config("brother_ql_web.configuration"),
backend_class=get_config("brother_ql_web.backend_class"),
configuration=cast(
Configuration, get_config("brother_ql_web.configuration")
),
backend_class=cast(
type[BrotherQLBackendGeneric],
get_config("brother_ql_web.backend_class"),
),
)
except Exception as e:
return_dict["message"] = str(e)
Expand All @@ -140,7 +148,12 @@ def print_text():
return return_dict


def main(configuration: Configuration, fonts, label_sizes, backend_class):
def main(
configuration: Configuration,
fonts: dict[str, dict[str, str]],
label_sizes: list[tuple[str, str]],
backend_class: type[BrotherQLBackendGeneric],
) -> None:
app = bottle.default_app()
app.config["brother_ql_web.configuration"] = configuration
app.config["brother_ql_web.fonts"] = fonts
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ requires = [

[tool.mypy]
mypy_path = '$MYPY_CONFIG_FILE_DIR/stubs'
strict = true
10 changes: 7 additions & 3 deletions stubs/bottle.pyi
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Generated from https://github.com/bottlepy/bottle/blob/master/bottle.py

# mypy: disable-error-code="no-untyped-def,type-arg"

import functools
import pathlib
import threading
Expand Down Expand Up @@ -177,7 +179,8 @@ class BaseRequest:
MEMFILE_MAX: int
environ: Incomplete
def __init__(self, environ: Incomplete | None = ...) -> None: ...
def app(self) -> None: ...
@property
def app(self) -> Bottle: ...
def route(self) -> None: ...
def url_args(self) -> None: ...
@property
Expand All @@ -196,7 +199,8 @@ class BaseRequest:
): ...
def query(self): ...
def forms(self): ...
def params(self): ...
@property
def params(self) -> FormsDict: ...
def files(self): ...
def json(self): ...
@property
Expand Down Expand Up @@ -493,7 +497,7 @@ def static_file(
charset: str = ...,
etag: Incomplete | None = ...,
headers: Incomplete | None = ...,
): ...
) -> HTTPResponse: ...
def debug(mode: bool = ...) -> None: ...
def http_date(value): ...
def parse_date(ims): ...
Expand Down
6 changes: 4 additions & 2 deletions stubs/brother_ql/backends/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@ from _typeshed import Incomplete

available_backends: Incomplete

def guess_backend(identifier): ...
def backend_factory(backend_name): ...
def guess_backend(identifier: str) -> str: ...
def backend_factory(
backend_name: str,
) -> dict[str, list[str] | BrotherQLBackendGeneric]: ...
6 changes: 3 additions & 3 deletions stubs/brother_ql/backends/generic.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ def list_available_devices() -> None: ...
class BrotherQLBackendGeneric:
write_dev: Incomplete
read_dev: Incomplete
def __init__(self, device_specifier) -> None: ...
def write(self, data) -> None: ...
def read(self, length: int = ...): ...
def __init__(self, device_specifier: str) -> None: ...
def write(self, data: bytes) -> None: ...
def read(self, length: int = ...) -> bytes: ...
def dispose(self) -> None: ...
def __del__(self) -> None: ...
4 changes: 2 additions & 2 deletions stubs/brother_ql/backends/helpers.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ from brother_ql.reader import interpret_response as interpret_response

logger: Incomplete

def discover(backend_identifier: str = ...): ...
def discover(backend_identifier: str = ...) -> list[str]: ...
def send(
instructions,
instructions: bytes,
printer_identifier: Incomplete | None = ...,
backend_identifier: Incomplete | None = ...,
blocking: bool = ...,
Expand Down
4 changes: 2 additions & 2 deletions stubs/brother_ql/backends/linux_kernel.pyi
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from .generic import BrotherQLBackendGeneric as BrotherQLBackendGeneric
from _typeshed import Incomplete

def list_available_devices(): ...
def list_available_devices() -> list[dict[str, str | None]]: ...

class BrotherQLBackendLinuxKernel(BrotherQLBackendGeneric):
read_timeout: float
strategy: str
dev: Incomplete
write_dev: Incomplete
read_dev: Incomplete
def __init__(self, device_specifier) -> None: ...
def __init__(self, device_specifier: str) -> None: ...
Loading

0 comments on commit 7c724c3

Please sign in to comment.