ruff: enable EM lint

This commit is contained in:
Marcel Hellwig
2026-01-04 14:05:44 +01:00
parent 7ef4e52c81
commit 97cb3b5c1e
15 changed files with 100 additions and 83 deletions

View File

@@ -51,7 +51,8 @@ def init_engine(
if db_config is None:
url = os.getenv("DATABASE_URL")
if not url:
raise RuntimeError("DB config or `DATABASE_URL` must be provided")
msg = "DB config or `DATABASE_URL` must be provided"
raise RuntimeError(msg)
else:
url = build_db_url(
db_config.user,
@@ -76,15 +77,15 @@ def init_engine(
def get_engine() -> Engine:
if engine is None:
raise RuntimeError("Engine not initialized. Call init_engine(...) first.")
msg = "Engine not initialized. Call init_engine(...) first."
raise RuntimeError(msg)
return engine
def get_session() -> Generator[Session, Any, None]:
if SessionLocal is None:
raise RuntimeError(
"Session factory not initialized. Call init_engine(...) first."
)
msg = "Session factory not initialized. Call init_engine(...) first."
raise RuntimeError(msg)
db = SessionLocal()
try:
yield db

View File

@@ -12,7 +12,8 @@ class GenericIndexer(ABC):
if name:
self.name = name
else:
raise ValueError("indexer name must not be None")
msg = "indexer name must not be None"
raise ValueError(msg)
@abstractmethod
def search(self, query: str, is_tv: bool) -> list[IndexerQueryResult]:

View File

@@ -132,7 +132,8 @@ def follow_redirects_to_final_torrent_url(
if 300 <= response.status_code < 400:
redirect_url = response.headers.get("Location")
if not redirect_url:
raise RuntimeError("Redirect response without Location header")
msg = "Redirect response without Location header"
raise RuntimeError(msg)
# Resolve relative redirects against the last URL
current_url = urljoin(current_url, redirect_url)
@@ -144,10 +145,12 @@ def follow_redirects_to_final_torrent_url(
response.raise_for_status() # Raise an exception for bad status codes
return current_url
else:
raise RuntimeError("Exceeded maximum number of redirects")
msg = "Exceeded maximum number of redirects"
raise RuntimeError(msg)
except requests.exceptions.RequestException as e:
log.debug(f"An error occurred during the request for {initial_url}: {e}")
raise RuntimeError(f"An error occurred during the request: {e}") from e
msg = f"An error occurred during the request: {e}"
raise RuntimeError(msg) from e
return current_url

View File

@@ -45,7 +45,8 @@ class MovieRepository:
stmt = select(Movie).where(Movie.id == movie_id)
result = self.db.execute(stmt).unique().scalar_one_or_none()
if not result:
raise NotFoundError(f"Movie with id {movie_id} not found.")
msg = f"Movie with id {movie_id} not found."
raise NotFoundError(msg)
return MovieSchema.model_validate(result)
except SQLAlchemyError as e:
log.error(f"Database error while retrieving movie {movie_id}: {e}")
@@ -71,9 +72,8 @@ class MovieRepository:
)
result = self.db.execute(stmt).unique().scalar_one_or_none()
if not result:
raise NotFoundError(
f"Movie with external_id {external_id} and provider {metadata_provider} not found."
)
msg = f"Movie with external_id {external_id} and provider {metadata_provider} not found."
raise NotFoundError(msg)
return MovieSchema.model_validate(result)
except SQLAlchemyError as e:
log.error(
@@ -130,9 +130,10 @@ class MovieRepository:
except IntegrityError as e:
self.db.rollback()
log.error(f"Integrity error while saving movie {movie.name}: {e}")
raise ConflictError(
msg = (
f"Movie with this primary key or unique constraint violation: {e.orig}"
) from e
)
raise ConflictError(msg) from e
except SQLAlchemyError as e:
self.db.rollback()
log.error(f"Database error while saving movie {movie.name}: {e}")
@@ -151,7 +152,8 @@ class MovieRepository:
movie = self.db.get(Movie, movie_id)
if not movie:
log.warning(f"Movie with id {movie_id} not found for deletion.")
raise NotFoundError(f"Movie with id {movie_id} not found.")
msg = f"Movie with id {movie_id} not found."
raise NotFoundError(msg)
self.db.delete(movie)
self.db.commit()
log.info(f"Successfully deleted movie with id: {movie_id}")
@@ -212,7 +214,8 @@ class MovieRepository:
try:
movie = self.db.get(Movie, movie_id)
if not movie:
raise NotFoundError(f"movie with id {movie_id} not found.")
msg = f"movie with id {movie_id} not found."
raise NotFoundError(msg)
movie.library = library
self.db.commit()
except SQLAlchemyError as e:
@@ -233,9 +236,8 @@ class MovieRepository:
result = self.db.execute(stmt)
if result.rowcount == 0:
self.db.rollback()
raise NotFoundError(
f"movie request with id {movie_request_id} not found."
)
msg = f"movie request with id {movie_request_id} not found."
raise NotFoundError(msg)
self.db.commit()
# Successfully deleted movie request with id: {movie_request_id}
except SQLAlchemyError as e:
@@ -395,9 +397,8 @@ class MovieRepository:
try:
request = self.db.get(MovieRequest, movie_request_id)
if not request:
raise NotFoundError(
f"Movie request with id {movie_request_id} not found."
)
msg = f"Movie request with id {movie_request_id} not found."
raise NotFoundError(msg)
return MovieRequestSchema.model_validate(request)
except SQLAlchemyError as e:
log.error(
@@ -422,7 +423,8 @@ class MovieRepository:
)
result = self.db.execute(stmt).unique().scalar_one_or_none()
if not result:
raise NotFoundError(f"Movie for torrent_id {torrent_id} not found.")
msg = f"Movie for torrent_id {torrent_id} not found."
raise NotFoundError(msg)
return MovieSchema.model_validate(result)
except SQLAlchemyError as e:
log.error(
@@ -450,7 +452,8 @@ class MovieRepository:
"""
db_movie = self.db.get(Movie, movie_id)
if not db_movie:
raise NotFoundError(f"Movie with id {movie_id} not found.")
msg = f"Movie with id {movie_id} not found."
raise NotFoundError(msg)
updated = False
if name is not None and db_movie.name != name:

View File

@@ -47,9 +47,8 @@ class MovieRequestBase(BaseModel):
@model_validator(mode="after")
def ensure_wanted_quality_is_eq_or_gt_min_quality(self) -> "MovieRequestBase":
if self.min_quality.value < self.wanted_quality.value:
raise ValueError(
"wanted_quality must be equal to or lower than minimum_quality."
)
msg = "wanted_quality must be equal to or lower than minimum_quality."
raise ValueError(msg)
return self

View File

@@ -218,9 +218,10 @@ class MovieService:
return False
else:
raise ValueError(
msg = (
"Either external_id and metadata_provider or movie_id must be provided"
)
raise ValueError(msg)
def get_all_available_torrents_for_movie(
self, movie: Movie, search_query_override: str = None
@@ -462,7 +463,8 @@ class MovieService:
:raises ValueError: If the movie request is not authorized.
"""
if not movie_request.authorized:
raise ValueError("Movie request is not authorized")
msg = "Movie request is not authorized"
raise ValueError(msg)
log.info(f"Downloading approved movie request {movie_request.id}")
@@ -663,7 +665,8 @@ class MovieService:
source_directory.rename(new_source_path)
except Exception as e:
log.error(f"Failed to rename {source_directory} to {new_source_path}: {e}")
raise Exception("Failed to rename directory") from e
msg = "Failed to rename directory"
raise Exception(msg) from e
video_files, subtitle_files, all_files = get_files_for_import(
directory=new_source_path

View File

@@ -24,7 +24,8 @@ class NotificationRepository:
result = self.db.get(Notification, id)
if not result:
raise NotFoundError(f"Notification with id {id} not found.")
msg = f"Notification with id {id} not found."
raise NotFoundError(msg)
return NotificationSchema.model_validate(result)
@@ -69,9 +70,8 @@ class NotificationRepository:
self.db.commit()
except IntegrityError as e:
log.error(f"Could not save notification, Error: {e}")
raise ConflictError(
f"Notification with id {notification.id} already exists."
) from None
msg = f"Notification with id {notification.id} already exists."
raise ConflictError(msg) from None
return
def mark_notification_as_read(self, id: NotificationId) -> None:
@@ -88,6 +88,7 @@ class NotificationRepository:
stmt = delete(Notification).where(Notification.id == id)
result = self.db.execute(stmt)
if result.rowcount == 0:
raise NotFoundError(f"Notification with id {id} not found.")
msg = f"Notification with id {id} not found."
raise NotFoundError(msg)
self.db.commit()
return

View File

@@ -102,9 +102,8 @@ class QbittorrentDownloadClient(AbstractDownloadClient):
log.error(
f"Failed to download torrent, API-Answer isn't 'Ok.'; API Answer: {answer}"
)
raise RuntimeError(
f"Failed to download torrent, API-Answer isn't 'Ok.'; API Answer: {answer}"
)
msg = f"Failed to download torrent, API-Answer isn't 'Ok.'; API Answer: {answer}"
raise RuntimeError(msg)
log.info(f"Successfully processed torrent: {indexer_result.title}")

View File

@@ -56,7 +56,8 @@ class SabnzbdDownloadClient(AbstractDownloadClient):
if not response["status"]:
error_msg = response
log.error(f"Failed to add NZB to SABnzbd: {error_msg}")
raise RuntimeError(f"Failed to add NZB to SABnzbd: {error_msg}")
msg = f"Failed to add NZB to SABnzbd: {error_msg}"
raise RuntimeError(msg)
# Generate a hash for the NZB (using title and download URL)
nzo_id = response["nzo_ids"][0]

View File

@@ -79,11 +79,13 @@ class DownloadManager:
# Use the usenet flag from the indexer result to determine the client type
if indexer_result.usenet:
if not self._usenet_client:
raise RuntimeError("No usenet download client configured")
msg = "No usenet download client configured"
raise RuntimeError(msg)
return self._usenet_client
else:
if not self._torrent_client:
raise RuntimeError("No torrent download client configured")
msg = "No torrent download client configured"
raise RuntimeError(msg)
return self._torrent_client
def download(self, indexer_result: IndexerQueryResult) -> Torrent:

View File

@@ -52,7 +52,8 @@ class TorrentRepository:
def get_torrent_by_id(self, torrent_id: TorrentId) -> TorrentSchema:
result = self.db.get(Torrent, torrent_id)
if result is None:
raise NotFoundError(f"Torrent with ID {torrent_id} not found.")
msg = f"Torrent with ID {torrent_id} not found."
raise NotFoundError(msg)
return TorrentSchema.model_validate(result)
def delete_torrent(

View File

@@ -51,7 +51,8 @@ class TvRepository:
)
result = self.db.execute(stmt).unique().scalar_one_or_none()
if not result:
raise NotFoundError(f"Show with id {show_id} not found.")
msg = f"Show with id {show_id} not found."
raise NotFoundError(msg)
return ShowSchema.model_validate(result)
except SQLAlchemyError as e:
log.error(f"Database error while retrieving show {show_id}: {e}")
@@ -78,9 +79,8 @@ class TvRepository:
)
result = self.db.execute(stmt).unique().scalar_one_or_none()
if not result:
raise NotFoundError(
f"Show with external_id {external_id} and provider {metadata_provider} not found."
)
msg = f"Show with external_id {external_id} and provider {metadata_provider} not found."
raise NotFoundError(msg)
return ShowSchema.model_validate(result)
except SQLAlchemyError as e:
log.error(
@@ -178,9 +178,8 @@ class TvRepository:
return ShowSchema.model_validate(db_show)
except IntegrityError as e:
self.db.rollback()
raise ConflictError(
f"Show with this primary key or unique constraint violation: {e.orig}"
) from e
msg = f"Show with this primary key or unique constraint violation: {e.orig}"
raise ConflictError(msg) from e
except SQLAlchemyError as e:
self.db.rollback()
log.error(f"Database error while saving show {show.name}: {e}")
@@ -197,7 +196,8 @@ class TvRepository:
try:
show = self.db.get(Show, show_id)
if not show:
raise NotFoundError(f"Show with id {show_id} not found.")
msg = f"Show with id {show_id} not found."
raise NotFoundError(msg)
self.db.delete(show)
self.db.commit()
except SQLAlchemyError as e:
@@ -217,7 +217,8 @@ class TvRepository:
try:
season = self.db.get(Season, season_id)
if not season:
raise NotFoundError(f"Season with id {season_id} not found.")
msg = f"Season with id {season_id} not found."
raise NotFoundError(msg)
return SeasonSchema.model_validate(season)
except SQLAlchemyError as e:
log.error(f"Database error while retrieving season {season_id}: {e}")
@@ -274,9 +275,8 @@ class TvRepository:
result = self.db.execute(stmt)
if result.rowcount == 0:
self.db.rollback()
raise NotFoundError(
f"SeasonRequest with id {season_request_id} not found."
)
msg = f"SeasonRequest with id {season_request_id} not found."
raise NotFoundError(msg)
self.db.commit()
except SQLAlchemyError as e:
self.db.rollback()
@@ -304,9 +304,8 @@ class TvRepository:
)
result = self.db.execute(stmt).unique().scalar_one_or_none()
if not result:
raise NotFoundError(
f"Season number {season_number} for show_id {show_id} not found."
)
msg = f"Season number {season_number} for show_id {show_id} not found."
raise NotFoundError(msg)
return SeasonSchema.model_validate(result)
except SQLAlchemyError as e:
log.error(
@@ -403,7 +402,8 @@ class TvRepository:
try:
show = self.db.get(Show, show_id)
if not show:
raise NotFoundError(f"Show with id {show_id} not found.")
msg = f"Show with id {show_id} not found."
raise NotFoundError(msg)
show.library = library
self.db.commit()
except SQLAlchemyError as e:
@@ -514,9 +514,8 @@ class TvRepository:
request = self.db.get(SeasonRequest, season_request_id)
if not request:
log.warning(f"Season request with id {season_request_id} not found.")
raise NotFoundError(
f"Season request with id {season_request_id} not found."
)
msg = f"Season request with id {season_request_id} not found."
raise NotFoundError(msg)
return SeasonRequestSchema.model_validate(request)
except SQLAlchemyError as e:
log.error(
@@ -542,7 +541,8 @@ class TvRepository:
)
result = self.db.execute(stmt).unique().scalar_one_or_none()
if not result:
raise NotFoundError(f"Show for season_id {season_id} not found.")
msg = f"Show for season_id {season_id} not found."
raise NotFoundError(msg)
return ShowSchema.model_validate(result)
except SQLAlchemyError as e:
log.error(f"Database error retrieving show by season_id {season_id}: {e}")
@@ -563,7 +563,8 @@ class TvRepository:
"""
db_show = self.db.get(Show, show_id)
if not db_show:
raise NotFoundError(f"Show with id {show_id} not found.")
msg = f"Show with id {show_id} not found."
raise NotFoundError(msg)
stmt = (
select(Season)
@@ -612,7 +613,8 @@ class TvRepository:
"""
db_season = self.db.get(Season, season_id)
if not db_season:
raise NotFoundError(f"Season with id {season_id} not found.")
msg = f"Season with id {season_id} not found."
raise NotFoundError(msg)
stmt = (
select(Episode)
@@ -660,7 +662,8 @@ class TvRepository:
"""
db_show = self.db.get(Show, show_id)
if not db_show:
raise NotFoundError(f"Show with id {show_id} not found.")
msg = f"Show with id {show_id} not found."
raise NotFoundError(msg)
updated = False
if name is not None and db_show.name != name:
@@ -705,7 +708,8 @@ class TvRepository:
"""
db_season = self.db.get(Season, season_id)
if not db_season:
raise NotFoundError(f"Season with id {season_id} not found.")
msg = f"Season with id {season_id} not found."
raise NotFoundError(msg)
updated = False
if name is not None and db_season.name != name:
@@ -735,7 +739,8 @@ class TvRepository:
"""
db_episode = self.db.get(Episode, episode_id)
if not db_episode:
raise NotFoundError(f"Episode with id {episode_id} not found.")
msg = f"Episode with id {episode_id} not found."
raise NotFoundError(msg)
updated = False
if title is not None and db_episode.title != title:

View File

@@ -69,9 +69,8 @@ class SeasonRequestBase(BaseModel):
@model_validator(mode="after")
def ensure_wanted_quality_is_eq_or_gt_min_quality(self) -> "SeasonRequestBase":
if self.min_quality.value < self.wanted_quality.value:
raise ValueError(
"wanted_quality must be equal to or lower than minimum_quality."
)
msg = "wanted_quality must be equal to or lower than minimum_quality."
raise ValueError(msg)
return self

View File

@@ -223,9 +223,8 @@ class TvService:
except NotFoundError:
return False
else:
raise ValueError(
"External ID and metadata provider or Show ID must be provided"
)
msg = "External ID and metadata provider or Show ID must be provided"
raise ValueError(msg)
def get_all_available_torrents_for_a_season(
self, season_number: int, show_id: ShowId, search_query_override: str = None
@@ -511,9 +510,8 @@ class TvService:
:raises ValueError: If the season request is not authorized.
"""
if not season_request.authorized:
raise ValueError(
f"Season request {season_request.id} is not authorized for download"
)
msg = f"Season request {season_request.id} is not authorized for download"
raise ValueError(msg)
log.info(f"Downloading approved season request {season_request.id}")
@@ -633,9 +631,8 @@ class TvService:
import_file(target_file=target_video_file, source_file=file)
return True
else:
raise Exception(
f"Could not find any video file for episode {episode_number} of show {show.name} S{season.number}"
)
msg = f"Could not find any video file for episode {episode_number} of show {show.name} S{season.number}"
raise Exception(msg)
def import_season(
self,
@@ -654,7 +651,8 @@ class TvService:
season_path.mkdir(parents=True, exist_ok=True)
except Exception as e:
log.warning(f"Could not create path {season_path}: {e}")
raise Exception(f"Could not create path {season_path}") from e
msg = f"Could not create path {season_path}"
raise Exception(msg) from e
for episode in season.episodes:
try:
@@ -896,7 +894,8 @@ class TvService:
source_directory.rename(new_source_path)
except Exception as e:
log.error(f"Failed to rename {source_directory} to {new_source_path}: {e}")
raise Exception("Failed to rename source directory") from e
msg = "Failed to rename source directory"
raise Exception(msg) from e
video_files, subtitle_files, all_files = get_files_for_import(
directory=new_source_path