diff --git a/pyrightconfig.stricter.json b/pyrightconfig.stricter.json index c6a46f89c902..06d11f1a33b9 100644 --- a/pyrightconfig.stricter.json +++ b/pyrightconfig.stricter.json @@ -31,7 +31,6 @@ "stubs/cryptography", "stubs/dateparser", "stubs/docutils", - "stubs/ExifRead", "stubs/Flask-Migrate", "stubs/Flask-SQLAlchemy", "stubs/fpdf2", diff --git a/stubs/ExifRead/@tests/stubtest_allowlist.txt b/stubs/ExifRead/@tests/stubtest_allowlist.txt index 7c1f341af01e..7a1262f27a14 100644 --- a/stubs/ExifRead/@tests/stubtest_allowlist.txt +++ b/stubs/ExifRead/@tests/stubtest_allowlist.txt @@ -1,3 +1,6 @@ +# Stub-only module. +exifread._types + # The following constants are only re-exported at runtime as a side effect # of Python's import system. exifread.DEFAULT_STOP_TAG diff --git a/stubs/ExifRead/exifread/__init__.pyi b/stubs/ExifRead/exifread/__init__.pyi index e4646f82f300..c8b41bc1aceb 100644 --- a/stubs/ExifRead/exifread/__init__.pyi +++ b/stubs/ExifRead/exifread/__init__.pyi @@ -1,7 +1,17 @@ -from _typeshed import Incomplete +from logging import Logger +from typing import Any -logger: Incomplete +from ._types import Reader + +__version__: str +logger: Logger def process_file( - fh, stop_tag=..., details: bool = ..., strict: bool = ..., debug: bool = ..., truncate_tags: bool = ..., auto_seek: bool = ... -): ... + fh: Reader, + stop_tag: str = ..., + details: bool = ..., + strict: bool = ..., + debug: bool = ..., + truncate_tags: bool = ..., + auto_seek: bool = ..., +) -> dict[str, Any]: ... diff --git a/stubs/ExifRead/exifread/_types.pyi b/stubs/ExifRead/exifread/_types.pyi new file mode 100644 index 000000000000..819d7c1065a9 --- /dev/null +++ b/stubs/ExifRead/exifread/_types.pyi @@ -0,0 +1,14 @@ +# Stubs-only module with type aliases for ExifRead. + +from typing import Any, Protocol +from typing_extensions import Literal, TypeAlias + +# The second item of the value tuple - if it exists - can be a variety of types, +# including a callable or another dict. +TagDict: TypeAlias = dict[int, tuple[str] | tuple[str, Any]] + +class Reader(Protocol): + def __iter__(self) -> bytes: ... + def read(self, __size: int) -> bytes: ... + def tell(self) -> int: ... + def seek(self, __offset: int, __whence: Literal[0, 1] = ...) -> object: ... diff --git a/stubs/ExifRead/exifread/classes.pyi b/stubs/ExifRead/exifread/classes.pyi index 697f374c0585..669fb7414d6e 100644 --- a/stubs/ExifRead/exifread/classes.pyi +++ b/stubs/ExifRead/exifread/classes.pyi @@ -1,42 +1,48 @@ -from _typeshed import Incomplete +from logging import Logger +from typing import Any +from typing_extensions import Literal -logger: Incomplete +from ._types import Reader, TagDict + +logger: Logger class IfdTag: - printable: Incomplete - tag: Incomplete - field_type: Incomplete - field_offset: Incomplete - field_length: Incomplete - values: Incomplete - def __init__(self, printable: str, tag: int, field_type: int, values, field_offset: int, field_length: int) -> None: ... + printable: str + tag: int + field_type: int + field_offset: int + field_length: int + values: Any # either string, bytes or list of data items + def __init__(self, printable: str, tag: int, field_type: int, values: Any, field_offset: int, field_length: int) -> None: ... class ExifHeader: - file_handle: Incomplete - endian: Incomplete - offset: Incomplete - fake_exif: Incomplete - strict: Incomplete - debug: Incomplete - detailed: Incomplete - truncate_tags: Incomplete - tags: Incomplete + file_handle: Reader + endian: Literal["I", "M"] + offset: int + fake_exif: bool + strict: bool + debug: bool + detailed: bool + truncate_tags: bool + tags: dict[str, Any] def __init__( self, - file_handle, - endian, - offset, - fake_exif, + file_handle: Reader, + endian: Literal["I", "M"], + offset: int, + fake_exif: bool, strict: bool, debug: bool = ..., detailed: bool = ..., truncate_tags: bool = ..., ) -> None: ... - def s2n(self, offset, length: int, signed: bool = ...) -> int: ... - def n2b(self, offset, length) -> bytes: ... - def list_ifd(self) -> list[Incomplete]: ... - def dump_ifd(self, ifd, ifd_name: str, tag_dict: Incomplete | None = ..., relative: int = ..., stop_tag=...) -> None: ... + def s2n(self, offset: int, length: int, signed: bool = ...) -> int: ... + def n2b(self, offset: int, length: int) -> bytes: ... + def list_ifd(self) -> list[int]: ... + def dump_ifd( + self, ifd: int, ifd_name: str, tag_dict: TagDict | None = ..., relative: int = ..., stop_tag: str = ... + ) -> None: ... def extract_tiff_thumbnail(self, thumb_ifd: int) -> None: ... def extract_jpeg_thumbnail(self) -> None: ... def decode_maker_note(self) -> None: ... - def parse_xmp(self, xmp_bytes: bytes): ... + def parse_xmp(self, xmp_bytes: bytes) -> None: ... diff --git a/stubs/ExifRead/exifread/exif_log.pyi b/stubs/ExifRead/exifread/exif_log.pyi index a3afd67b4ce9..15899f4da288 100644 --- a/stubs/ExifRead/exifread/exif_log.pyi +++ b/stubs/ExifRead/exifread/exif_log.pyi @@ -1,5 +1,5 @@ import logging -from _typeshed import Incomplete +from typing import TextIO TEXT_NORMAL: int TEXT_BOLD: int @@ -10,16 +10,15 @@ TEXT_BLUE: int TEXT_MAGENTA: int TEXT_CYAN: int -def get_logger(): ... -def setup_logger(debug, color) -> None: ... +def get_logger() -> logging.Logger: ... +def setup_logger(debug: bool, color: bool) -> None: ... class Formatter(logging.Formatter): - color: Incomplete - debug: Incomplete + color: bool + debug: bool def __init__(self, debug: bool = ..., color: bool = ...) -> None: ... - def format(self, record): ... -class Handler(logging.StreamHandler[Incomplete]): - color: Incomplete - debug: Incomplete - def __init__(self, log_level, debug: bool = ..., color: bool = ...) -> None: ... +class Handler(logging.StreamHandler[TextIO]): + color: bool + debug: bool + def __init__(self, log_level: logging._Level, debug: bool = ..., color: bool = ...) -> None: ... diff --git a/stubs/ExifRead/exifread/heic.pyi b/stubs/ExifRead/exifread/heic.pyi index 046ea2ca247e..7fd0e1f839e3 100644 --- a/stubs/ExifRead/exifread/heic.pyi +++ b/stubs/ExifRead/exifread/heic.pyi @@ -1,7 +1,9 @@ -from _typeshed import Incomplete from collections.abc import Callable +from logging import Logger -logger: Incomplete +from ._types import Reader + +logger: Logger class WrongBox(Exception): ... class NoParser(Exception): ... @@ -15,10 +17,10 @@ class Box: size: int after: int pos: int - compat: list[Incomplete] + compat: list[bytes] base_offset: int subs: dict[str, Box] - locs: dict[Incomplete, Incomplete] + locs: dict[int, list[tuple[int, int]]] exif_infe: Box | None item_id: int item_type: bytes @@ -30,25 +32,25 @@ class Box: base_offset_size: int index_size: int flags: int - name: Incomplete + name: str def __init__(self, name: str) -> None: ... - def set_sizes(self, offset: int, length: int, base_offset: int, index: int): ... - def set_full(self, vflags: int): ... + def set_sizes(self, offset: int, length: int, base_offset: int, index: int) -> None: ... + def set_full(self, vflags: int) -> None: ... class HEICExifFinder: - file_handle: Incomplete - def __init__(self, file_handle) -> None: ... + file_handle: Reader + def __init__(self, file_handle: Reader) -> None: ... def get(self, nbytes: int) -> bytes: ... def get16(self) -> int: ... def get32(self) -> int: ... def get64(self) -> int: ... - def get_int4x2(self) -> tuple[Incomplete, Incomplete]: ... + def get_int4x2(self) -> tuple[int, int]: ... def get_int(self, size: int) -> int: ... def get_string(self) -> bytes: ... def next_box(self) -> Box: ... - def get_full(self, box: Box): ... - def skip(self, box: Box): ... + def get_full(self, box: Box) -> None: ... + def skip(self, box: Box) -> None: ... def expect_parse(self, name: str) -> Box: ... - def get_parser(self, box: Box) -> Callable[..., Incomplete]: ... + def get_parser(self, box: Box) -> Callable[[Box], None]: ... def parse_box(self, box: Box) -> Box: ... - def find_exif(self) -> tuple[Incomplete, Incomplete]: ... + def find_exif(self) -> tuple[int, bytes]: ... diff --git a/stubs/ExifRead/exifread/jpeg.pyi b/stubs/ExifRead/exifread/jpeg.pyi index f0ba05079631..9b179150410d 100644 --- a/stubs/ExifRead/exifread/jpeg.pyi +++ b/stubs/ExifRead/exifread/jpeg.pyi @@ -1,5 +1,7 @@ -from _typeshed import Incomplete +from logging import Logger -logger: Incomplete +from ._types import Reader -def find_jpeg_exif(fh, data, fake_exif) -> tuple[Incomplete, Incomplete, Incomplete]: ... +logger: Logger + +def find_jpeg_exif(fh: Reader, data: bytes, fake_exif: bool) -> tuple[int, bytes, bool]: ... diff --git a/stubs/ExifRead/exifread/tags/exif.pyi b/stubs/ExifRead/exifread/tags/exif.pyi index bf6514ac62d0..569609e93fb3 100644 --- a/stubs/ExifRead/exifread/tags/exif.pyi +++ b/stubs/ExifRead/exifread/tags/exif.pyi @@ -1,7 +1,7 @@ -from _typeshed import Incomplete +from exifread._types import TagDict -INTEROP_TAGS: Incomplete -INTEROP_INFO: Incomplete -GPS_TAGS: Incomplete -GPS_INFO: Incomplete -EXIF_TAGS: Incomplete +INTEROP_TAGS: TagDict +INTEROP_INFO: tuple[str, TagDict] +GPS_TAGS: TagDict +GPS_INFO: tuple[str, TagDict] +EXIF_TAGS: TagDict diff --git a/stubs/ExifRead/exifread/tags/makernote/apple.pyi b/stubs/ExifRead/exifread/tags/makernote/apple.pyi index 9e8d92850730..c72072637e49 100644 --- a/stubs/ExifRead/exifread/tags/makernote/apple.pyi +++ b/stubs/ExifRead/exifread/tags/makernote/apple.pyi @@ -1,3 +1,3 @@ -from _typeshed import Incomplete +from exifread._types import TagDict -TAGS: Incomplete +TAGS: TagDict diff --git a/stubs/ExifRead/exifread/tags/makernote/canon.pyi b/stubs/ExifRead/exifread/tags/makernote/canon.pyi index 112f87f2ab70..97d4f93c5309 100644 --- a/stubs/ExifRead/exifread/tags/makernote/canon.pyi +++ b/stubs/ExifRead/exifread/tags/makernote/canon.pyi @@ -1,19 +1,26 @@ -from _typeshed import Incomplete +from collections.abc import Callable +from typing import Any +from typing_extensions import TypeAlias -TAGS: Incomplete -CAMERA_SETTINGS: Incomplete -FOCAL_LENGTH: Incomplete -SHOT_INFO: Incomplete -AF_INFO_2: Incomplete -FILE_INFO: Incomplete +from exifread._types import TagDict -def add_one(value): ... -def subtract_one(value): ... -def convert_temp(value): ... +TAGS: TagDict + +CAMERA_SETTINGS: TagDict +FOCAL_LENGTH: TagDict +SHOT_INFO: TagDict +AF_INFO_2: TagDict +FILE_INFO: TagDict + +def add_one(value: int) -> int: ... +def subtract_one(value: int) -> int: ... +def convert_temp(value: int) -> str: ... + +_CameraInfo: TypeAlias = dict[int, tuple[str, str, Callable[[int], Any]]] CAMERA_INFO_TAG_NAME: str -CAMERA_INFO_5D: Incomplete -CAMERA_INFO_5DMKII: Incomplete -CAMERA_INFO_5DMKIII: Incomplete -CAMERA_INFO_600D: Incomplete -CAMERA_INFO_MODEL_MAP: Incomplete +CAMERA_INFO_5D: _CameraInfo +CAMERA_INFO_5DMKII: _CameraInfo +CAMERA_INFO_5DMKIII: _CameraInfo +CAMERA_INFO_600D: _CameraInfo +CAMERA_INFO_MODEL_MAP: dict[str, _CameraInfo] diff --git a/stubs/ExifRead/exifread/tags/makernote/casio.pyi b/stubs/ExifRead/exifread/tags/makernote/casio.pyi index 9e8d92850730..c72072637e49 100644 --- a/stubs/ExifRead/exifread/tags/makernote/casio.pyi +++ b/stubs/ExifRead/exifread/tags/makernote/casio.pyi @@ -1,3 +1,3 @@ -from _typeshed import Incomplete +from exifread._types import TagDict -TAGS: Incomplete +TAGS: TagDict diff --git a/stubs/ExifRead/exifread/tags/makernote/fujifilm.pyi b/stubs/ExifRead/exifread/tags/makernote/fujifilm.pyi index 9e8d92850730..c72072637e49 100644 --- a/stubs/ExifRead/exifread/tags/makernote/fujifilm.pyi +++ b/stubs/ExifRead/exifread/tags/makernote/fujifilm.pyi @@ -1,3 +1,3 @@ -from _typeshed import Incomplete +from exifread._types import TagDict -TAGS: Incomplete +TAGS: TagDict diff --git a/stubs/ExifRead/exifread/tags/makernote/nikon.pyi b/stubs/ExifRead/exifread/tags/makernote/nikon.pyi index b83fe90e67da..ffa7101f5df4 100644 --- a/stubs/ExifRead/exifread/tags/makernote/nikon.pyi +++ b/stubs/ExifRead/exifread/tags/makernote/nikon.pyi @@ -1,6 +1,6 @@ -from _typeshed import Incomplete +from exifread._types import TagDict -def ev_bias(seq) -> str: ... +def ev_bias(seq: list[int]) -> str: ... -TAGS_NEW: Incomplete -TAGS_OLD: Incomplete +TAGS_NEW: TagDict +TAGS_OLD: TagDict diff --git a/stubs/ExifRead/exifread/tags/makernote/olympus.pyi b/stubs/ExifRead/exifread/tags/makernote/olympus.pyi index 948f572aacef..0744c773824f 100644 --- a/stubs/ExifRead/exifread/tags/makernote/olympus.pyi +++ b/stubs/ExifRead/exifread/tags/makernote/olympus.pyi @@ -1,6 +1,6 @@ -from _typeshed import Incomplete +from exifread._types import TagDict -def special_mode(val): ... +def special_mode(val: bytes) -> str: ... -TAGS: Incomplete -TAG_0x2020: Incomplete +TAGS: TagDict +TAG_0x2020: TagDict diff --git a/stubs/ExifRead/exifread/utils.pyi b/stubs/ExifRead/exifread/utils.pyi index c6cd469ecb0d..878c3adfac1a 100644 --- a/stubs/ExifRead/exifread/utils.pyi +++ b/stubs/ExifRead/exifread/utils.pyi @@ -1,15 +1,22 @@ -from _typeshed import Incomplete +from _typeshed import Self +from collections.abc import Mapping from fractions import Fraction +from typing import Any, TypeVar, overload -def ord_(dta): ... -def make_string(seq: bytes | list[Incomplete]) -> str: ... -def make_string_uc(seq) -> str: ... -def get_gps_coords(tags: dict[Incomplete, Incomplete]) -> tuple[Incomplete, Incomplete]: ... +_T = TypeVar("_T") + +@overload +def ord_(dta: str) -> int: ... # type: ignore[misc] +@overload +def ord_(dta: _T) -> _T: ... +def make_string(seq: str | list[int]) -> str: ... +def make_string_uc(seq: str | list[int]) -> str: ... +def get_gps_coords(tags: Mapping[str, Any]) -> tuple[float, float]: ... class Ratio(Fraction): - def __new__(cls, numerator: int = ..., denominator: Incomplete | None = ...): ... + def __new__(cls: type[Self], numerator: int = ..., denominator: int | None = ...) -> Self: ... @property - def num(self): ... + def num(self) -> int: ... @property - def den(self): ... + def den(self) -> int: ... def decimal(self) -> float: ...