Source code for compass.pipeline.collection.dedupe

"""Document deduplication for collected artifacts"""

import logging
from collections import UserDict
from dataclasses import dataclass

from elm.web.document import BaseDocument


logger = logging.getLogger(__name__)


@dataclass
class _DocInfo:
    """Information about a collected document"""

    doc: BaseDocument
    from_steps: list[str]

    def add_step(self, step_name: str | None):
        """Add a collection step to the provenance of this document"""
        if step_name and step_name not in self.from_steps:
            self.from_steps.append(step_name)

    @classmethod
    def from_doc(cls, doc: BaseDocument):
        """Create a new _DocInfo from a document"""
        return cls(doc=doc, from_steps=list(doc.attrs.get("from_steps", [])))


[docs] class DocumentDeDuplicator(UserDict): """Domain Service for deduplicating collected documents"""
[docs] def add_docs(self, docs, *, step_name=None): """Add documents to the collection mapping Parameters ---------- docs : list Collected document objects to add to the internal de-duplicated mapping. step_name : str, optional Identifier for the collection step that produced the documents. If not provided, "from_steps" will not be updated for the added documents. By default, ``None``. """ if not docs: if step_name: logger.debug("No docs found to add for step %r", step_name) return logger.debug("Adding %d doc(s) to collection", len(docs)) for doc in docs: key = _collection_doc_key(doc.attrs) doc_info = self.data.setdefault(key, _DocInfo.from_doc(doc)) doc_info.add_step(step_name)
[docs] def info(self, doc): """Get the info for a given document Parameters ---------- doc : BaseDocument The document for which to retrieve the deduplication info. Returns ------- object The deduplication info for the given document. """ return self.data.get( _collection_doc_key(doc.attrs), _DocInfo(doc=doc, from_steps=[]) )
def _collection_doc_key(doc_info): """Build the deduplication key for a collected document""" try: return str(doc_info["checksum"]) except KeyError: return str( doc_info.get("checksum") or doc_info.get("source_fp") or doc_info.get("source") or doc_info.get("cache_fn") or id(doc_info) )