chg: [typing] Make Mypy Happy Again.

This commit is contained in:
Cédric Bonhomme 2025-06-22 12:03:30 +02:00
parent 21004219fa
commit 18fd8a8a49
No known key found for this signature in database
GPG key ID: A1CB94DE57B7A70D
5 changed files with 43 additions and 21 deletions

View file

@ -21,7 +21,7 @@ repos:
additional_dependencies: additional_dependencies:
- flake8-bugbear - flake8-bugbear
- flake8-implicit-str-concat - flake8-implicit-str-concat
args: ["--max-line-length=125"] args: ["--max-line-length=125", "--ignore=E203"]
- repo: https://github.com/pre-commit/pre-commit-hooks - repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0 rev: v4.1.0
hooks: hooks:

View file

@ -73,7 +73,7 @@ optional = true
[tool.mypy] [tool.mypy]
python_version = "3.12" python_version = "3.13"
check_untyped_defs = true check_untyped_defs = true
ignore_errors = false ignore_errors = false
ignore_missing_imports = true ignore_missing_imports = true
@ -87,7 +87,12 @@ warn_unreachable = true
show_error_context = true show_error_context = true
pretty = true pretty = true
exclude = "build|dist|docs|stegano.egg-info" exclude = "build|dist|docs"
[tool.isort] [tool.isort]
profile = "black" profile = "black"
[tool.flake8]
ignore = ["E203"]

View file

@ -23,7 +23,7 @@ __date__ = "$Date: 2010/10/01 $"
__revision__ = "$Date: 2017/02/06 $" __revision__ = "$Date: 2017/02/06 $"
__license__ = "GPLv3" __license__ = "GPLv3"
from typing import IO, Union from typing import IO, Union, cast
from stegano import tools from stegano import tools
@ -40,13 +40,17 @@ def hide(input_image: Union[str, IO[bytes]], message: str):
assert message_length != 0, "message message_length is zero" assert message_length != 0, "message message_length is zero"
assert message_length < 255, "message is too long" assert message_length < 255, "message is too long"
img = tools.open_image(input_image) img = tools.open_image(input_image)
# Ensure image mode is RGB
if img.mode != "RGB":
img = img.convert("RGB")
# Use a copy of image to hide the text in # Use a copy of image to hide the text in
encoded = img.copy() encoded = img.copy()
width, height = img.size width, height = img.size
index = 0 index = 0
for row in range(height): for row in range(height):
for col in range(width): for col in range(width):
(r, g, b) = img.getpixel((col, row)) pixel = cast(tuple[int, int, int], img.getpixel((col, row)))
r, g, b = pixel
# first value is message_length of message # first value is message_length of message
if row == 0 and col == 0 and index < message_length: if row == 0 and col == 0 and index < message_length:
asc = message_length asc = message_length
@ -70,12 +74,16 @@ def reveal(input_image: Union[str, IO[bytes]]):
The red value of the first pixel is used for message_length of string. The red value of the first pixel is used for message_length of string.
""" """
img = tools.open_image(input_image) img = tools.open_image(input_image)
# Ensure image mode is RGB
if img.mode != "RGB":
img = img.convert("RGB")
width, height = img.size width, height = img.size
message = "" message = ""
index = 0 index = 0
for row in range(height): for row in range(height):
for col in range(width): for col in range(width):
r, g, b = img.getpixel((col, row)) pixel = cast(tuple[int, int, int], img.getpixel((col, row)))
r, g, b = pixel
# First pixel r value is length of message # First pixel r value is length of message
if row == 0 and col == 0: if row == 0 and col == 0:
message_length = r message_length = r

View file

@ -23,6 +23,8 @@ __date__ = "$Date: 2010/10/01 $"
__revision__ = "$Date: 2019/06/06 $" __revision__ = "$Date: 2019/06/06 $"
__license__ = "GPLv3" __license__ = "GPLv3"
from typing import cast
from PIL import Image from PIL import Image
@ -34,7 +36,7 @@ def steganalyse(img: Image.Image) -> Image.Image:
width, height = img.size width, height = img.size
for row in range(height): for row in range(height):
for col in range(width): for col in range(width):
if pixel := img.getpixel((col, row)): if pixel := cast(tuple[int, int, int], img.getpixel((col, row))):
r, g, b = pixel[0:3] r, g, b = pixel[0:3]
else: else:
raise Exception("Error during steganlysis.") raise Exception("Error during steganlysis.")

View file

@ -26,7 +26,7 @@ __license__ = "GPLv3"
import base64 import base64
import itertools import itertools
from functools import reduce from functools import reduce
from typing import IO, List, Union from typing import IO, List, Union, cast
from PIL import Image from PIL import Image
@ -101,11 +101,12 @@ def base642binary(b64_fname: str) -> bytes:
return base64.b64decode(b64_fname) return base64.b64decode(b64_fname)
def open_image(fname_or_instance: Union[str, IO[bytes]]): def open_image(fname_or_instance: Union[str, IO[bytes], Image.Image]) -> Image.Image:
"""Opens a Image and returns it. """Opens an image and returns it.
:param fname_or_instance: Can either be the location of the image as a :param fname_or_instance: Can be a path to the image (str),
string or the Image.Image instance itself. a file-like object (IO[bytes]),
or a PIL Image instance.
""" """
if isinstance(fname_or_instance, Image.Image): if isinstance(fname_or_instance, Image.Image):
return fname_or_instance return fname_or_instance
@ -157,8 +158,15 @@ class Hider:
return True if self._index + 3 <= self._len_message_bits else False return True if self._index + 3 <= self._len_message_bits else False
def encode_pixel(self, coordinate: tuple): def encode_pixel(self, coordinate: tuple):
# Get the colour component. # Determine expected pixel format based on mode
r, g, b, *a = self.encoded_image.getpixel(coordinate) if self.encoded_image.mode == "RGBA":
r, g, b, *a = cast(
tuple[int, int, int, int], self.encoded_image.getpixel(coordinate)
)
else:
r, g, b, *a = cast(
tuple[int, int, int], self.encoded_image.getpixel(coordinate)
)
# Change the Least Significant Bit of each colour component. # Change the Least Significant Bit of each colour component.
r = setlsb(r, self._message_bits[self._index]) r = setlsb(r, self._message_bits[self._index])
@ -190,8 +198,11 @@ class Revealer:
self.close_file = close_file self.close_file = close_file
def decode_pixel(self, coordinate: tuple): def decode_pixel(self, coordinate: tuple):
# pixel = [r, g, b] or [r,g,b,a] # Tell mypy that this will be a 3- or 4-tuple of ints
pixel = self.encoded_image.getpixel(coordinate) pixel = cast(
tuple[int, int, int] | tuple[int, int, int, int],
self.encoded_image.getpixel(coordinate),
)
if self.encoded_image.mode == "RGBA": if self.encoded_image.mode == "RGBA":
pixel = pixel[:3] # ignore the alpha pixel = pixel[:3] # ignore the alpha
@ -211,13 +222,9 @@ class Revealer:
raise IndexError("Impossible to detect message.") raise IndexError("Impossible to detect message.")
if len(self._bitab) - len(str(self._limit)) - 1 == self._limit: if len(self._bitab) - len(str(self._limit)) - 1 == self._limit:
self.secret_message = "".join(self._bitab)[ self.secret_message = "".join(self._bitab)[len(str(self._limit)) + 1 :]
len(str(self._limit)) + 1 : # noqa: E203
]
if self.close_file: if self.close_file:
self.encoded_image.close() self.encoded_image.close()
return True return True
else: else:
return False return False