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 namespace: 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 inspec/kref/README.mdthat kumiho-db and every Kumiho SDK share, and returns aKrefPartsvalue. Everything that needs a piece of a kref reads it from there: theGetItemrequest comes fromKrefParts.get_item_request(), and theKrefaccessorsget_item_name()andget_kind()read the same textual split. A kref’s last/ends the parent path and its last.ends the item name, sokref://p/a/b/my.file.v2.kis itemmy.file.v2of kindkin/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,revisionand the rest) is computed the first time one of those attributes is read. A revision with more digits thanu64::MAXhas is refused without being converted to anint.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 legacykref:///spacespelling) 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, andnormalize_space_pathtrims 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 legacykref:///s/x.kis 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:
strA 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:
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.
- __hash__()
Return hash for use in sets and dicts.
- Return type:
- static __new__(cls, uri, *, validate=True)
Create a new Kref instance.
- Parameters:
- Returns:
A Kref instance that is also a string.
- Return type:
- 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:
- 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:
- 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:
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:
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:
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:
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:
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:
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 theGetItemrequest for it.- Return type:
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
- class kumiho.kref.KrefParts
Bases:
objectA 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 whatget_item_request()uses, so a kref this SDK passes through to the backend (for examplekref://p/s/x.k?r=0) still yields its request.The kernel’s reading (
valid,error_class,base,shapesand the fields below) followsspec/kref/README.md. It is computed the first time one of those attributes is read, and never raises. A kref the kernel refuses haserror_classset and no reading:baseand every field areNoneandshapesis empty.item_name,kindandis_project_root_itemdescribe the first shape the base satisfies, in the orderroot_item,item,space,project;item_nameandkindareNonewhen that shape is a space or a project.- __init__(uri, path, parent, leaf, leaf_name, leaf_kind)
- get_item_request()
The
GetItemrequest(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 rebuildsparent/name.kindafternormalize_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/sor/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:
- get_item_tuple()
The grammar’s
GetItemsplit(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 fieldget_item_tuple; the request the client sends isget_item_request().It depends on the text only, never on the kernel’s verdict, so a kref the backend should judge (
?r=0, the legacykref:///space/x.kspelling) 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:
- property valid: bool
Whether the kumiho-db kernel accepts this kref.
- uri: str
- path: str
- exception kumiho.kref.KrefValidationError
Bases:
ValueErrorRaised 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:
- 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
urionce into aKrefParts.Never raises: a string the kernel refuses comes back with
error_classset (one ofscheme,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
- 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:
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}")