From 4157cb63ad1f0c3831011a4abb921ec14943b336 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Sun, 7 Apr 2024 12:49:50 +0200 Subject: [PATCH] [qrcode] Add various annotations (#11726) --- stubs/qrcode/@tests/stubtest_allowlist.txt | 4 + stubs/qrcode/qrcode/constants.pyi | 10 ++- stubs/qrcode/qrcode/main.pyi | 86 +++++++++++++++++----- stubs/qrcode/qrcode/util.pyi | 37 ++++++---- 4 files changed, 102 insertions(+), 35 deletions(-) diff --git a/stubs/qrcode/@tests/stubtest_allowlist.txt b/stubs/qrcode/@tests/stubtest_allowlist.txt index 7e06a7706..8010322e7 100644 --- a/stubs/qrcode/@tests/stubtest_allowlist.txt +++ b/stubs/qrcode/@tests/stubtest_allowlist.txt @@ -4,6 +4,10 @@ qrcode\.compat\..* qrcode\.tests qrcode\.tests\..* +# Parameter "data" has unhelpful default value, which creates a QR code with string "None". +qrcode\.make +qrcode\.main\.make + # Stubtest hiccup: It doesn't recognize that the annotated type is a base # class of the default class assigned to the attribute. qrcode\.image\..*\.default_drawer_class diff --git a/stubs/qrcode/qrcode/constants.pyi b/stubs/qrcode/qrcode/constants.pyi index 31bdcb3a6..dc308677f 100644 --- a/stubs/qrcode/qrcode/constants.pyi +++ b/stubs/qrcode/qrcode/constants.pyi @@ -1,4 +1,6 @@ -ERROR_CORRECT_L: int -ERROR_CORRECT_M: int -ERROR_CORRECT_Q: int -ERROR_CORRECT_H: int +from typing import Final + +ERROR_CORRECT_L: Final = 1 +ERROR_CORRECT_M: Final = 0 +ERROR_CORRECT_Q: Final = 3 +ERROR_CORRECT_H: Final = 2 diff --git a/stubs/qrcode/qrcode/main.pyi b/stubs/qrcode/qrcode/main.pyi index 6d77e77a9..63329bb55 100644 --- a/stubs/qrcode/qrcode/main.pyi +++ b/stubs/qrcode/qrcode/main.pyi @@ -1,13 +1,37 @@ -from _typeshed import Incomplete -from typing import Generic, NamedTuple, TypeVar, overload +from _typeshed import ConvertibleToInt, Incomplete +from typing import Any, Generic, Literal, NamedTuple, TypeVar, overload from typing_extensions import TypeAlias -from qrcode.image.base import BaseImage +from .image.base import BaseImage +from .util import QRData, _MaskPattern ModulesType: TypeAlias = list[list[bool | None]] precomputed_qr_blanks: dict[int, ModulesType] -def make(data: Incomplete | None = None, **kwargs): ... +_DefaultImage: TypeAlias = Any # PilImage if Pillow is installed, PyPNGImage otherwise + +@overload +def make( + data: QRData | bytes | str, + *, + version: ConvertibleToInt | None = None, + error_correction: Literal[0, 1, 2, 3] = 0, + box_size: ConvertibleToInt = 10, + border: ConvertibleToInt = 4, + image_factory: None = None, + mask_pattern: _MaskPattern | None = None, +) -> _DefaultImage: ... +@overload +def make( + data: QRData | bytes | str, + *, + version: ConvertibleToInt | None = None, + error_correction: Literal[0, 1, 2, 3] = 0, + box_size: ConvertibleToInt = 10, + border: ConvertibleToInt = 4, + image_factory: type[GenericImage], + mask_pattern: _MaskPattern | None = None, +) -> GenericImage: ... def copy_2d_array(x): ... class ActiveWithNeighbors(NamedTuple): @@ -27,28 +51,54 @@ GenericImageLocal = TypeVar("GenericImageLocal", bound=BaseImage) # noqa: Y001 class QRCode(Generic[GenericImage]): modules: ModulesType - error_correction: Incomplete - box_size: Incomplete - border: Incomplete - image_factory: Incomplete + error_correction: Literal[0, 1, 2, 3] + box_size: int + border: int + image_factory: type[GenericImage] | None + @overload def __init__( self, - version: Incomplete | None = None, - error_correction=0, - box_size: int = 10, - border: int = 4, - image_factory: type[GenericImage] | None = None, - mask_pattern: Incomplete | None = None, + version: ConvertibleToInt | None, + error_correction: Literal[0, 1, 2, 3], + box_size: ConvertibleToInt, + border: ConvertibleToInt, + image_factory: type[GenericImage], + mask_pattern: _MaskPattern | None = None, + ) -> None: ... + @overload + def __init__( + self, + version: ConvertibleToInt | None = None, + error_correction: Literal[0, 1, 2, 3] = 0, + box_size: ConvertibleToInt = 10, + border: ConvertibleToInt = 4, + *, + image_factory: type[GenericImage], + mask_pattern: _MaskPattern | None = None, + ) -> None: ... + @overload + def __init__( + self: QRCode[_DefaultImage], + version: ConvertibleToInt | None = None, + error_correction: Literal[0, 1, 2, 3] = 0, + box_size: ConvertibleToInt = 10, + border: ConvertibleToInt = 4, + image_factory: None = None, + mask_pattern: _MaskPattern | None = None, ) -> None: ... @property def version(self) -> int: ... + @version.setter + def version(self, value: ConvertibleToInt | None) -> None: ... @property - def mask_pattern(self): ... + def mask_pattern(self) -> _MaskPattern | None: ... + @mask_pattern.setter + def mask_pattern(self, pattern: _MaskPattern | None) -> None: ... modules_count: int data_cache: Incomplete data_list: Incomplete def clear(self) -> None: ... - def add_data(self, data, optimize: int = 20) -> None: ... + def add_data(self, data: QRData | bytes | str, optimize: int = 20) -> None: ... def make(self, fit: bool = True) -> None: ... def makeImpl(self, test, mask_pattern) -> None: ... def setup_position_probe_pattern(self, row, col) -> None: ... @@ -57,9 +107,9 @@ class QRCode(Generic[GenericImage]): def print_tty(self, out: Incomplete | None = None) -> None: ... def print_ascii(self, out: Incomplete | None = None, tty: bool = False, invert: bool = False): ... @overload - def make_image(self, image_factory: None = None, **kwargs) -> GenericImage: ... + def make_image(self, image_factory: None = None, **kwargs: Any) -> GenericImage: ... @overload - def make_image(self, image_factory: type[GenericImageLocal], **kwargs) -> GenericImageLocal: ... + def make_image(self, image_factory: type[GenericImageLocal], **kwargs: Any) -> GenericImageLocal: ... def is_constrained(self, row: int, col: int) -> bool: ... def setup_timing_pattern(self) -> None: ... def setup_position_adjust_pattern(self) -> None: ... diff --git a/stubs/qrcode/qrcode/util.pyi b/stubs/qrcode/qrcode/util.pyi index be5b02144..993455589 100644 --- a/stubs/qrcode/qrcode/util.pyi +++ b/stubs/qrcode/qrcode/util.pyi @@ -1,15 +1,21 @@ from _typeshed import Incomplete -from collections.abc import Generator +from collections.abc import Callable, Generator +from typing import Final, Literal, overload +from typing_extensions import TypeAlias from qrcode.base import RSBlock as RSBlock -MODE_NUMBER: Incomplete -MODE_ALPHA_NUM: Incomplete -MODE_8BIT_BYTE: Incomplete -MODE_KANJI: Incomplete +_MaskPattern: TypeAlias = Literal[0, 1, 2, 3, 4, 5, 6, 7] + +MODE_NUMBER: Final = 1 +MODE_ALPHA_NUM: Final = 2 +MODE_8BIT_BYTE: Final = 4 +MODE_KANJI: Final = 8 + MODE_SIZE_SMALL: Incomplete MODE_SIZE_MEDIUM: Incomplete MODE_SIZE_LARGE: Incomplete + ALPHA_NUM: bytes RE_ALPHA_NUM: Incomplete NUMBER_LENGTH: Incomplete @@ -25,21 +31,26 @@ def BCH_type_info(data): ... def BCH_type_number(data): ... def BCH_digit(data): ... def pattern_position(version): ... -def mask_func(pattern): ... +def mask_func(pattern: _MaskPattern) -> Callable[[int, int], bool]: ... def mode_sizes_for_version(version): ... def length_in_bits(mode, version): ... def check_version(version) -> None: ... def lost_point(modules): ... -def optimal_data_chunks(data, minimum: int = 4) -> Generator[Incomplete, None, None]: ... -def to_bytestring(data): ... -def optimal_mode(data): ... +def optimal_data_chunks(data: str | bytes, minimum: int = 4) -> Generator[QRData, None, None]: ... +def to_bytestring(data: str | bytes) -> bytes: ... +def optimal_mode(data) -> Literal[1, 2, 4]: ... class QRData: - mode: Incomplete - data: Incomplete - def __init__(self, data, mode: Incomplete | None = None, check_data: bool = True) -> None: ... + mode: Literal[1, 2, 4] + data: bytes + @overload + def __init__(self, data: bytes | str, mode: Literal[1, 2, 4] | None = None, check_data: Literal[True] = True) -> None: ... + @overload + def __init__(self, data: bytes, mode: Literal[1, 2, 4] | None = None, *, check_data: Literal[False]) -> None: ... + @overload + def __init__(self, data: bytes, mode: Literal[1, 2, 4] | None, check_data: Literal[False]) -> None: ... def __len__(self) -> int: ... - def write(self, buffer) -> None: ... + def write(self, buffer: BitBuffer) -> None: ... class BitBuffer: buffer: Incomplete