Skip to content

Store

Store

Bases: Store[Dataset, StatementEntity]

Feature add-ons to nomenklatura.store.Store

Source code in ftmq/store/base.py
class Store(nk.Store[Dataset, StatementEntity]):
    """
    Feature add-ons to `nomenklatura.store.Store`
    """

    def __init__(
        self,
        dataset: Dataset | str | None = None,
        linker: Resolver | None = None,
        **kwargs,
    ) -> None:
        """
        Initialize a store. This should be called via
        [`get_store`][ftmq.store.get_store]

        Args:
            dataset: A `followthemoney.Dataset` instance to limit the scope to
            linker: A `nomenklatura.Resolver` instance with linked / deduped data
        """
        # An unscoped store (no explicit `dataset`) implicitly spans every
        # dataset present in the backend. nomenklatura scopes a view to
        # `dataset.leaf_names`, so without this the store would only surface
        # entities literally tagged `dataset="default"`. Resolved lazily (see
        # `scope`) so opening a store never queries the backend.
        self._implicit_scope = dataset is None
        linker = linker or get_resolver(kwargs.get("uri"))
        super().__init__(dataset=ensure_dataset(dataset), linker=linker, **kwargs)

    def get_scope(self) -> Dataset:
        """
        Return implicit `Dataset` computed from current datasets in store
        """
        raise NotImplementedError

    @property
    def scope(self) -> Dataset:
        """The effective read scope: the store's explicit `dataset`, or all
        datasets present in the backend when it was opened without one."""
        return self.get_scope() if self._implicit_scope else self.dataset

    def view(self, scope: Dataset | None = None, external: bool = False) -> "View":
        raise NotImplementedError

    def default_view(self, external: bool = False) -> "View":
        return self.view(self.scope, external)

    def iterate(self, dataset: str | Dataset | None = None) -> StatementEntities:
        """
        Iterate all the entities, optional filter for a dataset.

        Args:
            dataset: `Dataset` instance or name to limit scope to

        Yields:
            Generator of `nomenklatura.entity.CompositeEntity`
        """
        if dataset is not None:
            view = self.view(ensure_dataset(dataset))
        else:
            view = self.default_view()
        yield from view.entities()

scope property

The effective read scope: the store's explicit dataset, or all datasets present in the backend when it was opened without one.

__init__(dataset=None, linker=None, **kwargs)

Initialize a store. This should be called via get_store

Parameters:

Name Type Description Default
dataset Dataset | str | None

A followthemoney.Dataset instance to limit the scope to

None
linker Resolver | None

A nomenklatura.Resolver instance with linked / deduped data

None
Source code in ftmq/store/base.py
def __init__(
    self,
    dataset: Dataset | str | None = None,
    linker: Resolver | None = None,
    **kwargs,
) -> None:
    """
    Initialize a store. This should be called via
    [`get_store`][ftmq.store.get_store]

    Args:
        dataset: A `followthemoney.Dataset` instance to limit the scope to
        linker: A `nomenklatura.Resolver` instance with linked / deduped data
    """
    # An unscoped store (no explicit `dataset`) implicitly spans every
    # dataset present in the backend. nomenklatura scopes a view to
    # `dataset.leaf_names`, so without this the store would only surface
    # entities literally tagged `dataset="default"`. Resolved lazily (see
    # `scope`) so opening a store never queries the backend.
    self._implicit_scope = dataset is None
    linker = linker or get_resolver(kwargs.get("uri"))
    super().__init__(dataset=ensure_dataset(dataset), linker=linker, **kwargs)

get_scope()

Return implicit Dataset computed from current datasets in store

Source code in ftmq/store/base.py
def get_scope(self) -> Dataset:
    """
    Return implicit `Dataset` computed from current datasets in store
    """
    raise NotImplementedError

iterate(dataset=None)

Iterate all the entities, optional filter for a dataset.

Parameters:

Name Type Description Default
dataset str | Dataset | None

Dataset instance or name to limit scope to

None

Yields:

Type Description
StatementEntities

Generator of nomenklatura.entity.CompositeEntity

Source code in ftmq/store/base.py
def iterate(self, dataset: str | Dataset | None = None) -> StatementEntities:
    """
    Iterate all the entities, optional filter for a dataset.

    Args:
        dataset: `Dataset` instance or name to limit scope to

    Yields:
        Generator of `nomenklatura.entity.CompositeEntity`
    """
    if dataset is not None:
        view = self.view(ensure_dataset(dataset))
    else:
        view = self.default_view()
    yield from view.entities()

View

Bases: View[Dataset, StatementEntity]

Feature add-ons to nomenklatura.store.base.View

Source code in ftmq/store/base.py
class View(nk.View[Dataset, StatementEntity]):
    """
    Feature add-ons to `nomenklatura.store.base.View`
    """

    def query(self, query: Query | None = None) -> StatementEntities:
        """
        Get the entities of a store, optionally filtered by a
        [`Query`][ftmq.Query] object.

        Args:
            query: The Query filter object

        Yields:
            Generator of `followthemoney.StatementEntity`
        """
        view = self.store.view(self.scope)
        if query:
            yield from query.apply_iter(view.entities())
        else:
            yield from view.entities()

    def get_adjacents(
        self, proxies: Iterable[StatementEntity], inverted: bool | None = False
    ) -> set[StatementEntity]:
        seen: set[StatementEntity] = set()
        for proxy in proxies:
            for _, adjacent in self.get_adjacent(proxy, inverted=bool(inverted)):
                if adjacent.id not in seen:
                    seen.add(adjacent)
        return seen

    def stats(self, query: Query | None = None) -> DatasetStats:
        c = Collector()
        cov = c.collect_many(self.query(query))
        return cov

    def count(self, query: Query | None = None) -> int:
        return self.stats(query).entity_count or 0

    def aggregations(self, query: Query) -> AggregatorResult | None:
        if not query.aggregations:
            return
        _ = [x for x in self.query(query)]
        if query.aggregator:
            res = dict(query.aggregator.result)
            return res

query(query=None)

Get the entities of a store, optionally filtered by a Query object.

Parameters:

Name Type Description Default
query Query | None

The Query filter object

None

Yields:

Type Description
StatementEntities

Generator of followthemoney.StatementEntity

Source code in ftmq/store/base.py
def query(self, query: Query | None = None) -> StatementEntities:
    """
    Get the entities of a store, optionally filtered by a
    [`Query`][ftmq.Query] object.

    Args:
        query: The Query filter object

    Yields:
        Generator of `followthemoney.StatementEntity`
    """
    view = self.store.view(self.scope)
    if query:
        yield from query.apply_iter(view.entities())
    else:
        yield from view.entities()