chore: Fix for additional linting rules

This commit is contained in:
Marty Oehme 2025-09-11 13:38:47 +02:00
parent 96cd4929c9
commit f5455b6946
Signed by: Marty
GPG key ID: 4E535BC19C61886E
7 changed files with 58 additions and 40 deletions

View file

@ -1,4 +1,9 @@
import re
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from papis_extract.annotation import Annotation
from papis_extract.exporter import Exporter
import click
import papis.cli
@ -9,8 +14,6 @@ import papis.strings
from papis.document import Document
from papis_extract import extraction
from papis_extract.annotation import Annotation
from papis_extract.exporter import Exporter
from papis_extract.exporters import all_exporters
from papis_extract.extractors import all_extractors
from papis_extract.formatter import Formatter, formatters

View file

@ -1,6 +1,6 @@
import math
from dataclasses import dataclass
from typing import Any, Optional, cast
from typing import Any, cast
import chevron
import papis.config
@ -117,7 +117,7 @@ class Annotation:
return color_mapping.get(colorname, "")
# mimics the functions in papis.config.{getlist,getint,getfloat} etc.
def _getdict(self, key: str, section: Optional[str] = None) -> dict[str, str]:
def _getdict(self, key: str, section: str | None = None) -> dict[str, str]:
"""Dict getter
:returns: A python dict
@ -126,19 +126,17 @@ class Annotation:
"""
rawvalue: Any = papis.config.general_get(key, section=section)
if isinstance(rawvalue, dict):
return cast(dict[str, str], rawvalue)
return cast("dict[str, str]", rawvalue)
try:
rawvalue = eval(rawvalue)
except Exception:
raise SyntaxError(
"The key '{}' must be a valid Python object: {}".format(key, rawvalue)
f"The configuration key '{key}' must be a valid Python dict: {rawvalue}"
)
else:
if not isinstance(rawvalue, dict):
raise SyntaxError(
"The key '{}' must be a valid Python dict. Got: {} (type {!r})".format(
key, rawvalue, type(rawvalue).__name__
)
f"The configuration key '{key}' must be a valid Python dict. Got: {rawvalue} (type {type(rawvalue).__name__})"
)
return cast(dict[str, str], rawvalue)
return cast("dict[str, str]", rawvalue)

View file

@ -1,4 +1,5 @@
from dataclasses import dataclass
from pathlib import Path
import Levenshtein
import papis.commands.edit
@ -69,11 +70,11 @@ class NotesExporter:
:type duplicates: bool, optional
"""
logger.debug("Adding annotations to note...")
notes_path = papis.notes.notes_path_ensured(document)
notes_path = Path(papis.notes.notes_path_ensured(document))
existing: list[str] = []
with open(notes_path, "r") as file_read:
existing = file_read.readlines()
with notes_path.open("r") as fr:
existing = fr.readlines()
new_annotations: list[str] = formatted_annotations
if not duplicates:
@ -81,15 +82,16 @@ class NotesExporter:
formatted_annotations, existing
)
if not new_annotations:
logger.debug("No new annotations to be added.")
return
with open(notes_path, "a") as f:
with notes_path.open("a") as fa:
# add newline if theres no empty space at file end
if len(existing) > 0 and existing[-1].strip() != "":
f.write("\n")
fa.write("\n")
# We filter out any empty lines from the annotations
filtered_annotations = [annot for annot in new_annotations if annot != ""]
f.write("\n\n".join(filtered_annotations))
fa.write("\n\n".join(filtered_annotations))
logger.info(
f"Wrote {len(filtered_annotations)} "
f"{'line' if len(filtered_annotations) == 1 else 'lines'} "
@ -97,11 +99,11 @@ class NotesExporter:
)
if git:
msg = "Update notes for '{0}'".format(papis.document.describe(document))
msg = f"Update annotations for '{papis.document.describe(document)}'"
folder = document.get_main_folder()
if folder:
papis.git.add_and_commit_resources(
folder, [notes_path, document.get_info_file()], msg
folder, [str(notes_path), document.get_info_file()], msg
)
def _drop_existing_annotations(

View file

@ -19,9 +19,7 @@ class PdfExtractor:
if not filename.is_file():
logger.error(f"File {str(filename)} not readable.")
return False
if not self._is_pdf(filename):
return False
return True
return self._is_pdf(filename)
def run(self, filename: Path) -> list[Annotation]:
"""Extract annotations from a file.
@ -39,15 +37,15 @@ class PdfExtractor:
if not quote and not note:
continue
color: tuple[float, float, float] = cast(
tuple[float, float, float],
"tuple[float, float, float]",
(
annot.colors.get("fill")
or annot.colors.get("stroke")
or (0.0, 0.0, 0.0)
),
)
page_nr: int = cast(int, page.number or 0)
highlight_type: str = cast(str, annot.type[1] or "")
page_nr: int = cast("int", page.number or 0)
highlight_type: str = cast("str", annot.type[1] or "")
a = Annotation(
file=str(filename),
content=quote or "",
@ -83,7 +81,7 @@ class PdfExtractor:
should both be included or are the same, using
Levenshtein distance.
"""
content = cast(str, annotation.info["content"].replace("\n", " "))
content = cast("str", annotation.info["content"].replace("\n", " "))
written = page.get_textbox(annotation.rect).replace("\n", " ")
# highlight with selection in note
@ -94,13 +92,13 @@ class PdfExtractor:
if Levenshtein.ratio(content, written) > minimum_similarity:
return (content, None)
# both a highlight and a note
elif content and written:
if content and written:
return (written, content)
# an independent note, not a highlight
elif content:
if content:
return (None, content)
# highlight with selection not in note
elif written:
if written:
return (written, None)
# just a highlight without any text
return (None, None)

View file

@ -2,7 +2,6 @@
from pathlib import Path
import magic
import papis.config
import papis.logging
from bs4 import BeautifulSoup
@ -13,7 +12,7 @@ logger = papis.logging.get_logger(__name__)
class PocketBookExtractor:
def can_process(self, filename: Path) -> bool:
if not magic.from_file(filename, mime=True) == "text/xml":
if magic.from_file(filename, mime=True) != "text/xml":
return False
content = self._read_file(filename)
@ -21,11 +20,11 @@ class PocketBookExtractor:
return False
html = BeautifulSoup(content, features="xml")
if not html.find(
"meta", {"name": "generator", "content": "PocketBook Bookmarks Export"}
):
return False
return True
return bool(
html.find(
"meta", {"name": "generator", "content": "PocketBook Bookmarks Export"}
)
)
def run(self, filename: Path) -> list[Annotation]:
"""Extract annotations from pocketbook html file.
@ -78,8 +77,8 @@ class PocketBookExtractor:
def _read_file(self, filename: Path) -> str:
try:
with open(filename) as f:
return f.read()
with filename.open("r") as fr:
return fr.read()
except FileNotFoundError:
logger.error(f"Could not open file {filename} for extraction.")
return ""

View file

@ -17,7 +17,7 @@ class ReadEraExtractor:
"""
def can_process(self, filename: Path) -> bool:
if not magic.from_file(filename, mime=True) == "text/plain":
if magic.from_file(filename, mime=True) != "text/plain":
return False
content = self._read_file(filename)
@ -83,8 +83,8 @@ class ReadEraExtractor:
def _read_file(self, filename: Path) -> list[str]:
try:
with open(filename, encoding="utf-8") as f:
return f.readlines()
with filename.open("r") as fr:
return fr.readlines()
except FileNotFoundError:
logger.error(f"Could not open file {filename} for extraction.")
return []

View file

@ -39,6 +39,24 @@ pocketbook = ["beautifulsoup4<5.0.0,>=4.12.3"]
[tool.uv]
dev-dependencies = ["pytest<9.0.0,>=8.0.0", "pytest-cov<7.0.0,>=6.0.0"]
[tool.ruff.lint]
extend-select = [
"C4", # Catch incorrect use of comprehensions, dict, list, etc
"F", # Pyflakes rules
"FA", # Enforce from __future__ import annotations
"I", # Sort imports properly
"ICN", # Use common import conventions
"ISC", # Good use of string concatenation
"NPY", # Some numpy-specific things
"PTH", # Use pathlib instead of os.path
"RET", # Good return practices
"SIM", # Common simplification rules
"TC", # Enforce importing certain types in a TYPE_CHECKING block
"TID", # Some good import practices
"UP", # Warn if certain things can changed due to newer Python versions
"W", # PyCodeStyle warnings
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"