Skip to content

Commit

Permalink
Initial working Custom List Store + typos
Browse files Browse the repository at this point in the history
  • Loading branch information
sei-aderr committed Dec 20, 2024
1 parent de9e66a commit c415b42
Show file tree
Hide file tree
Showing 14 changed files with 276 additions and 8 deletions.
10 changes: 9 additions & 1 deletion mlte/backend/core/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from mlte.store.catalog.catalog_group import CatalogStoreGroup
from mlte.store.catalog.store import CatalogStore
from mlte.store.user.store import UserStore
from mlte.store.custom_list.store import CustomListStore


class State:
Expand All @@ -30,6 +31,9 @@ def reset(self):
self._catalog_stores: CatalogStoreGroup = CatalogStoreGroup()
"""The list of catalog store instances maintained by the state object."""

self._custom_list_store: Optional[CustomListStore] = None
"""The custom list store instance maintained by the state object."""

self._jwt_secret_key: str = ""
"""Secret key used to sign authentication tokens."""

Expand All @@ -38,7 +42,7 @@ def set_artifact_store(self, store: ArtifactStore):
self._artifact_store = store

def set_user_store(self, store: UserStore):
"""Set the globally-configured backend artifact store."""
"""Set the globally-configured backend user store."""
self._user_store = store

def add_catalog_store(
Expand All @@ -53,6 +57,10 @@ def add_catalog_store_from_uri(
"""Adds to the the globally-configured backend list of catalog stores."""
self._catalog_stores.add_catalog_from_uri(id, store_uri, overwite)

def set_custom_list_store(self, store: CustomListStore):
"""Set the globally-configured backend custom list store."""
self._custom_list_store = store

def set_token_key(self, token_key: str):
"""Sets the globally used token secret key."""
self._jwt_secret_key = token_key
Expand Down
5 changes: 5 additions & 0 deletions mlte/backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from mlte.store.base import StoreType, StoreURI
from mlte.store.catalog.sample_catalog import SampleCatalog
from mlte.store.user import factory as user_store_factory
from mlte.store.custom_list import factory as custom_list_store_factory

# Application exit codes
EXIT_SUCCESS = 0
Expand Down Expand Up @@ -95,6 +96,10 @@ def run(
f"Adding catalog with id '{id}' and URI of type: {StoreURI.from_string(uri).type}"
)
state.add_catalog_store_from_uri(uri, id)

# Initialize the backing custom list store instance. Assume same store as artifact one for now.
custom_list_store = custom_list_store_factory.create_custom_list_store(store_uri)
state.set_custom_list_store(custom_list_store)

# Set the token signing key.
state.set_token_key(jwt_secret)
Expand Down
Empty file added mlte/custom_list/__init__.py
Empty file.
29 changes: 29 additions & 0 deletions mlte/custom_list/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""
mlte/custom_list/model.py
Model implementation for a custom list.
"""
from __future__ import annotations

from typing import List

from mlte.model import BaseModel

class CustomList(BaseModel):
"""A model class representing a custom list."""

name: str
"""An name to uniquely identify the list."""

entries: List[CustomListEntry] = []
"""A list of entries in the list."""


class CustomListEntry(BaseModel):
"""A model class representing a custom list entry."""

namme: str
"""A name to uniquely identify the entry."""

description: str
"""A description of the the entry."""
6 changes: 3 additions & 3 deletions mlte/store/catalog/underlying/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
from mlte.store.common.fs_storage import FileSystemStorage

# -----------------------------------------------------------------------------
# LocalFileSystemStore
# FileSystemCatalogStore
# -----------------------------------------------------------------------------


class FileSystemCatalogStore(CatalogStore):
"""A local file system implementation of the MLTE catalog store."""

BASE_CATALOGS_FOLDER = "catalogs"
"""Base fodler to store catalog entries in."""
"""Base folder to store catalog entries in."""

DEFAULT_CATALOG_FOLDER = "catalog"
"""A default name for a catalog folder."""
Expand Down Expand Up @@ -56,7 +56,7 @@ def session(self) -> FileSystemCatalogStoreSession:


# -----------------------------------------------------------------------------
# LocalFileSystemStoreSession
# FileSystemCatalogStoreSession
# -----------------------------------------------------------------------------


Expand Down
Empty file.
29 changes: 29 additions & 0 deletions mlte/store/custom_list/factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""
mlte/store/custom_list/factory.py
Top-level functions for custom list store creation.
"""

from mlte.store.base import StoreType, StoreURI
from mlte.store.custom_list.store import CustomListStore
from mlte.store.custom_list.underlying.fs import FileSystemCustomListStore
# from mlte.store.custom_list.underlying.memory import InMemoryCustomListStore
# from mlte.store.custom_list.underlying.rdbs.store import RelationalDBCustomListStore

def create_custom_list_store(uri: str) -> CustomListStore:
"""
Create a MLTE custom list store instance.
:param uri: The URI for the store instance
:return: The store instance
"""
parsed_uri = StoreURI.from_string(uri)
if parsed_uri.type == StoreType.LOCAL_MEMORY:
return InMemoryCustomListStore(parsed_uri)
if parsed_uri.type == StoreType.RELATIONAL_DB:
return RelationalDBCustomListStore(parsed_uri)
if parsed_uri.type == StoreType.LOCAL_FILESYSTEM:
return FileSystemCustomListStore(parsed_uri)
else:
raise Exception(
f"Store can't be created, unknown or unsupported URI prefix received for uri {parsed_uri}"
)
31 changes: 31 additions & 0 deletions mlte/store/custom_list/store.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""
mlte/store/custom_list/store.py
MLTE custom list store implementation
"""

from __future__ import annotations

from mlte.store.base import Store, StoreSession

# -----------------------------------------------------------------------------
# CustomListStore
# -----------------------------------------------------------------------------


class CustomListStore(Store):
"""
An abstract custom list store
"""

def __init__(self, uri: StoreURI):
"""Base constructor"""
super().__init__(uri=uri)
"""Store uri."""

def session(self) -> CustomListStoreSession:
"""
Return a session handle for the store instance.
:return: The session handle
"""
raise NotImplementedError("Cannot get handle to abstract Store.")
63 changes: 63 additions & 0 deletions mlte/store/custom_list/store_session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
mlte/store/custom_list/store_session.py
MLTE custom list store interface implementation
"""
from __future__ import annotations

from typing import List

from mlte.store.base import ResourceMapper, StoreSession
from mlte.custom_list.model import CustomList, CustomListEntry

# -----------------------------------------------------------------------------
# CustomListStoreSession
# -----------------------------------------------------------------------------


class CustomListStoreSession(StoreSession):
"""The base class for all implementations of the MLTE custom list store session."""

custom_list_mapper: CustomListMapper
"""Mapper for the custom list resource."""

custom_list_entry_mapper: CustomListEntryMapper
"""Mapper for the custom list entry resource."""


class CustomListMapper(ResourceMapper):
"""An interface for mapping CRUD actions to custom lists."""

def create(self, new_custom_list: CustomList) -> CustomList:
raise NotImplementedError(self.NOT_IMPLEMENTED_ERROR_MSG)

def edit(self, updated_custom_list: CustomList) -> CustomList:
raise NotImplementedError(self.NOT_IMPLEMENTED_ERROR_MSG)

def read(self, custom_list_name: str) -> CustomList:
raise NotImplementedError(self.NOT_IMPLEMENTED_ERROR_MSG)

def list(self) -> List[str]:
raise NotImplementedError(self.NOT_IMPLEMENTED_ERROR_MSG)

def delete(self, custom_list_name: str) -> CustomList:
raise NotImplementedError(self.NOT_IMPLEMENTED_ERROR_MSG)


class CustomListEntryMapper(ResourceMapper):
"""An interface for mapping CRUD actions to custom list entries."""

def create(self, new_custom_list_entry: CustomListEntry) -> CustomListEntry:
raise NotImplementedError(self.NOT_IMPLEMENTED_ERROR_MSG)

def edit(self, updated_custom_list_entry: CustomListEntry) -> CustomListEntry:
raise NotImplementedError(self.NOT_IMPLEMENTED_ERROR_MSG)

def read(self, custom_list_entry_name: str) -> CustomListEntry:
raise NotImplementedError(self.NOT_IMPLEMENTED_ERROR_MSG)

def list(self) -> List[str]:
raise NotImplementedError(self.NOT_IMPLEMENTED_ERROR_MSG)

def delete(self, custom_list_entry_name: str) -> CustomListEntry:
raise NotImplementedError(self.NOT_IMPLEMENTED_ERROR_MSG)
Empty file.
103 changes: 103 additions & 0 deletions mlte/store/custom_list/underlying/fs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"""
mlte/store/custom_list/underlying/fs.py
Implementation of local file system custom list store.
"""
from __future__ import annotations

from pathlib import Path

from mlte.custom_list.model import CustomList, CustomListEntry
from mlte.store.base import StoreURI
from mlte.store.custom_list.store import CustomListStore
from mlte.store.custom_list.store_session import CustomListStoreSession, CustomListMapper, CustomListEntryMapper
from mlte.store.common.fs_storage import FileSystemStorage

# -----------------------------------------------------------------------------
# FileSystemCustomListStore
# -----------------------------------------------------------------------------


class FileSystemCustomListStore(CustomListStore):
"""A local file system implementation of the MLTE custom list store."""

BASE_CUSTOM_LIST_FOLDER = "custom_lists"
"""Base folder to store custom lists in."""

def __init__(self, uri: StoreURI) -> None:
self.storage = FileSystemStorage(
uri=uri, sub_folder=self.BASE_CUSTOM_LIST_FOLDER
)
"""Underlying storage."""

# Initialize defaults.
super().__init__(uri=uri)

def session(self) -> FileSystemCustomListStoreSession:
"""
Return a session handle for the store instance.
:return: The session handle
"""
return FileSystemCustomListStoreSession(storage=self.storage)


# -----------------------------------------------------------------------------
# FileSystemCustomLilstStoreSession
# -----------------------------------------------------------------------------


class FileSystemCustomListStoreSession(CustomListStoreSession):
"""A local file-system implementation of the MLTE custom list store."""

def __init__(self, storage: FileSystemStorage) -> None:
self.custom_list_mapper = FileSystemCustomListMapper(storage)
"""The mapper to custom list CRUD."""

self.custom_list_entry_mapper = FileSystemCustomListEntryMapper(storage)
"""The mapper to custom list entry CRUD."""

def close(self) -> None:
"""Close the session."""
# Closing a local FS session is a no-op.
pass


# -----------------------------------------------------------------------------
# FileSystemCustomListMappper
# -----------------------------------------------------------------------------


class FileSystemCustomListMapper(CustomListMapper):
"""FS mapper for the custom list resource."""

CUSTOM_LIST_FOLDER = "custom_lists"
"""Subfolder for custom lists."""

def __init__(
self, storage: FileSystemStorage
) -> None:
self.storage = storage.clone()
"""A reference to underlying storage."""

self.storage.set_base_path(
Path(FileSystemCustomListStore.BASE_CUSTOM_LIST_FOLDER, self.CUSTOM_LIST_FOLDER)
)
"""Set the subfodler for this resource."""

def create(self, custom_list: CustomList) -> CustomList:
self.storage.ensure_resource_does_not_exist(custom_list.name)
return self._write_entry(custom_list)

def _write_entry(self, custom_list: CustomList) -> CustomList:
"""Writes a entry to storage."""
self.storage.write_resource(custom_list.name, custom_list.model_dump())
return self._read_entry(custom_list.name)


# -----------------------------------------------------------------------------
# FileSystemCustomListEntryMappper
# -----------------------------------------------------------------------------


class FileSystemCustomListEntryMapper(CustomListEntryMapper):
pass
2 changes: 1 addition & 1 deletion mlte/store/user/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class UserStore(Store):
def __init__(self, uri: StoreURI, add_default_data: bool = True):
"""Base constructor."""
super().__init__(uri=uri)
"Store uri."
"""Store uri."""

# Sets up default user and permissions.
if add_default_data:
Expand Down
2 changes: 1 addition & 1 deletion mlte/store/user/store_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def __enter__(self) -> UserStoreSession:


class UserMapper(ResourceMapper):
"""A interface for mapping CRUD actions to store users."""
"""An interface for mapping CRUD actions to store users."""

def create(self, new_user: UserWithPassword) -> User:
raise NotImplementedError(self.NOT_IMPLEMENTED_ERROR_MSG)
Expand Down
4 changes: 2 additions & 2 deletions mlte/store/user/underlying/fs.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ def __init__(
"""A reference to underlying storage."""

self.group_mapper = group_mapper
"""Refernce to group mapper, to get updated groups when needed."""
"""Reference to group mapper, to get updated groups when needed."""

self.storage.set_base_path(
Path(FileSystemUserStore.BASE_USERS_FOLDER, self.USERS_FOLDER)
)
"""Set the subfodler for this resrouce."""
"""Set the subfodler for this resource."""

def create(self, user: UserWithPassword) -> User:
self.storage.ensure_resource_does_not_exist(user.username)
Expand Down

0 comments on commit c415b42

Please sign in to comment.