diff --git a/pyrightconfig.stricter.json b/pyrightconfig.stricter.json index 05e6455833a1..a3ea8b6478dc 100644 --- a/pyrightconfig.stricter.json +++ b/pyrightconfig.stricter.json @@ -87,7 +87,6 @@ "stubs/pywin32", "stubs/pyxdg", "stubs/PyYAML", - "stubs/qrcode", "stubs/redis", "stubs/reportlab", "stubs/requests", diff --git a/stubs/qrcode/@tests/stubtest_allowlist.txt b/stubs/qrcode/@tests/stubtest_allowlist.txt index 8010322e711b..d7f76b7b226f 100644 --- a/stubs/qrcode/@tests/stubtest_allowlist.txt +++ b/stubs/qrcode/@tests/stubtest_allowlist.txt @@ -4,6 +4,9 @@ qrcode\.compat\..* qrcode\.tests qrcode\.tests\..* +# Stub-only module +qrcode._types + # Parameter "data" has unhelpful default value, which creates a QR code with string "None". qrcode\.make qrcode\.main\.make @@ -12,5 +15,13 @@ qrcode\.main\.make # class of the default class assigned to the attribute. qrcode\.image\..*\.default_drawer_class +# Implementation has marked these methods as abstract without the class +# or its bases deriving from abc.ABCMeta +qrcode\.image\.base\.BaseImage\.(drawrect|new_image|save) + +# The implementation sets this attribute to None on the class but instances +# always set this to a PIL image instance. +qrcode\.image\.styles\.moduledrawers\.(pil\.)?CircleModuleDrawer.circle + # Leaked loop counter qrcode.base.i diff --git a/stubs/qrcode/METADATA.toml b/stubs/qrcode/METADATA.toml index e6451e017d7b..74396fc21bfd 100644 --- a/stubs/qrcode/METADATA.toml +++ b/stubs/qrcode/METADATA.toml @@ -1,5 +1,6 @@ version = "7.4.*" upstream_repository = "https://github.com/lincolnloop/python-qrcode" +requires = ["types-Pillow>=9.1.0"] [tool.stubtest] -extras = ["lxml"] +extras = ["pil"] diff --git a/stubs/qrcode/qrcode/LUT.pyi b/stubs/qrcode/qrcode/LUT.pyi index 8d6b33556d80..2e7f6fa4dd4e 100644 --- a/stubs/qrcode/qrcode/LUT.pyi +++ b/stubs/qrcode/qrcode/LUT.pyi @@ -1,3 +1,3 @@ -from _typeshed import Incomplete +from typing import Final -rsPoly_LUT: Incomplete +rsPoly_LUT: Final[dict[int, list[int]]] diff --git a/stubs/qrcode/qrcode/__init__.pyi b/stubs/qrcode/qrcode/__init__.pyi index 7022363a9885..2109f5de5a0a 100644 --- a/stubs/qrcode/qrcode/__init__.pyi +++ b/stubs/qrcode/qrcode/__init__.pyi @@ -1,3 +1,5 @@ +from _typeshed import ConvertibleToInt + from qrcode import image as image from qrcode.constants import ( ERROR_CORRECT_H as ERROR_CORRECT_H, @@ -5,6 +7,16 @@ from qrcode.constants import ( ERROR_CORRECT_M as ERROR_CORRECT_M, ERROR_CORRECT_Q as ERROR_CORRECT_Q, ) -from qrcode.main import make as make +from qrcode.main import GenericImage, QRCode as QRCode, make as make + +from ._types import ErrorCorrect, MaskPattern -def run_example(data: str = "http://www.lincolnloop.com", *args, **kwargs) -> None: ... +def run_example( + data: str = "http://www.lincolnloop.com", + version: ConvertibleToInt | None = None, + error_correction: ErrorCorrect = 0, + box_size: ConvertibleToInt = 10, + border: ConvertibleToInt = 4, + image_factory: type[GenericImage] | None = None, + mask_pattern: MaskPattern | None = None, +) -> None: ... diff --git a/stubs/qrcode/qrcode/_types.pyi b/stubs/qrcode/qrcode/_types.pyi new file mode 100644 index 000000000000..2fb145fc4fc0 --- /dev/null +++ b/stubs/qrcode/qrcode/_types.pyi @@ -0,0 +1,15 @@ +# Type aliases used in this stub package +from _typeshed import SupportsWrite +from typing import Any, Protocol +from typing_extensions import TypeAlias + +Box: TypeAlias = tuple[tuple[int, int], tuple[int, int]] +Ink: TypeAlias = tuple[int, int, int] | tuple[int, int, int, int] + +# Don't try to make these Literal[x, y, z] as this really wreaks +# havoc with overloads in mypy. +ErrorCorrect: TypeAlias = int +MaskPattern: TypeAlias = int + +class Writeable(SupportsWrite[bytes], Protocol): + def seek(self, offset: int, /) -> Any: ... diff --git a/stubs/qrcode/qrcode/base.pyi b/stubs/qrcode/qrcode/base.pyi index 04785f4a28b4..0b5cd8aa385f 100644 --- a/stubs/qrcode/qrcode/base.pyi +++ b/stubs/qrcode/qrcode/base.pyi @@ -1,25 +1,27 @@ -from _typeshed import Incomplete -from typing import NamedTuple +from collections.abc import Iterator +from typing import NamedTuple, SupportsIndex -EXP_TABLE: Incomplete -LOG_TABLE: Incomplete -RS_BLOCK_OFFSET: Incomplete -RS_BLOCK_TABLE: Incomplete +from ._types import ErrorCorrect -def glog(n): ... -def gexp(n): ... +EXP_TABLE: list[int] +LOG_TABLE: list[int] +RS_BLOCK_OFFSET: dict[ErrorCorrect, int] +RS_BLOCK_TABLE: tuple[tuple[int, int, int] | tuple[int, int, int, int, int, int], ...] + +def glog(n: int) -> int: ... +def gexp(n: int) -> int: ... class Polynomial: - num: Incomplete - def __init__(self, num, shift) -> None: ... - def __getitem__(self, index): ... - def __iter__(self): ... + num: list[int] + def __init__(self, num: list[int], shift: int) -> None: ... + def __getitem__(self, index: SupportsIndex) -> int: ... + def __iter__(self) -> Iterator[int]: ... def __len__(self) -> int: ... - def __mul__(self, other): ... - def __mod__(self, other): ... + def __mul__(self, other: Polynomial) -> Polynomial: ... + def __mod__(self, other: Polynomial) -> Polynomial: ... class RSBlock(NamedTuple): total_count: int data_count: int -def rs_blocks(version, error_correction): ... +def rs_blocks(version: int, error_correction: ErrorCorrect) -> list[RSBlock]: ... diff --git a/stubs/qrcode/qrcode/console_scripts.pyi b/stubs/qrcode/qrcode/console_scripts.pyi index ace65bac112d..44bc8d475a7e 100644 --- a/stubs/qrcode/qrcode/console_scripts.pyi +++ b/stubs/qrcode/qrcode/console_scripts.pyi @@ -1,12 +1,12 @@ -from _typeshed import Incomplete -from collections.abc import Iterable +from collections.abc import Iterable, Sequence -from qrcode.image.base import BaseImage, DrawerAliases as DrawerAliases +from ._types import ErrorCorrect +from .image.base import BaseImage, DrawerAliases as DrawerAliases -default_factories: Incomplete -error_correction: Incomplete +default_factories: dict[str, str] +error_correction: dict[str, ErrorCorrect] -def main(args: Incomplete | None = None) -> None: ... +def main(args: Sequence[str] | None = None) -> None: ... def get_factory(module: str) -> type[BaseImage]: ... def get_drawer_help() -> str: ... def commas(items: Iterable[str], joiner: str = "or") -> str: ... diff --git a/stubs/qrcode/qrcode/image/base.pyi b/stubs/qrcode/qrcode/image/base.pyi index 8fc2a6259a5d..0d43f58698d8 100644 --- a/stubs/qrcode/qrcode/image/base.pyi +++ b/stubs/qrcode/qrcode/image/base.pyi @@ -1,40 +1,46 @@ -import abc -from _typeshed import Incomplete -from typing import Any +from collections.abc import Callable +from typing import IO, Any from typing_extensions import TypeAlias -from qrcode.image.styles.moduledrawers.base import QRModuleDrawer -from qrcode.main import QRCode +from ..main import ModulesType, QRCode +from .styles.moduledrawers.base import QRModuleDrawer +# The second element of the value tuple are keyword arguments used when +# constructing instances of the QRModuleDrawer type. DrawerAliases: TypeAlias = dict[str, tuple[type[QRModuleDrawer], dict[str, Any]]] -class BaseImage(metaclass=abc.ABCMeta): +class BaseImage: kind: str | None allowed_kinds: tuple[str] | None needs_context: bool needs_processing: bool needs_drawrect: bool - border: Incomplete - width: Incomplete - box_size: Incomplete - pixel_size: Incomplete - modules: Incomplete - def __init__(self, border, width, box_size, *args, **kwargs) -> None: ... - @abc.abstractmethod - def drawrect(self, row, col): ... - def drawrect_context(self, row: int, col: int, qr: QRCode[Incomplete]): ... + border: int + width: int + box_size: int + pixel_size: int + modules: list[list[bool | None]] + # the class accepts arbitrary additional positional arguments to accommodate + # subclasses with additional arguments. kwargs are forwarded to the `new_image()` call. + def __init__( + self, border: int, width: int, box_size: int, *args: Any, qrcode_modules: ModulesType | None, **kwargs: Any + ) -> None: ... + def drawrect(self, row: int, col: int) -> None: ... + def drawrect_context(self, row: int, col: int, qr: QRCode[Any]) -> None: ... def process(self) -> None: ... - @abc.abstractmethod - def save(self, stream, kind: Incomplete | None = None): ... - def pixel_box(self, row, col): ... - @abc.abstractmethod - def new_image(self, **kwargs) -> Any: ... + def save(self, stream: IO[bytes], kind: str | None = None) -> None: ... + def pixel_box(self, row: int, col: int) -> tuple[tuple[int, int], tuple[int, int]]: ... + # the new_image method accepts arbitrary keyword arguments to accommodate + # subclasses with additional arguments. + def new_image(self, **kwargs: Any) -> Any: ... def init_new_image(self) -> None: ... - def get_image(self, **kwargs): ... - def check_kind(self, kind, transform: Incomplete | None = None): ... - def is_eye(self, row: int, col: int): ... + # the get_image method accepts arbitrary keyword arguments to accommodate + # subclasses with additional arguments. + def get_image(self, **kwargs: Any) -> Any: ... + def check_kind(self, kind: str | None, transform: Callable[[str | None], str | None] | None = None) -> str | None: ... + def is_eye(self, row: int, col: int) -> bool: ... -class BaseImageWithDrawer(BaseImage, metaclass=abc.ABCMeta): +class BaseImageWithDrawer(BaseImage): default_drawer_class: type[QRModuleDrawer] drawer_aliases: DrawerAliases def get_default_module_drawer(self) -> QRModuleDrawer: ... @@ -42,9 +48,20 @@ class BaseImageWithDrawer(BaseImage, metaclass=abc.ABCMeta): needs_context: bool module_drawer: QRModuleDrawer eye_drawer: QRModuleDrawer + # the class accepts arbitrary additional positional arguments to accommodate + # subclasses with additional arguments. kwargs are forwarded to the `new_image()` call + # via the BaseImage.__init__ method. def __init__( - self, *args, module_drawer: QRModuleDrawer | str | None = None, eye_drawer: QRModuleDrawer | str | None = None, **kwargs + self, + border: int, + width: int, + box_size: int, + *args: Any, + qrcode_modules: ModulesType | None, + module_drawer: QRModuleDrawer | str | None = None, + eye_drawer: QRModuleDrawer | str | None = None, + **kwargs: Any, ) -> None: ... def get_drawer(self, drawer: QRModuleDrawer | str | None) -> QRModuleDrawer | None: ... - def init_new_image(self): ... - def drawrect_context(self, row: int, col: int, qr: QRCode[Incomplete]): ... + def init_new_image(self) -> None: ... + def drawrect_context(self, row: int, col: int, qr: QRCode[Any]) -> None: ... diff --git a/stubs/qrcode/qrcode/image/pil.pyi b/stubs/qrcode/qrcode/image/pil.pyi index 3ae1e00cc0f8..635b069c6550 100644 --- a/stubs/qrcode/qrcode/image/pil.pyi +++ b/stubs/qrcode/qrcode/image/pil.pyi @@ -1,11 +1,30 @@ -from _typeshed import Incomplete +from pathlib import Path +from typing import Any, Literal -import qrcode.image.base +from PIL import Image -class PilImage(qrcode.image.base.BaseImage): - kind: str - fill_color: Incomplete - def new_image(self, **kwargs): ... - def drawrect(self, row, col) -> None: ... - def save(self, stream, format: Incomplete | None = None, **kwargs) -> None: ... # type: ignore[override] - def __getattr__(self, name): ... +from .._types import Writeable +from . import base + +class PilImage(base.BaseImage): + kind: Literal["PNG"] + fill_color: str + # the new_image and get_image methods accept arbitrary keyword arguments to + # accommodate subclasses with additional arguments. + def new_image(self, *, back_color: str = "white", fill_color: str = "black", **kwargs: Any) -> Image.Image: ... + def get_image(self, **kwargs: Any) -> Image.Image: ... + def drawrect(self, row: int, col: int) -> None: ... + # kwargs are passed on to PIL.Image.save, which also accepts arbitrary keyword arguments. + def save( # type: ignore[override] + self, + stream: str | bytes | Path | Writeable, + format: str | None = None, + *, + kind: str | None = None, + save_all: bool = ..., + bitmap_format: Literal["bmp", "png"] = ..., + optimize: bool = ..., + **kwargs: Any, + ) -> None: ... + # attribute access is forwarded to the wrapped PIL.Image.Image instance. + def __getattr__(self, name: str) -> Any: ... diff --git a/stubs/qrcode/qrcode/image/pure.pyi b/stubs/qrcode/qrcode/image/pure.pyi index 36177abe178c..ec5df707f02f 100644 --- a/stubs/qrcode/qrcode/image/pure.pyi +++ b/stubs/qrcode/qrcode/image/pure.pyi @@ -1,16 +1,23 @@ -from _typeshed import Incomplete +from _typeshed import SupportsWrite from collections.abc import Generator +from typing import Any, Literal +from typing_extensions import TypeAlias -import qrcode.image.base +from . import base -class PyPNGImage(qrcode.image.base.BaseImage): +# png.Writer; no types available +_Writer: TypeAlias = Any + +class PyPNGImage(base.BaseImage): kind: str - allowed_kinds: Incomplete - needs_drawrect: bool - def new_image(self, **kwargs): ... - def drawrect(self, row, col) -> None: ... - def save(self, stream, kind: Incomplete | None = None) -> None: ... - def rows_iter(self) -> Generator[Incomplete, Incomplete, None]: ... - def border_rows_iter(self) -> Generator[Incomplete, None, None]: ... + allowed_kinds: tuple[Literal["PNG"]] + # the new_image and get_image methods accept arbitrary keyword arguments to + # accommodate subclasses with additional arguments. + def new_image(self, **kwargs: Any) -> _Writer: ... + def get_image(self, **kwargs: Any) -> _Writer: ... + def drawrect(self, row: int, col: int) -> None: ... + def save(self, stream: SupportsWrite[bytes], kind: str | None = None) -> None: ... + def rows_iter(self) -> Generator[list[int], Any, None]: ... + def border_rows_iter(self) -> Generator[list[int], Any, None]: ... PymagingImage = PyPNGImage diff --git a/stubs/qrcode/qrcode/image/styledpil.pyi b/stubs/qrcode/qrcode/image/styledpil.pyi index 1d2ed26bef00..655b57b7589c 100644 --- a/stubs/qrcode/qrcode/image/styledpil.pyi +++ b/stubs/qrcode/qrcode/image/styledpil.pyi @@ -1,22 +1,56 @@ -import abc -from _typeshed import Incomplete +from _typeshed import SupportsRead +from pathlib import Path +from typing import Any, Literal -import qrcode.image.base -from qrcode.image.styles.colormasks import QRColorMask -from qrcode.image.styles.moduledrawers import SquareModuleDrawer +from PIL import Image -class StyledPilImage(qrcode.image.base.BaseImageWithDrawer, metaclass=abc.ABCMeta): - kind: str - needs_processing: bool +from .._types import Ink, Writeable +from ..main import ModulesType +from . import base +from .styles.colormasks import QRColorMask +from .styles.moduledrawers import SquareModuleDrawer +from .styles.moduledrawers.base import QRModuleDrawer + +class StyledPilImage(base.BaseImageWithDrawer): + kind: Literal["PNG"] color_mask: QRColorMask - default_drawer_class = SquareModuleDrawer - embeded_image: Incomplete - embeded_image_resample: Incomplete - paint_color: Incomplete - def __init__(self, *args, **kwargs) -> None: ... - def new_image(self, **kwargs): ... - def init_new_image(self) -> None: ... - def process(self) -> None: ... + default_drawer_class: type[SquareModuleDrawer] + embeded_image: Image.Image + embeded_image_resample: Image.Resampling + paint_color: Ink + # the class accepts arbitrary additional positional arguments to accommodate + # subclasses with additional arguments. kwargs are forwarded to the `new_image()` call + # via the BaseImage.__init__ method. + def __init__( + self, + border: int, + width: int, + box_size: int, + *args: Any, + qrcode_modules: ModulesType | None, + module_drawer: QRModuleDrawer | str | None = None, + eye_drawer: QRModuleDrawer | str | None = None, + color_mask: QRColorMask = ..., + embeded_image_path: str | bytes | Path | SupportsRead[bytes] | None = None, + embeded_image: Image.Image | None = None, + embeded_image_resample: Image.Resampling = ..., + **kwargs: Any, + ) -> None: ... + # the new_image method accepts arbitrary keyword arguments to accommodate + # subclasses with additional arguments. + def new_image(self, **kwargs: Any) -> Image.Image: ... def draw_embeded_image(self) -> None: ... - def save(self, stream, format: Incomplete | None = None, **kwargs) -> None: ... # type: ignore[override] - def __getattr__(self, name): ... + # kwargs are passed on to PIL.Image.save, which also accepts arbitrary keyword arguments. + def save( # type: ignore[override] + self, + stream: str | bytes | Path | Writeable, + format: str | None = None, + *, + kind: str | None = None, + save_all: bool = ..., + bitmap_format: Literal["bmp", "png"] = ..., + optimize: bool = ..., + **kwargs: Any, + ) -> None: ... + # attribute access is forwarded to the wrapped PIL.Image.Image instance. + def __getattr__(self, name: str) -> Any: ... diff --git a/stubs/qrcode/qrcode/image/styles/colormasks.pyi b/stubs/qrcode/qrcode/image/styles/colormasks.pyi index 12ad288796df..8fdd08621f4f 100644 --- a/stubs/qrcode/qrcode/image/styles/colormasks.pyi +++ b/stubs/qrcode/qrcode/image/styles/colormasks.pyi @@ -1,65 +1,63 @@ -from _typeshed import Incomplete +from _typeshed import SupportsRead +from pathlib import Path + +from PIL import Image + +from ..._types import Ink +from ..styledpil import StyledPilImage class QRColorMask: - back_color: Incomplete + back_color: Ink has_transparency: bool - paint_color = back_color - def initialize(self, styledPilImage, image) -> None: ... - def apply_mask(self, image) -> None: ... - def get_fg_pixel(self, image, x, y) -> None: ... - def get_bg_pixel(self, image, x, y): ... - def interp_num(self, n1, n2, norm): ... - def interp_color(self, col1, col2, norm): ... - def extrap_num(self, n1, n2, interped_num): ... - def extrap_color(self, col1, col2, interped_color): ... + paint_color: Ink + # image is not actually used by any of the initialize implementations in this project. + def initialize(self, styledPilImage: StyledPilImage, image: Image.Image) -> None: ... + def apply_mask(self, image: Image.Image) -> None: ... + def get_fg_pixel(self, image: Image.Image, x: int, y: int) -> Ink: ... + def get_bg_pixel(self, image: Image.Image, x: int, y: int) -> Ink: ... + def interp_num(self, n1: int, n2: int, norm: float) -> int: ... + def interp_color(self, col1: Ink, col2: Ink, norm: float) -> Ink: ... + def extrap_num(self, n1: int, n2: int, interped_num: int) -> float | None: ... + def extrap_color(self, col1: Ink, col2: Ink, interped_color: Ink) -> float | None: ... class SolidFillColorMask(QRColorMask): - back_color: Incomplete - front_color: Incomplete - has_transparency: Incomplete - def __init__(self, back_color=(255, 255, 255), front_color=(0, 0, 0)) -> None: ... - def apply_mask(self, image) -> None: ... - def get_fg_pixel(self, image, x, y): ... + front_color: Ink + def __init__(self, back_color: Ink = (255, 255, 255), front_color: Ink = (0, 0, 0)) -> None: ... class RadialGradiantColorMask(QRColorMask): - back_color: Incomplete - center_color: Incomplete - edge_color: Incomplete - has_transparency: Incomplete - def __init__(self, back_color=(255, 255, 255), center_color=(0, 0, 0), edge_color=(0, 0, 255)) -> None: ... - def get_fg_pixel(self, image, x, y): ... + center_color: Ink + edge_color: Ink + def __init__( + self, back_color: Ink = (255, 255, 255), center_color: Ink = (0, 0, 0), edge_color: Ink = (0, 0, 255) + ) -> None: ... class SquareGradiantColorMask(QRColorMask): - back_color: Incomplete - center_color: Incomplete - edge_color: Incomplete - has_transparency: Incomplete - def __init__(self, back_color=(255, 255, 255), center_color=(0, 0, 0), edge_color=(0, 0, 255)) -> None: ... - def get_fg_pixel(self, image, x, y): ... + center_color: Ink + edge_color: Ink + def __init__( + self, back_color: Ink = (255, 255, 255), center_color: Ink = (0, 0, 0), edge_color: Ink = (0, 0, 255) + ) -> None: ... class HorizontalGradiantColorMask(QRColorMask): - back_color: Incomplete - left_color: Incomplete - right_color: Incomplete - has_transparency: Incomplete - def __init__(self, back_color=(255, 255, 255), left_color=(0, 0, 0), right_color=(0, 0, 255)) -> None: ... - def get_fg_pixel(self, image, x, y): ... + left_color: Ink + right_color: Ink + def __init__( + self, back_color: Ink = (255, 255, 255), left_color: Ink = (0, 0, 0), right_color: Ink = (0, 0, 255) + ) -> None: ... class VerticalGradiantColorMask(QRColorMask): - back_color: Incomplete - top_color: Incomplete - bottom_color: Incomplete - has_transparency: Incomplete - def __init__(self, back_color=(255, 255, 255), top_color=(0, 0, 0), bottom_color=(0, 0, 255)) -> None: ... - def get_fg_pixel(self, image, x, y): ... + top_color: Ink + bottom_color: Ink + def __init__( + self, back_color: Ink = (255, 255, 255), top_color: Ink = (0, 0, 0), bottom_color: Ink = (0, 0, 255) + ) -> None: ... class ImageColorMask(QRColorMask): - back_color: Incomplete - color_img: Incomplete - has_transparency: Incomplete + color_img: Ink def __init__( - self, back_color=(255, 255, 255), color_mask_path: Incomplete | None = None, color_mask_image: Incomplete | None = None + self, + back_color: Ink = (255, 255, 255), + color_mask_path: str | bytes | Path | SupportsRead[bytes] | None = None, + color_mask_image: Image.Image | None = None, ) -> None: ... - paint_color: Incomplete - def initialize(self, styledPilImage, image) -> None: ... - def get_fg_pixel(self, image, x, y): ... + paint_color: Ink diff --git a/stubs/qrcode/qrcode/image/styles/moduledrawers/base.pyi b/stubs/qrcode/qrcode/image/styles/moduledrawers/base.pyi index 917c1ac41424..74832b09b966 100644 --- a/stubs/qrcode/qrcode/image/styles/moduledrawers/base.pyi +++ b/stubs/qrcode/qrcode/image/styles/moduledrawers/base.pyi @@ -1,12 +1,12 @@ import abc -from _typeshed import Incomplete -from qrcode.image.base import BaseImage +from ...._types import Box +from ....main import ActiveWithNeighbors +from ...base import BaseImage class QRModuleDrawer(abc.ABC, metaclass=abc.ABCMeta): - needs_neighbors: bool - def __init__(self, **kwargs) -> None: ... - img: Incomplete + needs_neighbors: bool = False + img: BaseImage def initialize(self, img: BaseImage) -> None: ... @abc.abstractmethod - def drawrect(self, box, is_active) -> None: ... + def drawrect(self, box: Box, is_active: bool | ActiveWithNeighbors) -> None: ... diff --git a/stubs/qrcode/qrcode/image/styles/moduledrawers/pil.pyi b/stubs/qrcode/qrcode/image/styles/moduledrawers/pil.pyi index e5c4e94b7c4f..637091661493 100644 --- a/stubs/qrcode/qrcode/image/styles/moduledrawers/pil.pyi +++ b/stubs/qrcode/qrcode/image/styles/moduledrawers/pil.pyi @@ -1,9 +1,12 @@ import abc -from _typeshed import Incomplete +from typing import Literal -from qrcode.image.styledpil import StyledPilImage -from qrcode.image.styles.moduledrawers.base import QRModuleDrawer -from qrcode.main import ActiveWithNeighbors +from PIL import Image, ImageDraw + +from ...._types import Box +from ....main import ActiveWithNeighbors +from ...styledpil import StyledPilImage +from .base import QRModuleDrawer ANTIALIASING_FACTOR: int @@ -11,59 +14,53 @@ class StyledPilQRModuleDrawer(QRModuleDrawer, metaclass=abc.ABCMeta): img: StyledPilImage class SquareModuleDrawer(StyledPilQRModuleDrawer): - imgDraw: Incomplete - def initialize(self, *args, **kwargs) -> None: ... - def drawrect(self, box, is_active: bool): ... + imgDraw: ImageDraw.ImageDraw + def drawrect(self, box: Box, is_active: bool) -> None: ... # type: ignore[override] class GappedSquareModuleDrawer(StyledPilQRModuleDrawer): - size_ratio: Incomplete + size_ratio: float def __init__(self, size_ratio: float = 0.8) -> None: ... - imgDraw: Incomplete - delta: Incomplete - def initialize(self, *args, **kwargs) -> None: ... - def drawrect(self, box, is_active: bool): ... + imgDraw: ImageDraw.ImageDraw + delta: float + def drawrect(self, box: Box, is_active: bool) -> None: ... # type: ignore[override] class CircleModuleDrawer(StyledPilQRModuleDrawer): - circle: Incomplete - def initialize(self, *args, **kwargs) -> None: ... - def drawrect(self, box, is_active: bool): ... + circle: Image.Image + def drawrect(self, box: Box, is_active: bool) -> None: ... # type: ignore[override] class RoundedModuleDrawer(StyledPilQRModuleDrawer): - needs_neighbors: bool - radius_ratio: Incomplete - def __init__(self, radius_ratio: int = 1) -> None: ... - corner_width: Incomplete - def initialize(self, *args, **kwargs) -> None: ... - SQUARE: Incomplete - NW_ROUND: Incomplete - SW_ROUND: Incomplete - SE_ROUND: Incomplete - NE_ROUND: Incomplete + needs_neighbors: Literal[True] + radius_ratio: float + def __init__(self, radius_ratio: float = 1) -> None: ... + corner_width: int + SQUARE: Image.Image + NW_ROUND: Image.Image + SW_ROUND: Image.Image + SE_ROUND: Image.Image + NE_ROUND: Image.Image def setup_corners(self) -> None: ... - def drawrect(self, box: list[list[int]], is_active: ActiveWithNeighbors): ... + def drawrect(self, box: Box, is_active: ActiveWithNeighbors) -> None: ... # type: ignore[override] class VerticalBarsDrawer(StyledPilQRModuleDrawer): - needs_neighbors: bool - horizontal_shrink: Incomplete + needs_neighbors: Literal[True] + horizontal_shrink: float def __init__(self, horizontal_shrink: float = 0.8) -> None: ... - half_height: Incomplete - delta: Incomplete - def initialize(self, *args, **kwargs) -> None: ... - SQUARE: Incomplete - ROUND_TOP: Incomplete - ROUND_BOTTOM: Incomplete + half_height: int + delta: int + SQUARE: Image.Image + ROUND_TOP: Image.Image + ROUND_BOTTOM: Image.Image def setup_edges(self) -> None: ... - def drawrect(self, box, is_active: ActiveWithNeighbors): ... + def drawrect(self, box: Box, is_active: ActiveWithNeighbors) -> None: ... # type: ignore[override] class HorizontalBarsDrawer(StyledPilQRModuleDrawer): - needs_neighbors: bool - vertical_shrink: Incomplete + needs_neighbors: Literal[True] + vertical_shrink: float def __init__(self, vertical_shrink: float = 0.8) -> None: ... - half_width: Incomplete - delta: Incomplete - def initialize(self, *args, **kwargs) -> None: ... - SQUARE: Incomplete - ROUND_LEFT: Incomplete - ROUND_RIGHT: Incomplete + half_width: int + delta: int + SQUARE: Image.Image + ROUND_LEFT: Image.Image + ROUND_RIGHT: Image.Image def setup_edges(self) -> None: ... - def drawrect(self, box, is_active: ActiveWithNeighbors): ... + def drawrect(self, box: Box, is_active: ActiveWithNeighbors) -> None: ... # type: ignore[override] diff --git a/stubs/qrcode/qrcode/image/styles/moduledrawers/svg.pyi b/stubs/qrcode/qrcode/image/styles/moduledrawers/svg.pyi index 8ff91c13e06d..dbbaa5653931 100644 --- a/stubs/qrcode/qrcode/image/styles/moduledrawers/svg.pyi +++ b/stubs/qrcode/qrcode/image/styles/moduledrawers/svg.pyi @@ -1,10 +1,11 @@ import abc -from _typeshed import Incomplete from decimal import Decimal -from typing import NamedTuple +from typing import Any, NamedTuple +from xml.etree.ElementTree import Element, QName -from qrcode.image.styles.moduledrawers.base import QRModuleDrawer -from qrcode.image.svg import SvgFragmentImage, SvgPathImage +from ...._types import Box +from ...svg import SvgFragmentImage, SvgPathImage +from .base import QRModuleDrawer ANTIALIASING_FACTOR: int @@ -18,42 +19,38 @@ class Coords(NamedTuple): class BaseSvgQRModuleDrawer(QRModuleDrawer, metaclass=abc.ABCMeta): img: SvgFragmentImage - size_ratio: Incomplete - def __init__(self, *, size_ratio: Decimal = ..., **kwargs) -> None: ... - box_delta: Incomplete - box_size: Incomplete - box_half: Incomplete - def initialize(self, *args, **kwargs) -> None: ... - def coords(self, box) -> Coords: ... + size_ratio: Decimal + # kwargs are used to allow for subclasses with additional keyword arguments + def __init__(self, *, size_ratio: Decimal = ..., **kwargs: Any) -> None: ... + box_delta: float + box_size: Decimal + box_half: Decimal + def coords(self, box: Box) -> Coords: ... class SvgQRModuleDrawer(BaseSvgQRModuleDrawer, metaclass=abc.ABCMeta): tag: str - tag_qname: Incomplete - def initialize(self, *args, **kwargs) -> None: ... - def drawrect(self, box, is_active: bool): ... + tag_qname: QName + def drawrect(self, box: Box, is_active: bool) -> None: ... # type: ignore[override] @abc.abstractmethod - def el(self, box): ... + def el(self, box: Box) -> Element: ... class SvgSquareDrawer(SvgQRModuleDrawer): - unit_size: Incomplete - def initialize(self, *args, **kwargs) -> None: ... - def el(self, box): ... + unit_size: str + def el(self, box: Box) -> Element: ... class SvgCircleDrawer(SvgQRModuleDrawer): tag: str - radius: Incomplete - def initialize(self, *args, **kwargs) -> None: ... - def el(self, box): ... + radius: str + def el(self, box: Box) -> Element: ... class SvgPathQRModuleDrawer(BaseSvgQRModuleDrawer, metaclass=abc.ABCMeta): img: SvgPathImage - def drawrect(self, box, is_active: bool): ... + def drawrect(self, box: Box, is_active: bool) -> None: ... # type: ignore[override] @abc.abstractmethod - def subpath(self, box) -> str: ... + def subpath(self, box: Box) -> str: ... class SvgPathSquareDrawer(SvgPathQRModuleDrawer): - def subpath(self, box) -> str: ... + def subpath(self, box: Box) -> str: ... class SvgPathCircleDrawer(SvgPathQRModuleDrawer): - def initialize(self, *args, **kwargs) -> None: ... - def subpath(self, box) -> str: ... + def subpath(self, box: Box) -> str: ... diff --git a/stubs/qrcode/qrcode/image/svg.pyi b/stubs/qrcode/qrcode/image/svg.pyi index 73f50127b1c3..a1f95c6984f2 100644 --- a/stubs/qrcode/qrcode/image/svg.pyi +++ b/stubs/qrcode/qrcode/image/svg.pyi @@ -1,38 +1,63 @@ import abc -from _typeshed import Incomplete from decimal import Decimal -from typing import Literal, overload +from typing import Any, Literal, overload from xml.etree.ElementTree import Element -import qrcode.image.base -from qrcode.image.styles.moduledrawers.base import QRModuleDrawer +from . import base +from .styles.moduledrawers.base import QRModuleDrawer -class SvgFragmentImage(qrcode.image.base.BaseImageWithDrawer, metaclass=abc.ABCMeta): +class SvgFragmentImage(base.BaseImageWithDrawer, metaclass=abc.ABCMeta): kind: str - allowed_kinds: Incomplete + allowed_kinds: tuple[Literal["SVG"]] default_drawer_class: type[QRModuleDrawer] - unit_size: Incomplete - def __init__(self, *args, **kwargs) -> None: ... + unit_size: Decimal | str @overload def units(self, pixels: int | Decimal, text: Literal[False]) -> Decimal: ... @overload def units(self, pixels: int | Decimal, text: Literal[True] = True) -> str: ... - def save(self, stream, kind: Incomplete | None = None) -> None: ... - def to_string(self, **kwargs): ... - def new_image(self, **kwargs): ... + # to_string is delegated to ET.Element.tostring, which dictates the overload + # options here. + @overload + def to_string( + self, + *, + encoding: None = None, + method: str | None = None, + xml_declaration: bool | None = None, + default_namespace: str | None = None, + short_empty_elements: bool = True, + ) -> bytes: ... + @overload + def to_string( + self, + *, + encoding: Literal["unicode"], + method: str | None = None, + xml_declaration: bool | None = None, + default_namespace: str | None = None, + short_empty_elements: bool = True, + ) -> str: ... + @overload + def to_string( + self, + *, + encoding: str, + method: str | None = None, + xml_declaration: bool | None = None, + default_namespace: str | None = None, + short_empty_elements: bool = True, + ) -> Any: ... + # the new_image method accepts arbitrary keyword arguments to accommodate + # subclasses with additional arguments. + def new_image(self, **kwargs: Any) -> Element: ... class SvgImage(SvgFragmentImage, metaclass=abc.ABCMeta): background: str | None - drawer_aliases: qrcode.image.base.DrawerAliases + drawer_aliases: base.DrawerAliases class SvgPathImage(SvgImage, metaclass=abc.ABCMeta): - QR_PATH_STYLE: Incomplete - needs_processing: bool + QR_PATH_STYLE: dict[str, str] path: Element | None - default_drawer_class: type[QRModuleDrawer] - drawer_aliases: Incomplete - def __init__(self, *args, **kwargs) -> None: ... - def process(self) -> None: ... class SvgFillImage(SvgImage, metaclass=abc.ABCMeta): background: str diff --git a/stubs/qrcode/qrcode/main.pyi b/stubs/qrcode/qrcode/main.pyi index 63329bb55e2b..09a7b7a16eca 100644 --- a/stubs/qrcode/qrcode/main.pyi +++ b/stubs/qrcode/qrcode/main.pyi @@ -1,38 +1,43 @@ -from _typeshed import ConvertibleToInt, Incomplete -from typing import Any, Generic, Literal, NamedTuple, TypeVar, overload +from _typeshed import ConvertibleToInt +from collections.abc import Sequence +from typing import Any, Generic, NamedTuple, Protocol, TypeVar, overload, type_check_only from typing_extensions import TypeAlias +from ._types import ErrorCorrect, MaskPattern from .image.base import BaseImage -from .util import QRData, _MaskPattern +from .image.pil import PilImage +from .image.pure import PyPNGImage +from .util import QRData ModulesType: TypeAlias = list[list[bool | None]] precomputed_qr_blanks: dict[int, ModulesType] -_DefaultImage: TypeAlias = Any # PilImage if Pillow is installed, PyPNGImage otherwise +_DefaultImage: TypeAlias = PilImage | PyPNGImage # PilImage if Pillow is installed, PyPNGImage otherwise +_AnySeq = TypeVar("_AnySeq", bound=Sequence[Any]) @overload def make( data: QRData | bytes | str, *, version: ConvertibleToInt | None = None, - error_correction: Literal[0, 1, 2, 3] = 0, + error_correction: ErrorCorrect = 0, box_size: ConvertibleToInt = 10, border: ConvertibleToInt = 4, image_factory: None = None, - mask_pattern: _MaskPattern | 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, + error_correction: ErrorCorrect = 0, box_size: ConvertibleToInt = 10, border: ConvertibleToInt = 4, image_factory: type[GenericImage], - mask_pattern: _MaskPattern | None = None, + mask_pattern: MaskPattern | None = None, ) -> GenericImage: ... -def copy_2d_array(x): ... +def copy_2d_array(x: Sequence[_AnySeq]) -> list[_AnySeq]: ... class ActiveWithNeighbors(NamedTuple): NW: bool @@ -49,9 +54,15 @@ class ActiveWithNeighbors(NamedTuple): GenericImage = TypeVar("GenericImage", bound=BaseImage) # noqa: Y001 GenericImageLocal = TypeVar("GenericImageLocal", bound=BaseImage) # noqa: Y001 +@type_check_only +class _TTYWriter(Protocol): + def isatty(self) -> bool: ... + def write(self, s: str, /) -> object: ... + def flush(self) -> object: ... + class QRCode(Generic[GenericImage]): modules: ModulesType - error_correction: Literal[0, 1, 2, 3] + error_correction: ErrorCorrect box_size: int border: int image_factory: type[GenericImage] | None @@ -59,53 +70,55 @@ class QRCode(Generic[GenericImage]): def __init__( self, version: ConvertibleToInt | None, - error_correction: Literal[0, 1, 2, 3], + error_correction: ErrorCorrect, box_size: ConvertibleToInt, border: ConvertibleToInt, image_factory: type[GenericImage], - mask_pattern: _MaskPattern | None = None, + mask_pattern: MaskPattern | None = None, ) -> None: ... @overload def __init__( self, version: ConvertibleToInt | None = None, - error_correction: Literal[0, 1, 2, 3] = 0, + error_correction: ErrorCorrect = 0, box_size: ConvertibleToInt = 10, border: ConvertibleToInt = 4, *, image_factory: type[GenericImage], - mask_pattern: _MaskPattern | None = None, + mask_pattern: MaskPattern | None = None, ) -> None: ... @overload def __init__( self: QRCode[_DefaultImage], version: ConvertibleToInt | None = None, - error_correction: Literal[0, 1, 2, 3] = 0, + error_correction: ErrorCorrect = 0, box_size: ConvertibleToInt = 10, border: ConvertibleToInt = 4, image_factory: None = None, - mask_pattern: _MaskPattern | 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) -> _MaskPattern | None: ... + def mask_pattern(self) -> MaskPattern | None: ... @mask_pattern.setter - def mask_pattern(self, pattern: _MaskPattern | None) -> None: ... + def mask_pattern(self, pattern: MaskPattern | None) -> None: ... modules_count: int - data_cache: Incomplete - data_list: Incomplete + data_cache: list[int] + data_list: list[QRData] def clear(self) -> 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: ... - def best_fit(self, start: Incomplete | None = None): ... - def best_mask_pattern(self): ... - def print_tty(self, out: Incomplete | None = None) -> None: ... - def print_ascii(self, out: Incomplete | None = None, tty: bool = False, invert: bool = False): ... + def makeImpl(self, test: bool, mask_pattern: MaskPattern) -> None: ... + def setup_position_probe_pattern(self, row: int, col: int) -> None: ... + def best_fit(self, start: int | None = None) -> int: ... + def best_mask_pattern(self) -> int: ... + def print_tty(self, out: _TTYWriter | None = None) -> None: ... + def print_ascii(self, out: _TTYWriter | None = None, tty: bool = False, invert: bool = False) -> None: ... + # kwargs are passed on to the specific image factory used, and in turn passed through to + # their make_image method. @overload def make_image(self, image_factory: None = None, **kwargs: Any) -> GenericImage: ... @overload @@ -113,8 +126,8 @@ class QRCode(Generic[GenericImage]): def is_constrained(self, row: int, col: int) -> bool: ... def setup_timing_pattern(self) -> None: ... def setup_position_adjust_pattern(self) -> None: ... - def setup_type_number(self, test) -> None: ... - def setup_type_info(self, test, mask_pattern) -> None: ... - def map_data(self, data, mask_pattern) -> None: ... - def get_matrix(self): ... + def setup_type_number(self, test: bool) -> None: ... + def setup_type_info(self, test: bool, mask_pattern: MaskPattern) -> None: ... + def map_data(self, data: Sequence[int], mask_pattern: MaskPattern) -> None: ... + def get_matrix(self) -> list[list[bool]]: ... def active_with_neighbors(self, row: int, col: int) -> ActiveWithNeighbors: ... diff --git a/stubs/qrcode/qrcode/release.pyi b/stubs/qrcode/qrcode/release.pyi index eac4d5241953..823dd58f3e15 100644 --- a/stubs/qrcode/qrcode/release.pyi +++ b/stubs/qrcode/qrcode/release.pyi @@ -1 +1 @@ -def update_manpage(data) -> None: ... +def update_manpage(data: dict[str, str]) -> None: ... diff --git a/stubs/qrcode/qrcode/util.pyi b/stubs/qrcode/qrcode/util.pyi index 993455589c3e..df4832c5d11d 100644 --- a/stubs/qrcode/qrcode/util.pyi +++ b/stubs/qrcode/qrcode/util.pyi @@ -1,65 +1,69 @@ -from _typeshed import Incomplete from collections.abc import Callable, Generator +from re import Pattern from typing import Final, Literal, overload from typing_extensions import TypeAlias -from qrcode.base import RSBlock as RSBlock +from ._types import ErrorCorrect, MaskPattern +from .base import RSBlock as RSBlock -_MaskPattern: TypeAlias = Literal[0, 1, 2, 3, 4, 5, 6, 7] +MODE_NUMBER: Final[int] = 1 +MODE_ALPHA_NUM: Final[int] = 2 +MODE_8BIT_BYTE: Final[int] = 4 +MODE_KANJI: Final[int] = 8 -MODE_NUMBER: Final = 1 -MODE_ALPHA_NUM: Final = 2 -MODE_8BIT_BYTE: Final = 4 -MODE_KANJI: Final = 8 +_MODE: TypeAlias = Literal[1, 2, 4, 8] -MODE_SIZE_SMALL: Incomplete -MODE_SIZE_MEDIUM: Incomplete -MODE_SIZE_LARGE: Incomplete +MODE_SIZE_SMALL: Final[dict[_MODE, int]] +MODE_SIZE_MEDIUM: Final[dict[_MODE, int]] +MODE_SIZE_LARGE: Final[dict[_MODE, int]] -ALPHA_NUM: bytes -RE_ALPHA_NUM: Incomplete -NUMBER_LENGTH: Incomplete -PATTERN_POSITION_TABLE: Incomplete -G15: Incomplete -G18: Incomplete -G15_MASK: Incomplete -PAD0: int -PAD1: int -BIT_LIMIT_TABLE: Incomplete +ALPHA_NUM: Final[bytes] +RE_ALPHA_NUM: Final[Pattern[bytes]] +NUMBER_LENGTH: Final[dict[int, int]] +PATTERN_POSITION_TABLE: Final[list[list[int]]] +G15: Final[int] +G18: Final[int] +G15_MASK: Final[int] +PAD0: Final[int] +PAD1: Final[int] +BIT_LIMIT_TABLE: Final[list[list[int]]] -def BCH_type_info(data): ... -def BCH_type_number(data): ... -def BCH_digit(data): ... -def pattern_position(version): ... -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): ... +# In the implementation, MODE_KANJI is not accepted in all places +_SupportedMode: TypeAlias = Literal[1, 2, 4] + +def BCH_type_info(data: int) -> int: ... +def BCH_type_number(data: int) -> int: ... +def BCH_digit(data: int) -> int: ... +def pattern_position(version: int) -> list[int]: ... +def mask_func(pattern: MaskPattern) -> Callable[[int, int], bool]: ... +def mode_sizes_for_version(version: int) -> dict[_MODE, int]: ... +def length_in_bits(mode: _MODE, version: int) -> int: ... +def check_version(version: int) -> None: ... +def lost_point(modules: list[list[bool | None]]) -> int: ... 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]: ... +def optimal_mode(data: bytes) -> _SupportedMode: ... class QRData: - mode: Literal[1, 2, 4] + mode: _SupportedMode data: bytes @overload - def __init__(self, data: bytes | str, mode: Literal[1, 2, 4] | None = None, check_data: Literal[True] = True) -> None: ... + def __init__(self, data: bytes | str, mode: _SupportedMode | 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: ... + def __init__(self, data: bytes, mode: _SupportedMode | 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 __init__(self, data: bytes, mode: _SupportedMode | None, check_data: Literal[False]) -> None: ... def __len__(self) -> int: ... def write(self, buffer: BitBuffer) -> None: ... class BitBuffer: - buffer: Incomplete + buffer: list[int] length: int def __init__(self) -> None: ... - def get(self, index): ... - def put(self, num, length) -> None: ... + def get(self, index: int) -> bool: ... + def put(self, num: int, length: int) -> None: ... def __len__(self) -> int: ... - def put_bit(self, bit) -> None: ... + def put_bit(self, bit: bool) -> None: ... -def create_bytes(buffer: BitBuffer, rs_blocks: list[RSBlock]): ... -def create_data(version, error_correction, data_list): ... +def create_bytes(buffer: BitBuffer, rs_blocks: list[RSBlock]) -> list[int]: ... +def create_data(version: int, error_correction: ErrorCorrect, data_list: list[QRData]) -> list[int]: ...