Skip to content

ontocast.onto.tenancy

Tenant/project naming helpers for triple-store datasets and vector collections.

Naming convention (separator default --)::

{tenant}{sep}{project}{sep}facts
{tenant}{sep}{project}{sep}ontologies
{tenant}{sep}{project}{sep}shapes

The shapes partition is a triple-store dataset only: it has no vector-store counterpart, because SHACL shapes are never retrieved by similarity.

Runtime tenant and project are taken from CLI flags or HTTP request parameters only (not from environment variables). :data:DEFAULT_TENANT / :data:DEFAULT_PROJECT are used when a parameter is omitted and for deriving initial Fuseki/Qdrant names in configuration.

TenancyScope

Bases: BaseModel

A tenant/project partition and the backend names it resolves to.

Frozen: a scope identifies a ToolBox in the registry, and a mutable key would let a rename silently point two scopes at the same entry.

Source code in ontocast/onto/tenancy.py
class TenancyScope(BaseModel):
    """A tenant/project partition and the backend names it resolves to.

    Frozen: a scope identifies a ToolBox in the registry, and a mutable key
    would let a rename silently point two scopes at the same entry.
    """

    model_config = ConfigDict(frozen=True)

    tenant: str
    project: str
    facts_name: str
    ontologies_name: str
    shapes_name: str

    @classmethod
    def build(
        cls, tenant: str, project: str, *, sep: str = TENANCY_SEP
    ) -> "TenancyScope":
        """Resolve a tenant/project pair to its backend names.

        Args:
            tenant: Tenant identifier.
            project: Project identifier within the tenant.
            sep: Separator used in derived names.

        Returns:
            The resolved scope.

        Raises:
            ValueError: If either identifier is blank.
        """
        t, p = tenant.strip(), project.strip()
        if not t or not p:
            raise ValueError("tenant and project must be non-empty")
        return cls(
            tenant=t,
            project=p,
            facts_name=tenant_project_facts_name(t, p, sep=sep),
            ontologies_name=tenant_project_ontologies_name(t, p, sep=sep),
            shapes_name=tenant_project_shapes_name(t, p, sep=sep),
        )

    @property
    def key(self) -> tuple[str, str]:
        """Registry key for this scope."""
        return (self.tenant, self.project)

key property

Registry key for this scope.

build(tenant, project, *, sep=TENANCY_SEP) classmethod

Resolve a tenant/project pair to its backend names.

Parameters:

Name Type Description Default
tenant str

Tenant identifier.

required
project str

Project identifier within the tenant.

required
sep str

Separator used in derived names.

TENANCY_SEP

Returns:

Type Description
'TenancyScope'

The resolved scope.

Raises:

Type Description
ValueError

If either identifier is blank.

Source code in ontocast/onto/tenancy.py
@classmethod
def build(
    cls, tenant: str, project: str, *, sep: str = TENANCY_SEP
) -> "TenancyScope":
    """Resolve a tenant/project pair to its backend names.

    Args:
        tenant: Tenant identifier.
        project: Project identifier within the tenant.
        sep: Separator used in derived names.

    Returns:
        The resolved scope.

    Raises:
        ValueError: If either identifier is blank.
    """
    t, p = tenant.strip(), project.strip()
    if not t or not p:
        raise ValueError("tenant and project must be non-empty")
    return cls(
        tenant=t,
        project=p,
        facts_name=tenant_project_facts_name(t, p, sep=sep),
        ontologies_name=tenant_project_ontologies_name(t, p, sep=sep),
        shapes_name=tenant_project_shapes_name(t, p, sep=sep),
    )

tenant_project_facts_name(tenant, project, *, sep=TENANCY_SEP)

Facts dataset (Fuseki) or facts collection (Qdrant).

Source code in ontocast/onto/tenancy.py
def tenant_project_facts_name(
    tenant: str, project: str, *, sep: str = TENANCY_SEP
) -> str:
    """Facts dataset (Fuseki) or facts collection (Qdrant)."""
    return tenant_project_store_name(tenant, project, "facts", sep=sep)

tenant_project_ontologies_name(tenant, project, *, sep=TENANCY_SEP)

Ontologies dataset (Fuseki) or ontologies collection (Qdrant).

Source code in ontocast/onto/tenancy.py
def tenant_project_ontologies_name(
    tenant: str, project: str, *, sep: str = TENANCY_SEP
) -> str:
    """Ontologies dataset (Fuseki) or ontologies collection (Qdrant)."""
    return tenant_project_store_name(tenant, project, "ontologies", sep=sep)

tenant_project_shapes_name(tenant, project, *, sep=TENANCY_SEP)

SHACL shapes dataset (Fuseki or in-memory partition).

Shapes are kept out of the ontologies dataset on purpose: a shapes document declares its own owl:Ontology header, and catalog discovery selects every named graph that carries one. Co-located shapes would register as catalog ontologies and be offered to the renderer as schema.

Source code in ontocast/onto/tenancy.py
def tenant_project_shapes_name(
    tenant: str, project: str, *, sep: str = TENANCY_SEP
) -> str:
    """SHACL shapes dataset (Fuseki or in-memory partition).

    Shapes are kept out of the ontologies dataset on purpose: a shapes document
    declares its own ``owl:Ontology`` header, and catalog discovery selects every
    named graph that carries one. Co-located shapes would register as catalog
    ontologies and be offered to the renderer as schema.
    """
    return tenant_project_store_name(tenant, project, "shapes", sep=sep)

tenant_project_store_name(tenant, project, kind, *, sep=TENANCY_SEP)

Return Fuseki dataset or Qdrant collection name for the given kind.

Source code in ontocast/onto/tenancy.py
def tenant_project_store_name(
    tenant: str,
    project: str,
    kind: StoreKind,
    *,
    sep: str = TENANCY_SEP,
) -> str:
    """Return Fuseki dataset or Qdrant collection name for the given kind."""
    t = tenant.strip()
    p = project.strip()
    if not t or not p:
        raise ValueError("tenant and project must be non-empty")
    return f"{t}{sep}{p}{sep}{kind}"