Source code for flpq_data.dataset.registry
"""Per-graph registry and the network-free metadata API."""
import json
import pathlib
from dataclasses import dataclass
from functools import lru_cache
__all__ = [
"GraphInfo",
"QueryInfo",
"graph_names",
"graph_info",
"categories",
]
#: The per-graph registry bundled with the package (the current dataset
#: version; see the "Graph registry" section of ``docs/flpq.rst``).
REGISTRY_JSON = pathlib.Path(__file__).parent / "registry.json"
@lru_cache(maxsize=1)
def _load_registry() -> dict:
"""Loads (and caches) the bundled registry JSON."""
return json.loads(REGISTRY_JSON.read_text(encoding="utf-8"))
[docs]
@dataclass(frozen=True)
class QueryInfo:
"""One query of a graph (a ``queries/`` dir of its archive).
Attributes
----------
query_class : str
The query class (``cfpq``, ``rpq``, or ``mcfpq``).
name : str
The query name (the directory name under ``queries/<class>/``).
representations : tuple[str, ...]
The representation formats present for the query (e.g.
``("cnf", "rsm")``), sorted.
"""
query_class: str
name: str
representations: tuple[str, ...]
[docs]
@dataclass(frozen=True)
class GraphInfo:
"""The registry record of one graph.
Attributes
----------
name : str
The graph name (the archive is ``<name>.tar.gz``).
category : str
The dataset category the graph belongs to.
num_nodes : int
The number of vertices (the declared MTX dimension).
num_edges : int
The number of stored edges (the sum of the MTX nnz).
size_mb : float
The archive size in MB (three decimals).
sha256 : str
The sha256 hex digest of the ``<name>.tar.gz`` archive.
queries : tuple[QueryInfo, ...]
The queries shipped with the graph, sorted by (class, name).
"""
name: str
category: str
num_nodes: int
num_edges: int
size_mb: float
sha256: str
queries: tuple[QueryInfo, ...]
def _to_graph_info(name: str, record: dict) -> GraphInfo:
"""Maps one registry JSON record to a :class:`GraphInfo`."""
return GraphInfo(
name=name,
category=record["category"],
num_nodes=record["num_nodes"],
num_edges=record["num_edges"],
size_mb=record["size_mb"],
sha256=record["sha256"],
queries=tuple(
QueryInfo(
query_class=query["class"],
name=query["name"],
representations=tuple(query["representations"]),
)
for query in record["queries"]
),
)
[docs]
def graph_names() -> list[str]:
"""Returns the names of all downloadable graphs, sorted.
Examples
--------
>>> from flpq_data import *
>>> len(graph_names())
113
>>> graph_names()[0]
'airflow'
Returns
-------
names : list[str]
The graph names of the current dataset version.
"""
return sorted(_load_registry()["graphs"])
[docs]
def graph_info(name: str) -> GraphInfo:
"""Returns the registry record of one graph.
Parameters
----------
name : str
The graph name (see :func:`graph_names`).
Examples
--------
>>> from flpq_data import *
>>> info = graph_info("skos")
>>> info.category, info.num_nodes, info.num_edges
('rdf', 144, 252)
Returns
-------
info : GraphInfo
The metadata of the graph.
Raises
------
FileNotFoundError
If no graph with this name exists in the dataset.
"""
records = _load_registry()["graphs"]
if name not in records:
raise FileNotFoundError(f"No graph with {name=} found")
return _to_graph_info(name, records[name])
[docs]
def categories() -> dict[str, list[str]]:
"""Returns the dataset categories mapped to their graph names.
Examples
--------
>>> from flpq_data import *
>>> "skos" in categories()["rdf"]
True
Returns
-------
mapping : dict[str, list[str]]
Category -> sorted graph names; categories in sorted order.
"""
records = _load_registry()["graphs"]
by_category: dict[str, list[str]] = {}
for name in sorted(records):
by_category.setdefault(records[name]["category"], []).append(name)
return {category: by_category[category] for category in sorted(by_category)}