Skip to content

Commit

Permalink
restructure collections, user sessions and fix cyclical dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
jfeodor committed Nov 25, 2024
1 parent 8a5ebf5 commit f4b084c
Show file tree
Hide file tree
Showing 59 changed files with 487 additions and 469 deletions.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ where = ["python/src"]
[tool.ruff]
src = ["python/src"]
exclude = [
"./python/src/numerous/generated/",
"./python/src/numerous/_client/graphql",
"./setup.py",
"./python/docs",
"./examples",
Expand Down Expand Up @@ -90,7 +90,7 @@ mark-parentheses = false
schema_path = "../shared/schema.gql"
queries_path = "queries.gql"
target_package_name = "graphql"
target_package_path = "src/numerous/generated"
target_package_path = "src/numerous/_client"

[tool.mypy]
ignore_missing_imports = true
Expand Down
4 changes: 0 additions & 4 deletions python/src/numerous/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
"""The python SDK for numerous."""

__all__ = ("collection",)

from .collection import collection
6 changes: 6 additions & 0 deletions python/src/numerous/_client/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class ParentCollectionNotFoundError(Exception):
_msg = "Parent collection not found"

def __init__(self, collection_id: str) -> None:
self.collection_id = collection_id
super().__init__(self._msg)
Original file line number Diff line number Diff line change
Expand Up @@ -3,61 +3,38 @@
import json
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import TYPE_CHECKING, Any, BinaryIO
from typing import Any, BinaryIO

from numerous.collection.file_reference import FileReference
from numerous.generated.graphql.fragments import (
from numerous._utils.jsonbase64 import base64_to_dict, dict_to_base64
from numerous.collections._client import (
CollectionDocumentReference,
CollectionDocumentReferenceTags,
CollectionFileReferenceTags,
CollectionReference,
CollectionFileIdentifier,
CollectionIdentifier,
Tag,
)
from numerous.jsonbase64 import base64_to_dict, dict_to_base64


if TYPE_CHECKING:
from numerous.generated.graphql.input_types import TagInput
def _parse_tag(tag: dict[str, Any]) -> Tag:
key = tag.get("key")
if not isinstance(key, str):
tname = type(key).__name__
msg = f"FileSystemCollectionTag key must be str, found {tname}"
raise TypeError(msg)

value = tag.get("value")
if not isinstance(value, str):
tname = type(value).__name__
msg = f"FileSystemCollectionTag value must be str, found {tname}"
raise TypeError(msg)

@dataclass
class FileSystemCollectionTag:
key: str
value: str

@staticmethod
def load(tag: dict[str, Any]) -> FileSystemCollectionTag:
key = tag.get("key")
if not isinstance(key, str):
tname = type(key).__name__
msg = f"FileSystemCollectionTag key must be str, found {tname}"
raise TypeError(msg)

value = tag.get("value")
if not isinstance(value, str):
tname = type(value).__name__
msg = f"FileSystemCollectionTag value must be str, found {tname}"
raise TypeError(msg)

return FileSystemCollectionTag(key=key, value=value)

def to_file_reference_tag(self) -> CollectionFileReferenceTags:
return CollectionFileReferenceTags(
key=self.key,
value=self.value,
)

def to_document_reference_tag(self) -> CollectionDocumentReferenceTags:
return CollectionDocumentReferenceTags(
key=self.key,
value=self.value,
)
return Tag(key=key, value=value)


@dataclass
class FileSystemFileMetadata:
file_id: str
file_key: str
tags: list[FileSystemCollectionTag]
tags: list[Tag]

def save(self, path: Path) -> None:
def convert_to_serializable(obj: Path) -> str:
Expand Down Expand Up @@ -99,16 +76,13 @@ def load(file_path: Path) -> FileSystemFileMetadata:
return FileSystemFileMetadata(
file_id=file_id,
file_key=file_key,
tags=[FileSystemCollectionTag.load(tag) for tag in tags],
tags=[_parse_tag(tag) for tag in tags],
)

def reference_tags(self) -> list[CollectionFileReferenceTags]:
return [
CollectionFileReferenceTags(key=tag.key, value=tag.value)
for tag in self.tags
]
def reference_tags(self) -> list[Tag]:
return [Tag(key=tag.key, value=tag.value) for tag in self.tags]

def tag_matches(self, tag_input: TagInput) -> bool:
def tag_matches(self, tag_input: Tag) -> bool:
matching_tag = next(
(
tag
Expand All @@ -124,7 +98,7 @@ def tag_matches(self, tag_input: TagInput) -> bool:
@dataclass
class FileSystemCollectionDocument:
data: dict[str, Any]
tags: list[FileSystemCollectionTag]
tags: list[Tag]

def save(self, path: Path) -> None:
with path.open("w") as f:
Expand Down Expand Up @@ -153,19 +127,13 @@ def load(path: Path) -> FileSystemCollectionDocument:
raise TypeError(msg)

return FileSystemCollectionDocument(
data=data, tags=[FileSystemCollectionTag.load(tag) for tag in tags]
data=data, tags=[_parse_tag(tag) for tag in tags]
)

def reference_tags(self) -> list[CollectionDocumentReferenceTags]:
return [
CollectionDocumentReferenceTags(
key=tag.key,
value=tag.value,
)
for tag in self.tags
]
def reference_tags(self) -> list[Tag]:
return [Tag(key=tag.key, value=tag.value) for tag in self.tags]

def tag_matches(self, tag_input: TagInput) -> bool:
def tag_matches(self, tag_input: Tag) -> bool:
matching_tag = next(
(
tag
Expand Down Expand Up @@ -227,7 +195,7 @@ def _document_path_from_id(self, document_id: str) -> Path:

def get_collection_reference(
self, collection_key: str, parent_collection_id: str | None = None
) -> CollectionReference:
) -> CollectionIdentifier:
collection_relpath = (
Path(parent_collection_id) / collection_key
if parent_collection_id is not None
Expand All @@ -236,7 +204,7 @@ def get_collection_reference(
collection_id = str(collection_relpath)
collection_path = self._base_path / collection_relpath
collection_path.mkdir(parents=True, exist_ok=True)
return CollectionReference(id=collection_id, key=collection_key)
return CollectionIdentifier(id=collection_id, key=collection_key)

def get_collection_document(
self, collection_id: str, document_key: str
Expand All @@ -252,7 +220,7 @@ def get_collection_document(
id=doc_id,
key=document_key,
data=dict_to_base64(doc.data),
tags=[tag.to_document_reference_tag() for tag in doc.tags],
tags=doc.tags,
)

def set_collection_document(
Expand Down Expand Up @@ -294,14 +262,14 @@ def delete_collection_document(
)

def add_collection_document_tag(
self, document_id: str, tag: TagInput
self, document_id: str, tag: Tag
) -> CollectionDocumentReference | None:
doc_path = self._document_path_from_id(document_id)
if not doc_path.exists():
return None

doc = FileSystemCollectionDocument.load(doc_path)
doc.tags.append(FileSystemCollectionTag(key=tag.key, value=tag.value))
doc.tags.append(Tag(key=tag.key, value=tag.value))
doc.save(doc_path)

return CollectionDocumentReference(
Expand Down Expand Up @@ -333,7 +301,7 @@ def get_collection_documents(
self,
collection_id: str,
end_cursor: str, # noqa: ARG002
tag_input: TagInput | None,
tag_input: Tag | None,
) -> tuple[list[CollectionDocumentReference | None], bool, str]:
col_path = self._base_path / collection_id
if not col_path.exists():
Expand Down Expand Up @@ -368,7 +336,7 @@ def get_collection_documents(

def create_collection_file_reference(
self, collection_id: str, file_key: str
) -> FileReference | None:
) -> CollectionFileIdentifier | None:
meta_path = self._file_metadata_path(collection_id, file_key)
if meta_path.exists():
meta = FileSystemFileMetadata.load(meta_path)
Expand All @@ -379,11 +347,7 @@ def create_collection_file_reference(
meta = FileSystemFileMetadata(file_id=file_id, file_key=file_key, tags=[])
meta.save(self._file_metadata_path(collection_id, file_key))

return FileReference(
client=self,
file_id=meta.file_id,
key=file_key,
)
return CollectionFileIdentifier(id=meta.file_id, key=file_key)

def collection_file_tags(self, file_id: str) -> dict[str, str] | None:
try:
Expand Down Expand Up @@ -420,13 +384,13 @@ def get_collection_files(
self,
collection_id: str,
end_cursor: str, # noqa: ARG002
tag_input: TagInput | None,
) -> tuple[list[FileReference], bool, str]:
tag_input: Tag | None,
) -> tuple[list[CollectionFileIdentifier], bool, str]:
col_path = self._base_path / collection_id
if not col_path.exists():
return [], False, ""

files: list[FileReference] = []
files: list[CollectionFileIdentifier] = []
for file_path in col_path.iterdir():
if not file_path.name.endswith(".file.meta.json"):
continue
Expand All @@ -437,13 +401,11 @@ def get_collection_files(
# skips files that do not match tag input, if it is given
continue

files.append(
FileReference(client=self, file_id=meta.file_id, key=meta.file_key)
)
files.append(CollectionFileIdentifier(id=meta.file_id, key=meta.file_key))

return files, False, ""

def add_collection_file_tag(self, file_id: str, tag: TagInput) -> None:
def add_collection_file_tag(self, file_id: str, tag: Tag) -> None:
index_entry = self._file_index_entry(file_id)
meta_path = self._file_metadata_path(
index_entry.collection_id, index_entry.file_key
Expand All @@ -453,7 +415,7 @@ def add_collection_file_tag(self, file_id: str, tag: TagInput) -> None:

meta = FileSystemFileMetadata.load(meta_path)
if not meta.tag_matches(tag):
meta.tags.append(FileSystemCollectionTag(key=tag.key, value=tag.value))
meta.tags.append(Tag(key=tag.key, value=tag.value))
meta.save(meta_path)

def delete_collection_file_tag(self, file_id: str, tag_key: str) -> None:
Expand All @@ -472,16 +434,16 @@ def get_collection_collections(
self,
collection_key: str,
end_cursor: str, # noqa: ARG002
) -> tuple[list[CollectionReference], bool, str]:
) -> tuple[list[CollectionIdentifier], bool, str]:
col_path = self._base_path / collection_key
if not col_path.exists():
return [], False, ""

collections: list[CollectionReference] = []
collections: list[CollectionIdentifier] = []
for item in col_path.iterdir():
if item.is_dir():
col_id = str(item.relative_to(self._base_path))
collections.append(CollectionReference(id=col_id, key=item.name))
collections.append(CollectionIdentifier(id=col_id, key=item.name))

return sorted(collections, key=lambda c: c.id), False, ""

Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
from __future__ import annotations

import os
import typing
from pathlib import Path
from typing import Optional

from numerous.collection._client import Client
from numerous.generated.graphql.client import Client as GQLClient
from .fs_client import FileSystemClient
from .graphql.client import Client as GQLClient
from .graphql_client import GraphQLClient

from ._fs_client import FileSystemClient
from ._graphql_client import GraphQLClient

if typing.TYPE_CHECKING:
from numerous.collections._client import Client

_client: Optional[Client] = None
_client: Client | None = None


def get_client() -> Client:
Expand Down
Loading

0 comments on commit f4b084c

Please sign in to comment.