kumiho.kref

Kref module for Kumiho artifact references.

This module provides the Kref class, which represents a Kumiho Artifact Reference—a URI-based unique identifier for any object in the Kumiho system.

Kref Format:

The kref URI follows this pattern:

kref://project/space/item.kind?r=REVISION&a=ARTIFACT
Components:
  • project: The project name

  • space: The space path (can be nested: space/subspace)

  • item.kind: Item name and kind separated by dot

  • ?r=REVISION: Optional revision number (default: 1)

  • &a=ARTIFACT: Optional artifact name

Examples

Item kref:

kref://film-2024/characters/hero.model

Revision kref:

kref://film-2024/characters/hero.model?r=3

Artifact kref:

kref://film-2024/characters/hero.model?r=3&a=mesh
Parsing:

parse_kref() is the one parser. It reads a kref once, with the grammar in spec/kref/README.md that kumiho-db and every Kumiho SDK share, and returns a KrefParts value. Everything that needs a piece of a kref reads it from there: the GetItem request comes from KrefParts.get_item_request(), and the Kref accessors get_item_name() and get_kind() read the same textual split. A kref’s last / ends the parent path and its last . ends the item name, so kref://p/a/b/my.file.v2.k is item my.file.v2 of kind k in /p/a/b.

The parser is total and cheap: it never raises, the textual split is cut when it is created, and the kernel’s reading (valid, error_class, revision and the rest) is computed the first time one of those attributes is read. A revision with more digits than u64::MAX has is refused without being converted to an int.

Whether a string is accepted is a separate question, answered by validate_kref() and unchanged by the parser: a kref the kernel refuses but this SDK accepts (?r=0, a 33rd segment, the legacy kref:///space spelling) is still sent, and the backend decides.

Every request is either the one the SDK sent before the structured parser (a7f155e) or resolves to the same node on kumiho-server. The server joins normalize_space_path(parent_path), /, the item name, . and the kind, and normalize_space_path trims whitespace and /. Where that would move a nested parent to a different space (a space segment that ends in whitespace, an empty trailing segment), the request keeps the shape a7f155e used: the project as the parent and everything after it as the name. The legacy kref:///s/x.k is sent as ("//s", "x", "k"), which the server normalizes to the node a7f155e’s ("/", "s/x", "k") named.

Usage:

import kumiho
from kumiho import Kref

# Parse a kref
kref = Kref("kref://project/models/hero.model?r=2&a=mesh")

# Extract components
print(kref.get_space())        # "project/models"
print(kref.get_item_name())    # "hero.model"
print(kref.get_kind())         # "model"
print(kref.get_revision())     # 2
print(kref.get_artifact_name()) # "mesh"

# Use as string
print(f"Reference: {kref}")  # Works like a string
class kumiho.kref.Kref

Bases: str

A Kumiho Artifact Reference (URI-based unique identifier).

Kref is a subclass of str, so it behaves like a string but provides utility methods for parsing and extracting components from the URI.

The kref format is:

kref://project/space/item.kind?r=REVISION&a=ARTIFACT
uri

The URI string (for backward compatibility).

Type:

str

Example:

from kumiho import Kref

# Create from string
kref = Kref("kref://my-project/assets/hero.model?r=2")

# Use as string (since Kref extends str)
print(kref)  # kref://my-project/assets/hero.model?r=2

# Parse components
print(kref.get_space())    # "my-project/assets"
print(kref.get_revision()) # 2

# Compare with strings
if kref == "kref://my-project/assets/hero.model?r=2":
    print("Match!")

Note

Since Kref is a string subclass, you can use it anywhere a string is expected. All string methods work normally.

__eq__(other)

Compare with another Kref or string.

Return type:

bool

Parameters:

other (object)

__hash__()

Return hash for use in sets and dicts.

Return type:

int

static __new__(cls, uri, *, validate=True)

Create a new Kref instance.

Parameters:
  • uri (str) – The kref URI string.

  • validate (bool) – Whether to validate the URI (default: True). Set to False for trusted internal sources.

Returns:

A Kref instance that is also a string.

Return type:

Kref

Raises:

KrefValidationError – If validate=True and the URI is invalid.

Example

>>> kref = Kref("kref://project/space/item.kind?r=1")
>>> isinstance(kref, str)
True
__repr__()

Return a developer-friendly string representation.

Return type:

str

classmethod from_pb(pb_kref)

Create a Kref from a protobuf message.

This is used for krefs received from the server, which are trusted.

Parameters:

pb_kref (Kref) – The protobuf Kref message.

Returns:

A Kref instance.

Return type:

Kref

get_artifact_name()

Extract the artifact name from the URI query string.

Returns:

The artifact name if present, None otherwise.

Return type:

Optional[str]

Example

>>> Kref("kref://project/models/hero.model?r=1&a=mesh").get_artifact_name()
'mesh'
>>> Kref("kref://project/models/hero.model?r=1").get_artifact_name()
None
get_item_name()

Extract the item name with kind from the URI.

Returns:

The item name including kind (e.g., “hero.model”).

Return type:

str

Example

>>> Kref("kref://project/models/hero.model").get_item_name()
'hero.model'
get_kind()

Extract the item kind from the URI.

Returns:

The item kind (e.g., “model”, “texture”).

Return type:

str

Example

>>> Kref("kref://project/models/hero.model").get_kind()
'model'
get_path()

Extract the path component from the URI.

Returns the part after kref:// and before any query parameters.

Returns:

The path (e.g., “project/space/item.kind”).

Return type:

str

Example

>>> Kref("kref://project/models/hero.model?r=1").get_path()
'project/models/hero.model'
get_project()

Extract the project name from the URI.

Returns the first path component (project name).

Returns:

The project name (e.g., “my-project”).

Return type:

str

Example

>>> Kref("kref://my-project/models/hero.model").get_project()
'my-project'
get_revision()

Extract the revision number from the URI query string.

Returns:

The revision number, or 1 if not specified.

Return type:

int

Example

>>> Kref("kref://project/models/hero.model?r=3").get_revision()
3
>>> Kref("kref://project/models/hero.model").get_revision()
1
get_space()

Extract the space path from the URI (without project).

Returns the path between project and item name.

Returns:

The space path (e.g., “models” or “models/characters”).

Return type:

str

Example

>>> Kref("kref://project/models/hero.model").get_space()
'models'
>>> Kref("kref://project/models/characters/hero.model").get_space()
'models/characters'
property parts: KrefParts

The kref read once by parse_kref().

Returns:

The kernel’s reading of this kref plus its textual split. parts.get_item_request() is the GetItem request for it.

Return type:

KrefParts

Example

>>> Kref("kref://project/models/hero.v2.model").parts.get_item_request()
('/project/models', 'hero.v2', 'model')
to_pb()

Convert to a protobuf Kref object.

Used internally for gRPC communication.

Returns:

A protobuf Kref message.

Return type:

kumiho_pb2.Kref

property uri: str

Get the URI string.

This property exists for backward compatibility with older code that accessed .uri directly.

Returns:

The kref URI string.

Return type:

str

class kumiho.kref.KrefParts

Bases: object

A kref read once: the textual split now, the kernel’s reading on demand.

The textual split (path, parent, leaf, leaf_name, leaf_kind) is cut when the value is created and is independent of the kernel’s verdict. It is what get_item_request() uses, so a kref this SDK passes through to the backend (for example kref://p/s/x.k?r=0) still yields its request.

The kernel’s reading (valid, error_class, base, shapes and the fields below) follows spec/kref/README.md. It is computed the first time one of those attributes is read, and never raises. A kref the kernel refuses has error_class set and no reading: base and every field are None and shapes is empty.

item_name, kind and is_project_root_item describe the first shape the base satisfies, in the order root_item, item, space, project; item_name and kind are None when that shape is a space or a project.

__init__(uri, path, parent, leaf, leaf_name, leaf_kind)
Parameters:
  • uri (str)

  • path (str)

  • parent (str | None)

  • leaf (str | None)

  • leaf_name (str | None)

  • leaf_kind (str | None)

Return type:

None

property artifact: str | None
property base: str | None

The text between the scheme and the first ?, when the kernel accepts it.

property error_class: str | None

The kernel’s refusal class, or None when it accepts the kref.

get_item_request()

The GetItem request (parent_path, item_name, kind) to send.

This is get_item_tuple(), except where kumiho-server would turn it into a different node than the request a7f155e sent for the same kref. The server rebuilds parent/name.kind after normalize_space_path, which trims whitespace and / from the parent: a space segment that ends in whitespace (kref://p/s /x.k) or an empty trailing segment (kref://p//x.k) would be moved to the space /p/s or /p. For those krefs, which only a server-returned item kref can be (the client validators refuse them), the request keeps a7f155e’s shape: the project as the parent, the text between the project and the last . as the name, and the text after it as the kind. That shape names the node the kref spells.

Raises:

ValueError – As get_item_tuple().

Return type:

Tuple[str, str, str]

get_item_tuple()

The grammar’s GetItem split (parent_path, item_name, kind).

The parent path is / plus everything before the LAST / of the path, so it holds the project and every nested space. The leaf after it is split at its LAST .: item names may contain dots, kinds never do. The query is dropped. This is the corpus field get_item_tuple; the request the client sends is get_item_request().

It depends on the text only, never on the kernel’s verdict, so a kref the backend should judge (?r=0, the legacy kref:///space/x.k spelling) is still split.

Raises:

ValueError – If the path has no / or its leaf has no .. A leaf without a dot (kref://p/s.v1/x) names a space, not an item.

Return type:

Tuple[str, str, str]

property is_project_root_item: bool | None
property item_name: str | None
property kind: str | None
property project: str | None
property revision: int | None
property shapes: Tuple[str, ...]

Every namespace the base satisfies, in resolver order.

property space_path: Tuple[str, ...] | None
property tag: str | None
property valid: bool

Whether the kumiho-db kernel accepts this kref.

uri: str
path: str
parent: str | None
leaf: str | None
leaf_name: str | None
leaf_kind: str | None
exception kumiho.kref.KrefValidationError

Bases: ValueError

Raised when a Kref URI is invalid or contains malicious patterns.

kumiho.kref.is_valid_kref(uri)

Check if a Kref URI is valid without raising exceptions.

Parameters:

uri (str) – The kref URI to validate.

Return type:

bool

Returns:

True if the URI is valid, False otherwise.

Example:

from kumiho.kref import is_valid_kref

if is_valid_kref("kref://project/space/item.kind"):
    print("Valid!")
kumiho.kref.parse_kref(uri)

Parse uri once into a KrefParts.

Never raises: a string the kernel refuses comes back with error_class set (one of scheme, fragment_or_percent, tag_reserved_char, path, query_pair, unknown_key, duplicate_key, r_and_t, revision_number, tag, artifact). The kernel’s reading is computed lazily, the first time one of its attributes is read.

Example:

>>> parts = parse_kref("kref://p/a/b/my.file.k?r=2")
>>> parts.get_item_request()
('/p/a/b', 'my.file', 'k')
>>> parts.revision
2
Return type:

KrefParts

Parameters:

uri (str)

kumiho.kref.validate_kref(uri)

Validate a Kref URI for security and correctness.

Checks for: - Proper kref:// scheme - No path traversal patterns (..) - No control characters - Valid path segment format

Parameters:

uri (str) – The kref URI to validate.

Raises:

KrefValidationError – If the URI is invalid or contains malicious patterns.

Return type:

None

Example:

from kumiho.kref import validate_kref, KrefValidationError

try:
    validate_kref("kref://project/space/item.kind?r=1")
except KrefValidationError as e:
    print(f"Invalid kref: {e}")