fix: use strict mypy mode

This commit is contained in:
Hsiaoming Yang
2023-07-29 08:45:27 +09:00
parent e657c93adc
commit d5245d4101
4 changed files with 45 additions and 47 deletions

View File

@@ -64,6 +64,7 @@ exclude_lines = [
]
[tool.mypy]
strict = true
python_version = "3.8"
files = ["src/captcha"]
show_error_codes = true

View File

@@ -188,12 +188,12 @@ class AudioCaptcha:
"""
return random.sample(self.choices, length)
def load(self):
def load(self) -> None:
"""Load voice data into memory."""
for name in self.choices:
self._load_data(name)
def _load_data(self, name: str):
def _load_data(self, name: str) -> None:
dirname = os.path.join(self._voicedir, name)
data: t.List[bytearray] = []
for f in os.listdir(dirname):
@@ -227,7 +227,7 @@ class AudioCaptcha:
voice = change_sound(voice, level)
return voice
def create_background_noise(self, length: int, chars: str):
def create_background_noise(self, length: int, chars: str) -> bytearray:
noise = create_noise(length, 4)
pos = 0
while pos < length:
@@ -268,7 +268,7 @@ class AudioCaptcha:
body = self.create_wave_body(chars)
return patch_wave_header(body)
def write(self, chars: str, output: str):
def write(self, chars: str, output: str) -> None:
"""Generate and write audio CAPTCHA data to the output.
:param chars: text to be generated.
@@ -276,4 +276,4 @@ class AudioCaptcha:
"""
data = self.generate(chars)
with open(output, 'wb') as f:
return f.write(data)
f.write(data)

View File

@@ -10,7 +10,7 @@ import os
import random
import typing as t
from PIL.Image import new as createImage, Image, QUAD, BILINEAR
from PIL.ImageDraw import Draw
from PIL.ImageDraw import Draw, ImageDraw
from PIL.ImageFilter import SMOOTH
from PIL.ImageFont import FreeTypeFont, truetype
from io import BytesIO
@@ -24,11 +24,6 @@ DATA_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'data')
DEFAULT_FONTS = [os.path.join(DATA_DIR, 'DroidSansMono.ttf')]
table: t.List[int] = []
for i in range(256):
table.append(int(i * 1.97))
class ImageCaptcha:
"""Create an image CAPTCHA.
@@ -49,6 +44,8 @@ class ImageCaptcha:
:param fonts: Fonts to be used to generate CAPTCHA images.
:param font_sizes: Random choose a font size from this parameters.
"""
lookup_table: t.List[int] = [int(i * 1.97) for i in range(256)]
def __init__(
self,
width: int = 160,
@@ -73,7 +70,7 @@ class ImageCaptcha:
return self._truefonts
@staticmethod
def create_noise_curve(image: Image, color: ColorTuple):
def create_noise_curve(image: Image, color: ColorTuple) -> Image:
w, h = image.size
x1 = random.randint(0, int(w / 5))
x2 = random.randint(w - int(w / 5), w)
@@ -100,6 +97,38 @@ class ImageCaptcha:
number -= 1
return image
def _draw_character(self, c: str, draw: ImageDraw, color: ColorTuple) -> Image:
font = random.choice(self.truefonts)
_, _, w, h = draw.textbbox((1, 1), c, font=font)
dx1 = random.randint(0, 4)
dy1 = random.randint(0, 6)
im = createImage('RGBA', (w + dx1, h + dy1))
Draw(im).text((dx1, dy1), c, font=font, fill=color)
# rotate
im = im.crop(im.getbbox())
im = im.rotate(random.uniform(-30, 30), BILINEAR, expand=True)
# warp
dx2 = w * random.uniform(0.1, 0.3)
dy2 = h * random.uniform(0.2, 0.3)
x1 = int(random.uniform(-dx2, dx2))
y1 = int(random.uniform(-dy2, dy2))
x2 = int(random.uniform(-dx2, dx2))
y2 = int(random.uniform(-dy2, dy2))
w2 = w + abs(x1) + abs(x2)
h2 = h + abs(y1) + abs(y2)
data = (
x1, y1,
-x1, h2 - y2,
w2 + x2, h2 + y2,
w2 - x2, -y1,
)
im = im.resize((w2, h2))
im = im.transform((w, h), QUAD, data)
return im
def create_captcha_image(
self,
chars: str,
@@ -116,43 +145,11 @@ class ImageCaptcha:
image = createImage('RGB', (self._width, self._height), background)
draw = Draw(image)
def _draw_character(c: str):
font = random.choice(self.truefonts)
_, _, w, h = draw.textbbox((1, 1), c, font=font)
dx1 = random.randint(0, 4)
dy1 = random.randint(0, 6)
im = createImage('RGBA', (w + dx1, h + dy1))
Draw(im).text((dx1, dy1), c, font=font, fill=color)
# rotate
im = im.crop(im.getbbox())
im = im.rotate(random.uniform(-30, 30), BILINEAR, expand=True)
# warp
dx2 = w * random.uniform(0.1, 0.3)
dy2 = h * random.uniform(0.2, 0.3)
x1 = int(random.uniform(-dx2, dx2))
y1 = int(random.uniform(-dy2, dy2))
x2 = int(random.uniform(-dx2, dx2))
y2 = int(random.uniform(-dy2, dy2))
w2 = w + abs(x1) + abs(x2)
h2 = h + abs(y1) + abs(y2)
data = (
x1, y1,
-x1, h2 - y2,
w2 + x2, h2 + y2,
w2 - x2, -y1,
)
im = im.resize((w2, h2))
im = im.transform((w, h), QUAD, data)
return im
images: t.List[Image] = []
for c in chars:
if random.random() > 0.5:
images.append(_draw_character(" "))
images.append(_draw_character(c))
images.append(self._draw_character(" ", draw, color))
images.append(self._draw_character(c, draw, color))
text_width = sum([im.size[0] for im in images])
@@ -165,7 +162,7 @@ class ImageCaptcha:
for im in images:
w, h = im.size
mask = im.convert('L').point(table)
mask = im.convert('L').point(self.lookup_table)
image.paste(im, (offset, int((self._height - h) / 2)), mask)
offset = offset + w + random.randint(-rand, 0)

0
src/captcha/py.typed Normal file
View File