trove/trovedb/trove.py

149 lines
3.9 KiB
Python
Raw Permalink Normal View History

from typing import Protocol, runtime_checkable, Optional, Dict, List, Self, NamedTuple, Iterable, TypedDict, Iterator
from uuid import UUID
import datetime as dt
import errno
2026-03-21 22:25:32 -05:00
type ObjectId = int | str | UUID
2026-03-21 22:25:32 -05:00
class TroveError(Exception):
"""Base class for all Trove errors."""
class ErrorWithErrno(TroveError):
"""Raised when an error occurs with an errno."""
def __init__(self, error: int, *args):
super().__init__(*args)
self.errno = error
class ErrorExists(ErrorWithErrno):
"""Raised when a note already exists."""
def __init__(self, *args):
super().__init__(errno.EEXIST, *args)
class ErrorNotFound(ErrorWithErrno):
"""Raised when a note is not found."""
def __init__(self, *args):
super().__init__(errno.ENOENT, *args)
class ErrorNotEmpty(ErrorWithErrno):
"""Raised when a directory is not empty."""
def __init__(self, *args):
super().__init__(errno.ENOTEMPTY, *args)
2026-03-28 13:25:25 -05:00
class ErrorBadType(TypeError):
"""Raised when an invalid type is encountered."""
...
2026-03-19 22:43:11 -05:00
class BadNoteType(TypeError):
"""Raised when an invalid note type is encountered."""
2026-03-21 22:25:32 -05:00
class TreeExists(RuntimeError):
"""Raised when a label already exists."""
class NoteNotFound(KeyError):
"""Raised when a note is not found."""
2026-03-19 22:43:11 -05:00
2026-03-21 22:25:32 -05:00
class OpenArguments(TypedDict):
create: bool
class TreeEntry(NamedTuple):
name: str
object_id: ObjectId
DEFAULT_MIME = "application/octet-stream"
@runtime_checkable
class Note(Protocol):
"""
Protocol for a Note item.
Represents access to an individual note's content and metadata.
"""
@property
def object_id(self) -> ObjectId:
"""The unique identifier for this note."""
...
@property
def mime(self) -> str:
"""The MIME type of the note's content."""
...
@property
def readonly(self) -> bool:
"""Whether the note is read-only."""
...
@property
def mtime(self) -> dt.datetime:
"""The last modification time of the note."""
...
def get_raw_metadata(self, key: str) -> Optional[bytes]:
"""Retrieve metadata value for the given key."""
...
def set_raw_metadata(self, key: str, value: bytes) -> None:
"""Set metadata value for the given key."""
...
def read_content(self) -> bytes:
"""Read the raw content of the note."""
...
def write_content(self, data:bytes) -> None:
"""Write the raw content of the note."""
...
def children(self) -> Iterator[TreeEntry]:
"""Get all children of this note."""
...
def child(self, name: str) -> 'Note':
"""Retrieve a child note by name."""
...
def new_child(self, name: str, mime: str, content: bytes | None, executable: bool, hidden: bool) -> 'Note':
"""Create a new child note."""
...
def rm_child(self, name: str, recurse: bool):
"""Remove a child note."""
...
def has_children(self) -> bool:
"""Check if note has children."""
return next(self.children(), None) is not None
def new_child(note: Note, name: str, mime: str = DEFAULT_MIME, content: bytes | None = None, executable: bool = False, hidden: bool = False) -> Note:
return note.new_child(name=name, mime=mime, content=content, executable=executable, hidden=hidden)
@runtime_checkable
class Trove(Protocol):
"""
Protocol for the Trove database API.
Provides high-level access to notes and trees.
"""
def get_raw_note(self, note: ObjectId) -> Note:
"""Retrieve a note by a object id"""
...
2026-03-28 13:25:25 -05:00
def move(self, src_parent: Note, src_name: str, dst_parent: Note, dst_name: str, overwrite: bool):
"""Move a child note to a new location."""
...
def create_blob(self, data: bytes | None = None) -> Note:
"""Create a new blob node at the given path with content"""
...
def get_root(self) -> Note:
"""Get Tree Node at the given path"""
...