adsfolio.pdf.catalog
Central local catalog for PDF attachments and observed file locations.
- class adsfolio.pdf.catalog.CatalogObservation(attachment_id, location_id, version_id, matched_by)[source]
Bases:
objectResult of registering one observed filesystem location.
- class adsfolio.pdf.catalog.LegacyMigrationReport(imported)[source]
Bases:
objectSummary of one legacy-root migration.
- Parameters:
imported (int)
- class adsfolio.pdf.catalog.PdfCatalog(path=None)[source]
Bases:
objectStore PDF attachment identity independently of filesystem paths.
- Parameters:
path (Path | None)
- ads_bibtex_entries()[source]
Return saved ADS BibTeX as
{bibcode: (entry, fingerprint)}.A None entry means that ADS returned no entry for that Bibcode.
- attach_document_file(document_id, path, *, sha256, size_bytes, mtime_ns, device, inode)[source]
Observe a PDF and link it without replacing another document identity.
- classmethod canonical_doi(value)[source]
Return a DOI in comparable form: lowercase, without URL or prefix.
- change_token()[source]
Return a value that changes after any write to this catalog.
The first value identifies this open catalog in the process.
total_changescounts rows that this connection changed.PRAGMA data_versionchanges after another connection commits. Equal tokens therefore mean that no committed or pending write occurred between the two calls.
- clear_watch_pending(root, relative_path)[source]
Clear the watch mark of one active location. Change nothing else.
- Returns:
True when a marked row was changed.
- Return type:
- Parameters:
root (pathlib.Path)
relative_path (str)
- count_files(*, root=None, status=None, resolved=None, search=None, search_exact=False, search_wildcards=False, search_fields=(), include_missing=False, document_id=None, attachment_id=None, location_id=None, sha256=None)[source]
Count the locations that query_files returns for the same filters.
The count is done in SQL. Only a search reads metadata JSON. Digest collections are not accepted; call query_files for those.
- Parameters:
root (pathlib.Path | None)
status (str | None)
resolved (bool | None)
search (str | None)
search_exact (bool)
search_wildcards (bool)
search_fields (collections.abc.Collection[str])
include_missing (bool)
document_id (int | None)
attachment_id (int | None)
location_id (int | None)
sha256 (str | None)
- Return type:
- delete_locations(root, location_ids)[source]
Delete selected locations and orphaned attachments explicitly.
- Parameters:
root (pathlib.Path)
- Return type:
- discover_root(root, *, recursive=True, cancelled=None)[source]
Discover PDFs and verify known identity candidates by content.
Changed tracked files are hashed before their filesystem facts are updated. A new path is also hashed when its filesystem identity has a known digest. New paths in an existing library are queued for watching; the first import retains the baseline behavior. The digest decides whether the file is that content again (see _observe_file). Unchanged files are never hashed. A file that vanishes before hashing is skipped; any other read error aborts the scan before the catalog changes.
- Parameters:
root (pathlib.Path)
recursive (bool)
cancelled (collections.abc.Callable[[], bool] | None)
- Return type:
- document_for_attachment(attachment_id)[source]
Return the canonical document linked to an attachment.
- classmethod document_identity(metadata)[source]
Return the bibcode, canonical DOI, and arXiv ID of document metadata.
Missing identifiers are empty strings. The arXiv ID has no version.
- ensure_root(root)[source]
Register a library root and return its catalog identifier.
- Parameters:
root (pathlib.Path)
- Return type:
- find_ads_documents_by_bibcodes(bibcodes)[source]
Return cached provider documents keyed by lowercase Bibcode.
- get_file(root, relative_path)[source]
Return one location record and its attachment metadata.
Prefer an exact path match, including a missing location. Otherwise, return a unique active Unicode alias proven by its directory entry.
- Parameters:
root (pathlib.Path)
relative_path (str)
- Return type:
- mark_location_missing(root, relative_path)[source]
Retain one absent file location as history after an external move.
The path must no longer exist. Filesystem access errors stop the update. Return False when no active catalog location owns the path.
- Parameters:
root (pathlib.Path)
relative_path (str)
- Return type:
- mark_missing_locations(root, seen_paths, recursive=True)[source]
Mark active root locations absent from a completed scan as missing.
- Parameters:
root (pathlib.Path)
recursive (bool)
- Return type:
- migrate_legacy_root(root)[source]
Import legacy root state without changing its source files.
- Parameters:
root (pathlib.Path)
- Return type:
- move_file(root, relative_path, new_relative_path)[source]
Move a location while retaining its attachment and version history.
- Parameters:
root (pathlib.Path)
relative_path (str)
new_relative_path (str)
- Return type:
- observe_file(root, relative_path, *, sha256, size_bytes, mtime_ns, device=None, inode=None, metadata=None, status=None)[source]
Register one filesystem observation atomically.
- Parameters:
- Return type:
- preserve_annotation_revision(root, relative_path, expected_sha256, *, apply=True)[source]
Preserve an identified record when only PDF annotations changed.
The previous identified bytes must occur as an exact, cataloged prefix. Both revisions must have the same non-annotation PDF structure. An existing identity proof keeps its verification level. A legacy record without proof does not gain one.
- Parameters:
- Returns:
The preserved record, or None when continuity cannot be proven.
- Return type:
dict or None
- query_files(*, root=None, status=None, resolved=None, search=None, search_exact=False, search_wildcards=False, search_fields=(), include_missing=False, document_id=None, attachment_id=None, location_id=None, sha256=None)[source]
Return location records matching local catalog filters.
- Parameters:
include_missing (bool) – Include historical locations whose files are no longer observed. Normal queries return only current locations.
document_id (int | None) – Restrict locations to one canonical document when supplied.
attachment_id (int | None) – Restrict results to one attachment or one location identifier.
location_id (int | None) – Restrict results to one attachment or one location identifier.
search (str | None) – Keep locations that match the query search. search_fields names the fields that plain terms search. See adsfolio.pdf.search.document_matches for the rules.
search_exact (bool) – Keep locations that match the query search. search_fields names the fields that plain terms search. See adsfolio.pdf.search.document_matches for the rules.
search_wildcards (bool) – Keep locations that match the query search. search_fields names the fields that plain terms search. See adsfolio.pdf.search.document_matches for the rules.
search_fields (collections.abc.Collection[str]) – Keep locations that match the query search. search_fields names the fields that plain terms search. See adsfolio.pdf.search.document_matches for the rules.
sha256 (str | collections.abc.Collection[str] | None) – One digest, or a collection of digests, of the current content. An empty collection matches nothing. A collection runs one indexed query per distinct digest and merges the rows, so its size is not limited by the number of SQL variables.
root (pathlib.Path | None)
status (str | None)
resolved (bool | None)
- Return type:
- query_location_ids(*, root=None, search, search_exact=False, search_wildcards=False, search_fields=())[source]
Return current location identifiers that match search in SQL.
It applies the same search rule as query_files.
- Parameters:
root (pathlib.Path | None)
search (str)
search_exact (bool)
search_wildcards (bool)
search_fields (collections.abc.Collection[str])
- Return type:
- register_verified_replacement(root, relative_path, metadata)[source]
Register verified new contents without losing an absent PDF’s history.
A different name rejoins an old attachment only when exactly one matching attachment has no live locations. Existing editions remain separate. A different paper at the same path receives a new attachment. File bytes are never changed. Unknown filesystem state stops the write.
- Parameters:
root (pathlib.Path)
relative_path (str)
metadata (collections.abc.Mapping[str, Any])
- Return type:
- replace_file_metadata(root, relative_path, metadata)[source]
Replace local metadata for one attachment without changing identity.
- Parameters:
root (pathlib.Path)
relative_path (str)
metadata (collections.abc.Mapping[str, Any])
- Return type:
- replace_file_metadata_if_unchanged(root, relative_path, metadata, expected_record, *, expected_document=<object object>, changed_fields=None, allow_reviewed_stale_recovery=False)[source]
Replace metadata only when the catalog record matches a snapshot.
- Parameters:
root (pathlib.Path) – Library root that contains the location.
relative_path (str) – Path of the location within the root.
metadata (collections.abc.Mapping[str, Any]) – Replacement metadata, with the same semantics as
replace_file_metadata.expected_record (collections.abc.Mapping[str, Any]) – Unmodified record returned by
get_fileorquery_files. Keep its nested metadata separate from the replacement metadata.expected_document (collections.abc.Mapping[str, Any] | None) – Unmodified snapshot returned by
get_document. Pass None when the record has no linked document. Omit this argument to skip the document check.changed_fields (collections.abc.Collection[str] | None) – Fields to merge into an existing document. Omit this argument to infer changes from expected_record and metadata. An empty collection leaves existing document metadata unchanged. The full replacement still updates the attachment and identifies the target document. A new document receives the full replacement metadata.
allow_reviewed_stale_recovery (bool) – Allow a manually reviewed conflict to replace stale metadata. The proof must match the current PDF hash and identifiers.
- Returns:
True if the replacement succeeds. False if the location is missing or a supplied snapshot is incomplete or no longer matches. Get fresh snapshots before retrying after False.
- Return type:
- Raises:
RuntimeError – If this connection already has an open transaction.
TypeError – If changed_fields is a string or contains a non-string value.
sqlite3.OperationalError – If SQLite cannot acquire the write lock before its timeout.
Notes
The comparison and replacement share one SQLite write transaction. The digest and file facts come from the catalog, not the PDF on disk. The record snapshot does not include linked document metadata. The optional document check covers only the currently linked document. It does not guard a different document selected by replacement metadata. The replacement updates the attachment and may update its document. Other locations can share the attachment or document. Document fields use the existing merge rules for locks and empty values. For non-stale records, the catalog retains the current status when metadata omits status and leaves identifiers and identity proof unchanged. Explicit status and identity changes use the existing replacement rules. The comparison cannot detect changes that restore the snapshot values. Other connections can write again after this call commits.
- save_reference_documents(documents, *, source_text=None)[source]
Save one reference batch atomically and update attached metadata.
- Parameters:
documents (list[collections.abc.Mapping[str, Any]]) – Document mappings containing metadata, optional bibcode, and optional existing id. Duplicate citation keys and DOIs fail the whole batch; existing documents are never merged implicitly.
source_text (str | None) – Original BibTeX to store once for the batch, addressed by its SHA-256 digest in catalog_meta.
- Return type:
- search_texts(root)[source]
Return the raw text columns that the search filter compares.
Each row holds the location identifier, relative path, stored metadata JSON, and current digest of one current location in root.
- set_ads_document_metrics(bibcode, metrics)[source]
Store citation metrics inside a cached provider document.
- Parameters:
bibcode (str)
metrics (collections.abc.Mapping[str, int | None])
- Return type:
- set_document_cite_key(document_id, key)[source]
Save or clear the typed citation key of one document.
- Parameters:
document_id (int) – Catalog document ID.
key (str) – The key. An empty string removes the typed key.
- Raises:
ValueError – If document_id is unknown.
- Return type:
None
- store_ads_bibtex(entries)[source]
Save ADS BibTeX results as
{bibcode: (entry, fingerprint)}.Save a None entry when ADS returned none, so the same metadata is not requested again.
- Parameters:
entries (collections.abc.Mapping[str, tuple[str | None, str]])
- Return type:
None
- update_file_status(root, relative_path, status)[source]
Update the attachment status for one observed location.
- Parameters:
root (pathlib.Path)
relative_path (str)
status (str)
- Return type:
- adsfolio.pdf.catalog.file_facts_changed(previous, stat)[source]
Return whether size, modification time, or inode differ from the record.
The device number is not compared. macOS can give a volume a new device number after a restart, while every file on it stays the same. A copy or a replacement file gets a new inode.
- Parameters:
previous (collections.abc.Mapping[str, Any])
stat (os.stat_result)
- Return type:
- adsfolio.pdf.catalog.CATALOG_FILENAME = 'pdf-library.sqlite'
str(object=’’) -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to ‘utf-8’. errors defaults to ‘strict’.