fix: address codeql notes and warnings (#740)

This commit is contained in:
Jens
2025-12-20 18:17:51 +01:00
committed by GitHub
parent f0ebb26e5d
commit ba9b14b71b
9 changed files with 128 additions and 103 deletions

View File

@@ -746,6 +746,7 @@ class KleinanzeigenBot(WebScrapingMixin):
await ainput(_("Press a key to continue..."))
except TimeoutError:
# No captcha detected within timeout.
pass
async def login(self) -> None:
@@ -796,6 +797,7 @@ class KleinanzeigenBot(WebScrapingMixin):
LOG.warning("############################################")
await ainput("Press ENTER when done...")
except TimeoutError:
# No SMS verification prompt detected.
pass
try:
@@ -807,6 +809,7 @@ class KleinanzeigenBot(WebScrapingMixin):
"//div[@id='ConsentManagementPage']//*//button//*[contains(., 'Alle ablehnen und fortfahren')]",
timeout = gdpr_timeout)
except TimeoutError:
# GDPR banner not shown within timeout.
pass
async def is_logged_in(self) -> bool:
@@ -994,6 +997,7 @@ class KleinanzeigenBot(WebScrapingMixin):
try:
await self.web_select(By.CSS_SELECTOR, "select#price-type-react, select#micro-frontend-price-type, select#priceType", price_type)
except TimeoutError:
# Price type selector not present on this page variant.
pass
if ad_cfg.price:
if mode == AdUpdateStrategy.MODIFY:
@@ -1112,6 +1116,7 @@ class KleinanzeigenBot(WebScrapingMixin):
if not ad_cfg.images and await self.web_check(By.XPATH, image_hint_xpath, Is.DISPLAYED):
await self.web_click(By.XPATH, image_hint_xpath)
except TimeoutError:
# Image hint not shown; continue publish flow.
pass # nosec
#############################
@@ -1127,6 +1132,7 @@ class KleinanzeigenBot(WebScrapingMixin):
await self.web_scroll_page_down()
await ainput(_("Press a key to continue..."))
except TimeoutError:
# Payment form not present.
pass
confirmation_timeout = self._timeout("publishing_confirmation")
@@ -1234,6 +1240,7 @@ class KleinanzeigenBot(WebScrapingMixin):
if await self.web_text(By.ID, "postad-category-path"):
is_category_auto_selected = True
except TimeoutError:
# Category auto-selection indicator not available within timeout.
pass
if category:
@@ -1267,6 +1274,7 @@ class KleinanzeigenBot(WebScrapingMixin):
if not await self.web_check(By.XPATH, select_container_xpath, Is.DISPLAYED):
await (await self.web_find(By.XPATH, select_container_xpath)).apply("elem => elem.singleNodeValue.style.display = 'block'")
except TimeoutError:
# Skip visibility adjustment when container cannot be located in time.
pass # nosec
try:
@@ -1341,6 +1349,7 @@ class KleinanzeigenBot(WebScrapingMixin):
await self.web_click(By.XPATH,
'//dialog//button[contains(., "Andere Versandmethoden")]')
except TimeoutError:
# Dialog option not present; already on the individual shipping page.
pass
try:
@@ -1350,6 +1359,7 @@ class KleinanzeigenBot(WebScrapingMixin):
'//input[contains(@placeholder, "Versandkosten (optional)")]',
timeout = short_timeout)
except TimeoutError:
# Input not visible yet; click the individual shipping option.
await self.web_click(By.XPATH, '//*[contains(@id, "INDIVIDUAL") and contains(@data-testid, "Individueller Versand")]')
if ad_cfg.shipping_costs is not None:

View File

@@ -59,7 +59,10 @@ class AdExtractor(WebScrapingMixin):
# Save the ad configuration file (offload to executor to avoid blocking the event loop)
ad_file_path = str(Path(final_dir) / f"ad_{ad_id}.yaml")
header_string = "# yaml-language-server: $schema=https://raw.githubusercontent.com/Second-Hand-Friends/kleinanzeigen-bot/refs/heads/main/schemas/ad.schema.json"
header_string = (
"# yaml-language-server: $schema="
"https://raw.githubusercontent.com/Second-Hand-Friends/kleinanzeigen-bot/refs/heads/main/schemas/ad.schema.json"
)
await asyncio.get_running_loop().run_in_executor(
None,
lambda: dicts.save_dict(ad_file_path, ad_cfg.model_dump(), header = header_string)
@@ -141,9 +144,6 @@ class AdExtractor(WebScrapingMixin):
:return: the ad ID, a (ten-digit) integer number
"""
num_part = url.rsplit("/", maxsplit = 1)[-1] # suffix
id_part = num_part.split("-", maxsplit = 1)[0]
try:
path = url.split("?", maxsplit = 1)[0] # Remove query string if present
last_segment = path.rstrip("/").rsplit("/", maxsplit = 1)[-1] # Get last path component
@@ -165,7 +165,7 @@ class AdExtractor(WebScrapingMixin):
# Try to find the main ad list container first
try:
ad_list_container = await self.web_find(By.ID, "my-manageitems-adlist")
_ = await self.web_find(By.ID, "my-manageitems-adlist")
except TimeoutError:
LOG.warning("Ad list container #my-manageitems-adlist not found. Maybe no ads present?")
return []
@@ -290,6 +290,7 @@ class AdExtractor(WebScrapingMixin):
await self.web_click(By.CLASS_NAME, "mfp-close")
await self.web_sleep()
except TimeoutError:
# Popup did not appear within timeout.
pass
return True

View File

@@ -3,14 +3,11 @@
# SPDX-ArtifactOfProjectHomePage: https://github.com/Second-Hand-Friends/kleinanzeigen-bot/
import copy, logging, os, re, sys # isort: skip
from gettext import gettext as _
from logging import CRITICAL, DEBUG, ERROR, INFO, WARNING, Logger
from logging.handlers import RotatingFileHandler
from typing import Any, Final # @UnusedImport
import colorama
from . import i18n, reflect
__all__ = [
"Logger",
"LogFileHandle",
@@ -26,7 +23,14 @@ __all__ = [
"is_debug"
]
LOG_ROOT:Final[logging.Logger] = logging.getLogger()
CRITICAL = logging.CRITICAL
DEBUG = logging.DEBUG
ERROR = logging.ERROR
INFO = logging.INFO
WARNING = logging.WARNING
Logger = logging.Logger
LOG_ROOT:Final[Logger] = logging.getLogger()
class _MaxLevelFilter(logging.Filter):
@@ -141,7 +145,7 @@ def configure_console_logging() -> None:
class LogFileHandle:
"""Encapsulates a log file handler with close and status methods."""
def __init__(self, file_path:str, handler:RotatingFileHandler, logger:logging.Logger) -> None:
def __init__(self, file_path:str, handler:RotatingFileHandler, logger:Logger) -> None:
self.file_path = file_path
self._handler:RotatingFileHandler | None = handler
self._logger = logger
@@ -183,15 +187,16 @@ def flush_all_handlers() -> None:
handler.flush()
def get_logger(name:str | None = None) -> logging.Logger:
def get_logger(name:str | None = None) -> Logger:
"""
Returns a localized logger
"""
class TranslatingLogger(logging.Logger):
class TranslatingLogger(Logger):
def _log(self, level:int, msg:object, *args:Any, **kwargs:Any) -> None:
if level != DEBUG: # debug messages should not be translated
from . import i18n, reflect # noqa: PLC0415 # avoid cyclic import at module load
msg = i18n.translate(msg, reflect.get_caller(2))
super()._log(level, msg, *args, **kwargs)

View File

@@ -474,6 +474,7 @@ class WebScrapingMixin:
if is_relevant_browser:
browser_processes.append(proc.info)
except (psutil.NoSuchProcess, psutil.AccessDenied):
# Process ended or is not accessible; skip it.
pass
except (psutil.Error, PermissionError) as exc:
LOG.warning("(warn) Unable to inspect browser processes: %s", exc)
@@ -518,6 +519,7 @@ class WebScrapingMixin:
self.page = None # pyright: ignore[reportAttributeAccessIssue]
def get_compatible_browser(self) -> str:
browser_paths:list[str | None] = []
match platform.system():
case "Linux":
browser_paths = [