6
6
import urllib .parse
7
7
import zipfile
8
8
import tarfile
9
- from typing import List , Dict , TypedDict , Optional , Union
9
+ from typing import List , Dict , TypedDict , Optional , Union , Any
10
10
11
11
from bs4 import BeautifulSoup
12
12
from requests .exceptions import HTTPError , JSONDecodeError
30
30
31
31
32
32
class DownloadResult :
33
- def __init__ (self , url : str , success : bool , errors , external_urls : List [str ]):
33
+ def __init__ (self , url : str , success : bool , errors : Optional [ List [ str ]] , external_urls : List [str ]) -> None :
34
34
self .url = url
35
35
self .success = success
36
36
self .errors = errors or []
@@ -62,13 +62,13 @@ class GameMetadata(TypedDict, total=False):
62
62
63
63
64
64
class GameDownloader :
65
- def __init__ (self , settings : Settings , keys : Dict [int , str ]):
65
+ def __init__ (self , settings : Settings , keys : Dict [int , str ]) -> None :
66
66
self .settings = settings
67
67
self .download_keys = keys
68
68
self .client = ItchApiClient (settings .api_key , settings .user_agent )
69
69
70
70
@staticmethod
71
- def get_rating_json (site ) -> Optional [dict ]:
71
+ def get_rating_json (site : BeautifulSoup ) -> Optional [dict ]:
72
72
for ldjson_node in site .find_all ("script" , type = "application/ld+json" ):
73
73
try :
74
74
ldjson : dict = json .loads (ldjson_node .text .strip ())
@@ -80,7 +80,7 @@ def get_rating_json(site) -> Optional[dict]:
80
80
return None
81
81
82
82
@staticmethod
83
- def get_meta (site , ** kwargs ) -> Optional [str ]:
83
+ def get_meta (site : BeautifulSoup , ** kwargs : Any ) -> Optional [str ]: # noqa: ANN401
84
84
"""Grabs <meta property="xyz" content="value"/> values."""
85
85
node = site .find ("meta" , attrs = kwargs )
86
86
if not node :
@@ -160,8 +160,8 @@ def extract_metadata(self, game_id: int, url: str, site: BeautifulSoup) -> GameM
160
160
infobox = parse_infobox (infobox_div )
161
161
for dt in ("created_at" , "updated_at" , "released_at" , "published_at" ):
162
162
if dt in infobox :
163
- metadata [dt ] = infobox [dt ].isoformat () # noqa (non-literal TypedDict keys)
164
- del infobox [dt ] # noqa (non-literal TypedDict keys)
163
+ metadata [dt ] = infobox [dt ].isoformat () # noqa: PyTypedDict (non-literal TypedDict keys)
164
+ del infobox [dt ] # noqa: PyTypedDict (non-literal TypedDict keys)
165
165
166
166
if "author" in infobox :
167
167
metadata ["author" ] = infobox ["author" ]["author" ]
@@ -179,7 +179,7 @@ def extract_metadata(self, game_id: int, url: str, site: BeautifulSoup) -> GameM
179
179
if agg_rating :
180
180
try :
181
181
metadata ["rating" ] = {"average" : float (agg_rating ["ratingValue" ]), "votes" : agg_rating ["ratingCount" ]}
182
- except : # noqa
182
+ except : # noqa: E722 (do not use bare `except`)
183
183
logging .exception ("Could not extract the rating metadata..." )
184
184
pass # Nope, just, don't
185
185
@@ -221,7 +221,7 @@ def download_file_by_upload_id(self, upload_id: int, download_path: Optional[str
221
221
return self .download_file (f"/uploads/{ upload_id } /download" , download_path , credentials )
222
222
223
223
@staticmethod
224
- def get_decompressed_content_size (target_path ) -> None | int :
224
+ def get_decompressed_content_size (target_path : str | os . PathLike [ str ] ) -> None | int :
225
225
"""For some files, Itch API returns the decompressed file size, but serves
226
226
compressed downloads. Try to figure out the decompressed size. It may be
227
227
a single file in the root, or a container + files in it."""
@@ -248,7 +248,7 @@ def get_decompressed_content_size(target_path) -> None | int:
248
248
249
249
return None
250
250
251
- def download (self , url : str , skip_downloaded : bool = True ):
251
+ def download (self , url : str , skip_downloaded : bool = True ) -> DownloadResult :
252
252
match = re .match (ITCH_GAME_URL_REGEX , url )
253
253
if not match :
254
254
return DownloadResult (url , False , [f"Game URL is invalid: { url } - please file a new issue." ], [])
@@ -310,15 +310,15 @@ def download(self, url: str, skip_downloaded: bool = True):
310
310
logging .info (
311
311
"File '%s' does not match the glob filter '%s', skipping" ,
312
312
file_name ,
313
- self .settings .filter_files_glob
313
+ self .settings .filter_files_glob ,
314
314
)
315
315
continue
316
316
317
317
if self .settings .filter_files_regex and not re .fullmatch (self .settings .filter_files_regex , file_name ):
318
318
logging .info (
319
319
"File '%s' does not match the regex filter '%s', skipping" ,
320
320
file_name ,
321
- self .settings .filter_files_regex
321
+ self .settings .filter_files_regex ,
322
322
)
323
323
continue
324
324
@@ -338,7 +338,7 @@ def download(self, url: str, skip_downloaded: bool = True):
338
338
continue
339
339
340
340
if upload_is_external :
341
- logging .debug ("Found external download URL for %s: %s" , target_url )
341
+ logging .debug ("Found external download URL for %s: %s" , title , target_url )
342
342
external_urls .append (target_url )
343
343
continue
344
344
@@ -356,7 +356,10 @@ def download(self, url: str, skip_downloaded: bool = True):
356
356
and downloaded_size != expected_size
357
357
and content_size != expected_size
358
358
):
359
- errors .append (f"Downloaded file size is { downloaded_size } (content { content_size } ), expected { expected_size } for upload { upload } " )
359
+ errors .append (
360
+ f"Downloaded file size is { downloaded_size } (content { content_size } ), "
361
+ f"expected { expected_size } for upload { upload } "
362
+ )
360
363
361
364
logging .debug ("Done downloading files for %s" , title )
362
365
except Exception as e :
@@ -366,7 +369,7 @@ def download(self, url: str, skip_downloaded: bool = True):
366
369
metadata ["external_downloads" ] = external_urls
367
370
368
371
if len (external_urls ) > 0 :
369
- logging .warning (f "Game { title } has external download URLs: { external_urls } " )
372
+ logging .warning ("Game %s has external download URLs: %s" , title , external_urls )
370
373
371
374
# TODO: Mirror JS/CSS assets
372
375
if self .settings .mirror_web :
@@ -395,7 +398,7 @@ def download(self, url: str, skip_downloaded: bool = True):
395
398
json .dump (metadata , f , indent = 4 )
396
399
397
400
if len (errors ) > 0 :
398
- logging .error (f "Game { title } has download errors: { errors } " )
401
+ logging .error ("Game %s has download errors: %s" , title , errors )
399
402
400
403
logging .info ("Finished job %s (%s)" , url , title )
401
404
return DownloadResult (url , len (errors ) == 0 , errors , external_urls )
@@ -405,7 +408,7 @@ def drive_downloads(
405
408
jobs : List [str ],
406
409
settings : Settings ,
407
410
keys : Dict [int , str ],
408
- ):
411
+ ) -> None :
409
412
downloader = GameDownloader (settings , keys )
410
413
tqdm_args = {
411
414
"desc" : "Games" ,
0 commit comments