Skip to content

Commit 29dd2e7

Browse files
committed
Activate pyright strict mode and fix many typing issues
1 parent 86fb7dc commit 29dd2e7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+1214
-818
lines changed

contrib/encode_video.py

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ def encode_video(src_path: Path, dst_path: Path, preset: str):
2222
ffmpeg_args=preset_cls().to_ffmpeg_args(),
2323
with_process=True,
2424
) # pyright: ignore[reportGeneralTypeIssues] (returned type is variable, depending on `with_process` value)
25+
if not process: # pragma: no branch
26+
raise ValueError("process should have been returned")
2527
if not success:
2628
logger.error(f"conversion failed:\n{process.stdout}")
2729

pyproject.toml

+1-4
Original file line numberDiff line numberDiff line change
@@ -264,12 +264,9 @@ include = ["contrib", "src", "tests", "tasks.py"]
264264
exclude = [".env/**", ".venv/**"]
265265
extraPaths = ["src"]
266266
pythonVersion = "3.12"
267-
typeCheckingMode="basic"
267+
typeCheckingMode="strict"
268268
disableBytesTypePromotions = true
269269

270-
[tool.pyright.overrides]
271-
strict = true # Enable strict mode for specific files
272-
273270
[[tool.pyright.overrides.files]]
274271
files = [
275272
"src/zimscraperlib/rewriting**/*.py",

rules/generate_rules.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,11 @@
156156
{% endfor %}
157157
]
158158
)
159-
def {{ rule['name'] }}_case(request):
159+
def {{ rule['name'] }}_case(request: pytest.FixtureRequest):
160160
yield request.param
161161
162162
163-
def test_fuzzyrules_{{ rule['name'] }}({{ rule['name'] }}_case):
163+
def test_fuzzyrules_{{ rule['name'] }}({{ rule['name'] }}_case: ContentForTests):
164164
assert (
165165
ArticleUrlRewriter.apply_additional_rules({{ rule['name'] }}_case.input_str)
166166
== {{ rule['name'] }}_case.expected_str

src/zimscraperlib/__init__.py

-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
#!/usr/bin/env python
2-
# vim: ai ts=4 sts=4 et sw=4 nu
3-
41
import logging as stdlogging
52
import os
63

src/zimscraperlib/constants.py

-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
#!/usr/bin/env python3
2-
# vim: ai ts=4 sts=4 et sw=4 nu
3-
41
import pathlib
52

63
from zimscraperlib.__about__ import __version__

src/zimscraperlib/download.py

+18-22
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1-
#!/usr/bin/env python3
2-
# vim: ai ts=4 sts=4 et sw=4 nu
3-
41
from __future__ import annotations
52

63
import pathlib
74
import subprocess
85
from concurrent.futures import Future, ThreadPoolExecutor
9-
from typing import IO, ClassVar
6+
from typing import IO, Any, ClassVar
107

118
import requests
129
import requests.adapters
1310
import requests.structures
1411
import urllib3.util
15-
import yt_dlp as youtube_dl
12+
import yt_dlp as youtube_dl # pyright: ignore[reportMissingTypeStubs]
1613

1714
from zimscraperlib import logger
1815

@@ -29,24 +26,24 @@ def __init__(self, threads: int | None = 1) -> None:
2926
def __enter__(self):
3027
return self
3128

32-
def __exit__(self, *args):
29+
def __exit__(self, *_: Any):
3330
self.shutdown()
3431

3532
def shutdown(self) -> None:
3633
"""shuts down the executor, awaiting completion"""
3734
self.executor.shutdown(wait=True)
3835

39-
def _run_youtube_dl(self, url: str, options: dict) -> None:
36+
def _run_youtube_dl(self, url: str, options: dict[str, Any]) -> None:
4037
with youtube_dl.YoutubeDL(options) as ydl:
41-
ydl.download([url])
38+
ydl.download([url]) # pyright: ignore[reportUnknownMemberType]
4239

4340
def download(
4441
self,
4542
url: str,
46-
options: dict | None,
43+
options: dict[str, Any] | None,
4744
*,
4845
wait: bool | None = True,
49-
) -> bool | Future:
46+
) -> bool | Future[Any]:
5047
"""Downloads video using initialized executor.
5148
5249
url: URL or Video ID
@@ -65,7 +62,7 @@ def download(
6562
raise future.exception() # pyright: ignore
6663

6764

68-
class YoutubeConfig(dict):
65+
class YoutubeConfig(dict[str, str | bool | int | None]):
6966
options: ClassVar[dict[str, str | bool | int | None]] = {}
7067
defaults: ClassVar[dict[str, str | bool | int | None]] = {
7168
"writethumbnail": True,
@@ -81,7 +78,7 @@ class YoutubeConfig(dict):
8178
"outtmpl": "video.%(ext)s",
8279
}
8380

84-
def __init__(self, **kwargs):
81+
def __init__(self, **kwargs: str | bool | int | None):
8582
super().__init__(self, **type(self).defaults)
8683
self.update(self.options)
8784
self.update(kwargs)
@@ -91,7 +88,7 @@ def get_options(
9188
cls,
9289
target_dir: pathlib.Path | None = None,
9390
filepath: pathlib.Path | None = None,
94-
**options,
91+
**options: str | bool | int | None,
9592
):
9693
if "outtmpl" not in options:
9794
outtmpl = cls.options.get("outtmpl", cls.defaults["outtmpl"])
@@ -142,9 +139,10 @@ def save_large_file(url: str, fpath: pathlib.Path) -> None:
142139
)
143140

144141

145-
def _get_retry_adapter(
142+
def get_retry_adapter(
146143
max_retries: int | None = 5,
147144
) -> requests.adapters.BaseAdapter:
145+
"""A requests adapter to automatically retry on known HTTP status that can be"""
148146
retries = urllib3.util.retry.Retry(
149147
total=max_retries, # total number of retries
150148
connect=max_retries, # connection errors
@@ -168,7 +166,7 @@ def _get_retry_adapter(
168166
def get_session(max_retries: int | None = 5) -> requests.Session:
169167
"""Session to hold cookies and connection pool together"""
170168
session = requests.Session()
171-
session.mount("http", _get_retry_adapter(max_retries)) # tied to http and https
169+
session.mount("http", get_retry_adapter(max_retries)) # tied to http and https
172170
return session
173171

174172

@@ -198,7 +196,11 @@ def stream_file(
198196
Returns the total number of bytes downloaded and the response headers"""
199197

200198
# if no output option is supplied
201-
if fpath is None and byte_stream is None:
199+
if fpath is not None:
200+
fp = open(fpath, "wb")
201+
elif byte_stream is not None:
202+
fp = byte_stream
203+
else:
202204
raise ValueError("Either file path or a bytesIO object is needed")
203205

204206
if not session:
@@ -212,12 +214,6 @@ def stream_file(
212214
resp.raise_for_status()
213215

214216
total_downloaded = 0
215-
if fpath is not None:
216-
fp = open(fpath, "wb")
217-
elif (
218-
byte_stream is not None
219-
): # pragma: no branch (we use a precise condition to help type checker)
220-
fp = byte_stream
221217

222218
for data in resp.iter_content(block_size):
223219
total_downloaded += len(data)

src/zimscraperlib/filesystem.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
#!/usr/bin/env python
2-
# vim: ai ts=4 sts=4 et sw=4 nu
3-
41
""" Files manipulation tools
52
63
Shortcuts to retrieve mime type using magic"""
@@ -46,7 +43,7 @@ def get_content_mimetype(content: bytes | str) -> str:
4643

4744
def delete_callback(
4845
fpath: str | pathlib.Path,
49-
callback: Callable | None = None,
46+
callback: Callable[..., Any] | None = None,
5047
*callback_args: Any,
5148
):
5249
"""helper deleting passed filepath, optionnaly calling an additional callback"""
@@ -55,4 +52,4 @@ def delete_callback(
5552

5653
# call the callback if requested
5754
if callback and callable(callback):
58-
callback.__call__(*callback_args)
55+
callback(*callback_args)

src/zimscraperlib/fix_ogvjs_dist.py

-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
#!/usr/bin/env python3
2-
# vim: ai ts=4 sts=4 et sw=4 nu
3-
4-
51
""" quick script to fix videojs-ogvjs so that it triggers on webm mimetype """
62

73
from __future__ import annotations

src/zimscraperlib/html.py

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
#!/usr/bin/env python
2-
# vim: ai ts=4 sts=4 et sw=4 nu
3-
41
""" Tools to work with HTML contents """
2+
53
from __future__ import annotations
64

75
import pathlib
@@ -43,9 +41,7 @@ def find_language_in(content: str | BinaryIO | TextIO, mime_type: str) -> str:
4341
for key in keylist:
4442
node = soup.find(nodename)
4543
if node:
46-
if not isinstance(node, element.Tag) or (
47-
isinstance(node, element.Tag) and not node.has_attr(key)
48-
):
44+
if not isinstance(node, element.Tag) or not node.has_attr(key):
4945
continue
5046
if (
5147
nodename == "meta"

src/zimscraperlib/i18n.py

-29
Original file line numberDiff line numberDiff line change
@@ -47,35 +47,6 @@ def __init__(
4747
self.querytype = querytype
4848
self.query = query
4949

50-
def __eq__(self, value: object) -> bool:
51-
if not isinstance(value, LangAndDetails):
52-
return False
53-
54-
return (
55-
self.iso_639_1 == value.iso_639_1
56-
and self.iso_639_2b == value.iso_639_2b
57-
and self.iso_639_2t == value.iso_639_2t
58-
and self.iso_639_3 == value.iso_639_3
59-
and self.iso_639_5 == value.iso_639_5
60-
and self.english == value.english
61-
and self.native == value.native
62-
)
63-
64-
def __hash__(self) -> int:
65-
return hash(
66-
(
67-
self.iso_639_1,
68-
self.iso_639_2b,
69-
self.iso_639_2t,
70-
self.iso_639_3,
71-
self.iso_639_5,
72-
self.english,
73-
self.native,
74-
self.query,
75-
self.querytype,
76-
)
77-
)
78-
7950

8051
def get_iso_lang_data(lang: str) -> tuple[Lang, Lang | None]:
8152
"""ISO-639-x languages details for lang. Raises NotFoundError

src/zimscraperlib/image/__init__.py

-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
#!/usr/bin/env python
2-
# -*- coding: utf-8 -*-
3-
# vim: ai ts=4 sts=4 et sw=4 nu
4-
51
# flake8: noqa
62
from .conversion import convert_image
73
from .optimization import optimize_image

src/zimscraperlib/image/conversion.py

+12-9
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
#!/usr/bin/env python3
2-
# vim: ai ts=4 sts=4 et sw=4 nu
3-
41
from __future__ import annotations
52

63
import io
74
import pathlib
8-
from typing import IO
5+
from typing import IO, Any
96

10-
import cairosvg.svg
7+
import cairosvg.svg # pyright: ignore[reportMissingTypeStubs]
118
from PIL.Image import open as pilopen
129

1310
from zimscraperlib.constants import ALPHA_NOT_SUPPORTED
@@ -31,7 +28,9 @@ def convert_image(
3128
to RGB. ex: RGB, ARGB, CMYK (and other PIL colorspaces)"""
3229

3330
colorspace = params.get("colorspace") # requested colorspace
34-
fmt = params.pop("fmt").upper() if "fmt" in params else None # requested format
31+
fmt = ( # requested format
32+
(params.pop("fmt") or "").upper() if "fmt" in params else None
33+
)
3534
if not fmt:
3635
fmt = format_for(dst)
3736
if not fmt:
@@ -53,7 +52,7 @@ def convert_svg2png(
5352
Output width and height might be specified if resize is needed.
5453
PNG background is transparent.
5554
"""
56-
kwargs = {}
55+
kwargs: dict[str, Any] = {}
5756
if isinstance(src, pathlib.Path):
5857
src = str(src)
5958
if isinstance(src, str):
@@ -65,9 +64,13 @@ def convert_svg2png(
6564
if height:
6665
kwargs["output_height"] = height
6766
if isinstance(dst, pathlib.Path):
68-
cairosvg.svg2png(write_to=str(dst), **kwargs)
67+
cairosvg.svg2png( # pyright: ignore[reportUnknownMemberType]
68+
write_to=str(dst), **kwargs
69+
)
6970
else:
70-
result = cairosvg.svg2png(**kwargs)
71+
result = cairosvg.svg2png( # pyright: ignore[reportUnknownMemberType, reportUnknownVariableType]
72+
**kwargs
73+
)
7174
if not isinstance(result, bytes):
7275
raise Exception(
7376
"Unexpected type returned by cairosvg.svg2png"

0 commit comments

Comments
 (0)