From c6e04662542f619ad0be44fa1234e403711ea9de Mon Sep 17 00:00:00 2001 From: David Salvisberg Date: Thu, 11 Apr 2024 09:07:22 +0200 Subject: [PATCH] Add stubs for qrbill (#11741) Co-authored-by: Akuli --- stubs/qrbill/@tests/stubtest_allowlist.txt | 7 + stubs/qrbill/METADATA.toml | 3 + stubs/qrbill/qrbill/__init__.pyi | 1 + stubs/qrbill/qrbill/bill.pyi | 180 +++++++++++++++++++++ 4 files changed, 191 insertions(+) create mode 100644 stubs/qrbill/@tests/stubtest_allowlist.txt create mode 100644 stubs/qrbill/METADATA.toml create mode 100644 stubs/qrbill/qrbill/__init__.pyi create mode 100644 stubs/qrbill/qrbill/bill.pyi diff --git a/stubs/qrbill/@tests/stubtest_allowlist.txt b/stubs/qrbill/@tests/stubtest_allowlist.txt new file mode 100644 index 000000000000..f811d3866278 --- /dev/null +++ b/stubs/qrbill/@tests/stubtest_allowlist.txt @@ -0,0 +1,7 @@ +# Error: is inconsistent +# ====================== +# While the method provides default values for all arguments, the first two +# arguments always need to be provided, so it makes no sense to pretend that +# they are optional +qrbill.QRBill.__init__ +qrbill.bill.QRBill.__init__ diff --git a/stubs/qrbill/METADATA.toml b/stubs/qrbill/METADATA.toml new file mode 100644 index 000000000000..b46abf95c7db --- /dev/null +++ b/stubs/qrbill/METADATA.toml @@ -0,0 +1,3 @@ +version = "1.1.*" +upstream_repository = "https://github.com/claudep/swiss-qr-bill" +requires = ["types-qrcode"] diff --git a/stubs/qrbill/qrbill/__init__.pyi b/stubs/qrbill/qrbill/__init__.pyi new file mode 100644 index 000000000000..995a9dd82092 --- /dev/null +++ b/stubs/qrbill/qrbill/__init__.pyi @@ -0,0 +1 @@ +from .bill import QRBill as QRBill diff --git a/stubs/qrbill/qrbill/bill.pyi b/stubs/qrbill/qrbill/bill.pyi new file mode 100644 index 000000000000..0e2824b0451b --- /dev/null +++ b/stubs/qrbill/qrbill/bill.pyi @@ -0,0 +1,180 @@ +from _typeshed import SupportsWrite +from collections.abc import Iterable, Iterator, Mapping +from decimal import Decimal +from pathlib import Path +from typing import Any, Final, Literal, overload +from typing_extensions import TypeAlias, deprecated + +from qrcode.image.svg import SvgPathImage + +# NOTE: Since svgwrite doesn't have any stubs we provide some type aliases, that +# we can choose to refine in the future, e.g. using a Protocol +_SvgDrawing: TypeAlias = Any # svgwrite.Drawing +_SvgGroup: TypeAlias = Any # svgwrite.container.Group + +# NOTE: Eventually we may want to consider replacing this with typed dicts, even +# if that means disallowing non-dict arguments. It should allow anything +# that is valid to pass into `Address.create`. +_AddressDict: TypeAlias = Mapping[str, str | None] + +IBAN_ALLOWED_COUNTRIES: list[str] +QR_IID: dict[str, int] +AMOUNT_REGEX: str +MM_TO_UU: float +BILL_HEIGHT: int +RECEIPT_WIDTH: str +PAYMENT_WIDTH: str +MAX_CHARS_PAYMENT_LINE: int +MAX_CHARS_RECEIPT_LINE: int +A4: tuple[str, str] +LABELS: dict[str, dict[str, str]] +SCISSORS_SVG_PATH: str + +class Address: + @overload + @classmethod + def create(cls, *, name: str | None = None, line1: str, line2: str | None = None, country: str | None) -> CombinedAddress: ... + @overload + @classmethod + def create(cls, *, name: str | None = None, line1: str | None = None, line2: str, country: str | None) -> CombinedAddress: ... + @overload + @classmethod + def create( + cls, + *, + name: str, + street: str | None = None, + house_num: str | None = None, + pcode: str, + city: str, + country: str | None = None, + ) -> StructuredAddress: ... + @staticmethod + def parse_country(country: str | None) -> str: ... + +class CombinedAddress(Address): + combined: Final = True + name: str + line1: str + line2: str + country: str + def __init__( + self, *, name: str | None = None, line1: str | None = None, line2: str | None = None, country: str | None = None + ) -> None: ... + def data_list(self) -> list[str]: ... + def as_paragraph(self, max_chars: int = 72) -> Iterator[str]: ... + +class StructuredAddress(Address): + combined: Final = False + name: str + street: str + house_num: str + pcode: str + city: str + country: str + def __init__( + self, + *, + name: str | None = None, + street: str | None = None, + house_num: str | None = None, + pcode: str | None = None, + city: str | None = None, + country: str | None = None, + ) -> None: ... + def data_list(self) -> list[str]: ... + def as_paragraph(self, max_chars: int = 72) -> Iterator[str]: ... + +class QRBill: + qr_type: str + version: str + coding: int + allowed_currencies: tuple[Literal["CHF"], Literal["EUR"]] + font_family: str + creditor: CombinedAddress | StructuredAddress + final_creditor: CombinedAddress | StructuredAddress | None + debtor: CombinedAddress | StructuredAddress | None + reference_number: str | None + @overload + def __init__( + self, + account: str, + creditor: _AddressDict, + final_creditor: None = None, + amount: Decimal | str | None = None, + currency: Literal["CHF", "EUR"] = "CHF", + debtor: _AddressDict | None = None, + ref_number: None = None, + reference_number: str | None = None, + extra_infos: Literal[""] = "", + additional_information: str = "", + alt_procs: list[str] | tuple[()] | tuple[str] | tuple[str, str] = (), + language: Literal["en", "de", "fr", "it"] = "en", + top_line: bool = True, + payment_line: bool = True, + font_factor: int = 1, + ) -> None: ... + @deprecated("ref_number is deprecated and replaced by reference_number") + @overload + def __init__( + self, + account: str, + creditor: _AddressDict, + final_creditor: None = None, + amount: Decimal | str | None = None, + currency: Literal["CHF", "EUR"] = "CHF", + debtor: _AddressDict | None = None, + *, + ref_number: str, + reference_number: None = None, + extra_infos: str = "", + additional_information: str = "", + alt_procs: list[str] | tuple[()] | tuple[str] | tuple[str, str] = (), + language: Literal["en", "de", "fr", "it"] = "en", + top_line: bool = True, + payment_line: bool = True, + font_factor: int = 1, + ) -> None: ... + @deprecated("extra_infos is deprecated and replaced by additional_information") + @overload + def __init__( + self, + account: str, + creditor: _AddressDict, + final_creditor: None = None, + amount: Decimal | str | None = None, + currency: Literal["CHF", "EUR"] = "CHF", + debtor: _AddressDict | None = None, + ref_number: None = None, + reference_number: str | None = None, + *, + extra_infos: str, + additional_information: str = "", + alt_procs: list[str] | tuple[()] | tuple[str] | tuple[str, str] = (), + language: Literal["en", "de", "fr", "it"] = "en", + top_line: bool = True, + payment_line: bool = True, + font_factor: int = 1, + ) -> None: ... + @property + def title_font_info(self) -> dict[str, Any]: ... + @property + def font_info(self) -> dict[str, Any]: ... + def head_font_info(self, part: str | None = None) -> dict[str, Any]: ... + @property + def proc_font_info(self) -> dict[str, Any]: ... + def qr_data(self) -> str: ... + def qr_image(self) -> SvgPathImage: ... + def draw_swiss_cross(self, dwg: _SvgDrawing, grp: _SvgGroup, origin: tuple[float, float], size: float) -> None: ... + def draw_blank_rect(self, dwg: _SvgDrawing, grp: _SvgGroup, x: float, y: float, width: float, height: float) -> None: ... + def label(self, txt: str) -> str: ... + def as_svg(self, file_out: str | Path | SupportsWrite[str], full_page: bool = False) -> None: ... + def transform_to_full_page(self, dwg: _SvgDrawing, bill: _SvgGroup) -> None: ... + def draw_bill(self, dwg: _SvgDrawing, horiz_scissors: bool = True) -> _SvgGroup: ... + +def add_mm(*mms: str | float) -> float: ... +def mm(val: str | float) -> float: ... +def format_ref_number(bill: QRBill) -> str: ... +def format_amount(amount_: str | float) -> str: ... +def wrap_infos(infos: Iterable[str]) -> Iterator[str]: ... +def replace_linebreaks(text: str | None) -> str: ...