adsfolio.pdf.watcher

PDF filesystem watcher with polling and optional watchdog backends.

exception adsfolio.pdf.watcher.PdfNotReadyError[source]

Bases: RuntimeError

Indicate that a PDF should be retried after its filesystem state changes.

class adsfolio.pdf.watcher.PdfWatcher(identifier, renamer, upgrader=None)[source]

Bases: object

Watch directories for new PDF files and process them.

Parameters:
poll_loop(directory, sidecar, interval=10.0, recursive=False, callback=None, stop_event=None, auto_upgrade=False, upgrade_interval_hours=24.0, upgrade_kwargs=None, recheck_callback=None, update_locations=True)[source]

Poll filesystem for new PDFs and process them.

Parameters:
Return type:

None

process_event(event, state, rename_settings, identify_settings)[source]

Process one typed watch event using reusable GUI settings.

Parameters:
Returns:

Typed processing result. Readiness failures are deferred and expected processing failures are reported as failed outcomes.

Return type:

WatchOutcome

process_new_pdf(pdf_path, sidecar, scheme='{authors}_{bibcode}-{title}', author_format='surname_initials', char_policy='keep', max_authors=3, authors_when_truncated=1, output_unresolved=None, apply=True, journal_map=None, strategies=(IdentifyStrategy.FIRST_PAGE_ARXIV, IdentifyStrategy.FILENAME_BIBCODE, IdentifyStrategy.FILENAME_DOI, IdentifyStrategy.PDF_METADATA_BIBCODE, IdentifyStrategy.PDF_METADATA_DOI, IdentifyStrategy.FIRST_PAGE_BIBCODE, IdentifyStrategy.FIRST_PAGE_DOI, IdentifyStrategy.STRUCTURED_FILENAME, IdentifyStrategy.PDF_METADATA_TITLE, IdentifyStrategy.FIRST_PAGE_TITLE), providers=(DoiProvider.ADS, DoiProvider.CROSSREF, DoiProvider.DATACITE), author_separator='+', author_truncation_suffix='+', _check_annotation_revision=True)[source]

Identify and rename a single PDF, returning resolved metadata.

Every stored record is checked against the PDF’s own identity before the catalog is written or the file is renamed, including a dry run.

Raises:

IdentityValidationError – If a stored or newly found identity conflicts with the PDF or cannot be independently verified. Nothing is written or moved.

Parameters:
Return type:

dict | None

watchdog_loop(directory, sidecar, recursive=False, callback=None, reconciliation_interval=10.0, stop_event=None, auto_upgrade=False, upgrade_interval_hours=24.0, upgrade_kwargs=None, recheck_callback=None, update_locations=True)[source]

Use watchdog Observer backend to react to filesystem events.

Parameters:
Return type:

None

class adsfolio.pdf.watcher.WatchIdentifyPolicy(root, unresolved_directory, skip_unresolved_directory)[source]

Bases: object

Resolved single-file Identify path policy for one watched root.

Parameters:
excludes(path)[source]

Return whether path is inside the configured skip directory.

Parameters:

path (pathlib.Path)

Return type:

bool

classmethod from_settings(root, settings)[source]

Resolve output and skip containment from reusable settings.

Parameters:
Returns:

Normalized root, unresolved directory, and skip behavior. Relative output paths are rooted under the library; an unset output uses <root>/unresolved for skip containment, matching bulk Identify.

Return type:

WatchIdentifyPolicy

Raises:

ValueError – If skipping is enabled and the unresolved directory contains the watched root.

root: pathlib.Path
skip_unresolved_directory: bool
unresolved_directory: pathlib.Path