diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/__init__.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/__init__.py index 21c334cb9..b31e36dcf 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/__init__.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/__init__.py @@ -1,16 +1,20 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + from .store_item import StoreItem from .storage import Storage, AsyncStorageBase from .memory_storage import MemoryStorage -from .transcript_info import TranscriptInfo -from .transcript_logger import ( + +from .transcript import ( + TranscriptInfo, TranscriptLogger, ConsoleTranscriptLogger, TranscriptLoggerMiddleware, + TranscriptStore, FileTranscriptLogger, + FileTranscriptStore, PagedResult, ) -from .transcript_store import TranscriptStore -from .transcript_file_store import FileTranscriptStore __all__ = [ "StoreItem", diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/_type_aliases.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/_type_aliases.py index f800f57f8..c8fdd2690 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/_type_aliases.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/_type_aliases.py @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + from typing import MutableMapping, Any JSON = MutableMapping[str, Any] diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/error_handling.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/error_handling.py index 9f5cb5200..bec1f994d 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/error_handling.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/error_handling.py @@ -1,22 +1,24 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -from collections.abc import Callable, Awaitable from typing import TypeVar +from collections.abc import Callable, Awaitable -error_filter = TypeVar("error_filter", bound=Callable[[Exception], bool]) +ErrorFilter = Callable[[Exception], bool] +T = TypeVar("T") -async def ignore_error(promise: Awaitable, ignore_error_filter: error_filter): + +async def ignore_error( + promise: Awaitable[T], ignore_error_filter: ErrorFilter +) -> T | None: """ Ignores errors based on the provided filter function. - promise: the awaitable to execute - ignore_error_filter: a function that takes an Exception and returns True if the error should be - ignored, False otherwise. - - Returns the result of the promise if successful, or None if the error is ignored. - Raises the error if it is not ignored. + :param promise: An awaitable that may raise an exception. + :param ignore_error_filter: A function that takes an Exception and returns True if the error should be ignored. + :return: The result of the promise if successful, or None if the error is ignored. + :raises Exception: Re-raises the exception if it is not ignored. """ try: return await promise @@ -26,16 +28,17 @@ async def ignore_error(promise: Awaitable, ignore_error_filter: error_filter): raise err -def is_status_code_error(*ignored_codes: list[int]) -> error_filter: +def is_status_code_error(*ignored_codes: int) -> ErrorFilter: """ Creates an error filter function that ignores errors with specific status codes. - ignored_codes: a list of status codes to ignore - Returns a function that takes an Exception and returns True if the error's status code is in ignored_codes. + :param ignored_codes: A list of status codes to ignore. + :return: A function that takes an Exception and returns True if the error's status code is in the ignored list. """ def func(err: Exception) -> bool: - if hasattr(err, "status_code") and err.status_code in ignored_codes: + status_code = getattr(err, "status_code", None) + if status_code is not None and status_code in ignored_codes: return True return False diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/memory_storage.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/memory_storage.py index 7a0aaab4e..5e962ecda 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/memory_storage.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/memory_storage.py @@ -12,39 +12,47 @@ class MemoryStorage(Storage): + """In-memory storage implementation for testing and development purposes.""" + def __init__(self, state: dict[str, JSON] | None = None): + """Initializes the MemoryStorage with an optional initial state. + + :param state: An optional dictionary representing the initial state of the storage. + :raises ValueError: If state is not a dictionary or None. + """ self._memory: dict[str, JSON] = state or {} self._lock = Lock() async def read( - self, keys: list[str], *, target_cls: StoreItemT = None, **kwargs + self, keys: list[str], *, target_cls: type[StoreItemT], **kwargs ) -> dict[str, StoreItemT]: + """Reads items from the in-memory storage. + + :param keys: A list of keys to read from the storage. + :param target_cls: The class type of the items to be read. Must be a subclass of StoreItem. + :return: A dictionary mapping keys to their corresponding StoreItem instances. + :raises ValueError: If keys are empty. + """ if not keys: raise ValueError("Storage.read(): Keys are required when reading.") - if not target_cls: - raise ValueError("Storage.read(): target_cls cannot be None.") - result: dict[str, StoreItem] = {} + result: dict[str, StoreItemT] = {} async with self._lock: for key in keys: if key == "": raise ValueError("MemoryStorage.read(): key cannot be empty") if key in self._memory: - if not target_cls: - result[key] = self._memory[key] - else: - try: - result[key] = target_cls.from_json_to_store_item( - self._memory[key] - ) - except AttributeError as error: - raise TypeError( - f"MemoryStorage.read(): could not deserialize in-memory item into {target_cls} class. Error: {error}" - ) + result[key] = target_cls.from_json_to_store_item(self._memory[key]) + return result async def write(self, changes: dict[str, StoreItem]): + """Writes items to the in-memory storage. + + :param changes: A dictionary mapping keys to StoreItem instances to be written to the storage. + :raises ValueError: If changes is None or any key is empty. + """ if not changes: raise ValueError("MemoryStorage.write(): changes cannot be None") @@ -55,6 +63,12 @@ async def write(self, changes: dict[str, StoreItem]): self._memory[key] = changes[key].store_item_to_json() async def delete(self, keys: list[str]): + """Deletes items from the in-memory storage. + + :param keys: A list of keys to delete from the storage. + :raises ValueError: If keys is empty or any key is empty. + """ + if not keys: raise ValueError("Storage.delete(): Keys are required when deleting.") diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/storage.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/storage.py index 380def139..5b4161b07 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/storage.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/storage.py @@ -1,8 +1,8 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -from typing import Protocol, TypeVar, Type -from abc import abstractmethod +from typing import TypeVar +from abc import ABC, abstractmethod from asyncio import gather from .store_item import StoreItem @@ -11,26 +11,30 @@ StoreItemT = TypeVar("StoreItemT", bound=StoreItem) -class Storage(Protocol): +class Storage(ABC): + """Abstract base class for storage implementations.""" + + @abstractmethod async def read( - self, keys: list[str], *, target_cls: Type[StoreItemT] | None = None, **kwargs + self, keys: list[str], *, target_cls: type[StoreItemT], **kwargs ) -> dict[str, StoreItemT]: """Reads multiple items from storage. - keys: A list of keys to read. - target_cls: The class to deserialize the stored JSON into. - Returns a dictionary of key to StoreItem. - - missing keys are omitted from the result. + :param keys: A list of keys to read. + :param target_cls: The class of the StoreItem to deserialize the data into. + :return: A dictionary of key to StoreItem. """ pass - async def write(self, changes: dict[str, StoreItemT]) -> None: + @abstractmethod + async def write(self, changes: dict[str, StoreItem]) -> None: """Writes multiple items to storage. - changes: A dictionary of key to StoreItem to write.""" + :param changes: A dictionary of key to StoreItem to write. + """ pass + @abstractmethod async def delete(self, keys: list[str]) -> None: """Deletes multiple items from storage. @@ -53,21 +57,29 @@ async def initialize(self) -> None: @abstractmethod async def _read_item( - self, key: str, *, target_cls: Type[StoreItemT] | None = None, **kwargs + self, key: str, *, target_cls: type[StoreItemT], **kwargs ) -> tuple[str | None, StoreItemT | None]: """Reads a single item from storage by key. - Returns a tuple of (key, StoreItem) if found, or (None, None) if not found. + :param key: The key to read. + :param target_cls: The class of the StoreItem to deserialize the data into. + :return: A tuple of key and StoreItem. If the item does not exist, returns (None, None). """ pass async def read( - self, keys: list[str], *, target_cls: Type[StoreItemT] | None = None, **kwargs + self, keys: list[str], *, target_cls: type[StoreItemT], **kwargs ) -> dict[str, StoreItemT]: + """ + Reads multiple items from storage. + + :param keys: A list of keys to read. + :param target_cls: The class of the StoreItem to deserialize the data into. + :return: A dictionary of key to StoreItem. + :raises ValueError: If keys is empty. + """ if not keys: raise ValueError("Storage.read(): Keys are required when reading.") - if not target_cls: - raise ValueError("Storage.read(): target_cls cannot be None.") with spans.StorageRead(len(keys)): await self.initialize() @@ -75,14 +87,23 @@ async def read( items: list[tuple[str | None, StoreItemT | None]] = await gather( *[self._read_item(key, target_cls=target_cls, **kwargs) for key in keys] ) - return {key: value for key, value in items if key is not None} + return { + key: value + for key, value in items + if key is not None and value is not None + } @abstractmethod - async def _write_item(self, key: str, value: StoreItemT) -> None: + async def _write_item(self, key: str, value: StoreItem) -> None: """Writes a single item to storage by key.""" pass - async def write(self, changes: dict[str, StoreItemT]) -> None: + async def write(self, changes: dict[str, StoreItem]) -> None: + """Writes multiple items to storage. + + :param changes: A dictionary of key to StoreItem to write. + :raises ValueError: If changes is empty. + """ if not changes: raise ValueError("Storage.write(): Changes are required when writing.") @@ -95,10 +116,18 @@ async def write(self, changes: dict[str, StoreItemT]) -> None: @abstractmethod async def _delete_item(self, key: str) -> None: - """Deletes a single item from storage by key.""" + """Deletes a single item from storage by key. + + :param key: The key to delete. + """ pass async def delete(self, keys: list[str]) -> None: + """Deletes multiple items from storage. + + :param keys: A list of keys to delete. + :raises ValueError: If keys is empty. + """ if not keys: raise ValueError("Storage.delete(): Keys are required when deleting.") diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/store_item.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/store_item.py index 451b72295..9f751b8a9 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/store_item.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/store_item.py @@ -1,15 +1,30 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -from abc import ABC +from __future__ import annotations + +from abc import ABC, abstractmethod from ._type_aliases import JSON class StoreItem(ABC): + """Abstract base class for items stored in the storage system.""" + + @abstractmethod def store_item_to_json(self) -> JSON: + """Serializes the StoreItem to a JSON-compatible dictionary. + + :return: A JSON-compatible dictionary representation of the StoreItem. + """ pass @staticmethod - def from_json_to_store_item(json_data: JSON) -> "StoreItem": + @abstractmethod + def from_json_to_store_item(json_data: JSON) -> StoreItem: + """Deserializes a JSON-compatible dictionary to a StoreItem. + + :param json_data: A JSON-compatible dictionary representation of the StoreItem. + :return: A StoreItem instance. + """ pass diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/__init__.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/__init__.py new file mode 100644 index 000000000..0b6174763 --- /dev/null +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/__init__.py @@ -0,0 +1,24 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +from .transcript_info import TranscriptInfo +from .transcript_logger import ( + TranscriptLogger, + ConsoleTranscriptLogger, + TranscriptLoggerMiddleware, + FileTranscriptLogger, + PagedResult, +) +from .transcript_store import TranscriptStore +from .transcript_file_store import FileTranscriptStore + +__all__ = [ + "TranscriptInfo", + "TranscriptLogger", + "ConsoleTranscriptLogger", + "TranscriptLoggerMiddleware", + "TranscriptStore", + "FileTranscriptLogger", + "FileTranscriptStore", + "PagedResult", +] diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript_file_store.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/transcript_file_store.py similarity index 100% rename from libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript_file_store.py rename to libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/transcript_file_store.py diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript_info.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/transcript_info.py similarity index 100% rename from libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript_info.py rename to libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/transcript_info.py diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript_logger.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/transcript_logger.py similarity index 97% rename from libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript_logger.py rename to libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/transcript_logger.py index 3986e4792..780656199 100644 --- a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript_logger.py +++ b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/transcript_logger.py @@ -11,7 +11,7 @@ from typing import Awaitable, Callable, Optional from dataclasses import dataclass -from microsoft_agents.activity import Activity, ChannelAccount +from microsoft_agents.activity import Activity, ChannelAccount, ResourceResponse from microsoft_agents.activity.activity import ConversationReference from microsoft_agents.activity.activity_types import ActivityTypes from microsoft_agents.activity.conversation_reference import ActivityEventNames @@ -139,8 +139,8 @@ async def on_turn( async def send_activities_handler( ctx: TurnContext, activities: list[Activity], - next_send: Callable[[], Awaitable[None]], - ): + next_send: Callable[[], Awaitable[list[ResourceResponse]]], + ) -> list[ResourceResponse]: # Run full pipeline responses = await next_send() for index, activity in enumerate(activities): diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript_memory_store.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/transcript_memory_store.py similarity index 100% rename from libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript_memory_store.py rename to libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/transcript_memory_store.py diff --git a/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript_store.py b/libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/transcript_store.py similarity index 100% rename from libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript_store.py rename to libraries/microsoft-agents-hosting-core/microsoft_agents/hosting/core/storage/transcript/transcript_store.py diff --git a/libraries/microsoft-agents-storage-blob/microsoft_agents/storage/blob/blob_storage.py b/libraries/microsoft-agents-storage-blob/microsoft_agents/storage/blob/blob_storage.py index a88c60783..8dfcf8376 100644 --- a/libraries/microsoft-agents-storage-blob/microsoft_agents/storage/blob/blob_storage.py +++ b/libraries/microsoft-agents-storage-blob/microsoft_agents/storage/blob/blob_storage.py @@ -22,8 +22,14 @@ class BlobStorage(AsyncStorageBase): + """A Blob Storage provider for storing StoreItem objects in Azure Blob Storage.""" def __init__(self, config: BlobStorageConfig): + """Initialize the BlobStorage with the given configuration. + + :param config: BlobStorageConfig object containing the configuration for the blob storage. + :raises ValueError: If the container name is not provided in the configuration. + """ if not config.container_name: raise ValueError(str(blob_storage_errors.BlobContainerNameRequired)) @@ -37,6 +43,10 @@ def __init__(self, config: BlobStorageConfig): self._initialized: bool = False def _create_client(self) -> BlobServiceClient: + """Creates a BlobServiceClient based on the provided configuration. + :return: An instance of BlobServiceClient. + :raises ValueError: If the configuration is invalid. + """ if self.config.url: # connect with URL and credentials if not self.config.credential: raise ValueError( @@ -63,8 +73,14 @@ async def initialize(self) -> None: self._initialized = True async def _read_item( - self, key: str, *, target_cls: StoreItemT | None = None, **kwargs + self, key: str, *, target_cls: type[StoreItemT], **kwargs ) -> tuple[str | None, StoreItemT | None]: + """Reads an item from blob storage. + + :param key: The key of the item to read. + :param target_cls: The type of the StoreItem to deserialize into. + :return: A tuple containing the key and the deserialized StoreItem, or (None, None) if not found. + """ item = await ignore_error( self._container_client.download_blob(blob=key, timeout=5), is_status_code_error(404), @@ -72,7 +88,7 @@ async def _read_item( if not item: return None, None - item_rep: str = await item.readall() + item_rep: bytes = await item.readall() item_JSON: JSON = json.loads(item_rep) try: return key, target_cls.from_json_to_store_item(item_JSON) @@ -82,6 +98,12 @@ async def _read_item( ) async def _write_item(self, key: str, item: StoreItem) -> None: + """Writes an item to blob storage. + + :param key: The key under which to store the item. + :param item: The StoreItem to serialize and store. + :raises ValueError: If the StoreItem serialization returns None. + """ item_JSON: JSON = item.store_item_to_json() if item_JSON is None: raise ValueError( @@ -98,6 +120,11 @@ async def _write_item(self, key: str, item: StoreItem) -> None: ) async def _delete_item(self, key: str) -> None: + """Deletes an item from blob storage. + + :param key: The key of the item to delete. + :raises ValueError: If the deletion fails for reasons other than the item not existing. + """ await ignore_error( self._container_client.delete_blob(blob=key), is_status_code_error(404) ) diff --git a/libraries/microsoft-agents-storage-cosmos/microsoft_agents/storage/cosmos/cosmos_db_storage.py b/libraries/microsoft-agents-storage-cosmos/microsoft_agents/storage/cosmos/cosmos_db_storage.py index 5dc612737..68bd7d563 100644 --- a/libraries/microsoft-agents-storage-cosmos/microsoft_agents/storage/cosmos/cosmos_db_storage.py +++ b/libraries/microsoft-agents-storage-cosmos/microsoft_agents/storage/cosmos/cosmos_db_storage.py @@ -52,6 +52,11 @@ def __init__(self, config: CosmosDBStorageConfig): self._lock: asyncio.Lock = asyncio.Lock() def _create_client(self) -> CosmosClient: + """Create a CosmosClient based on the configuration. + + :return: A CosmosClient instance. + :raises ValueError: If the configuration is invalid. + """ if self._config.url: if not self._config.credential: raise ValueError( @@ -82,19 +87,27 @@ def _create_client(self) -> CosmosClient: ) def _sanitize(self, key: str) -> str: + """Sanitize the key for use in CosmosDB.""" return sanitize_key( key, self._config.key_suffix, self._config.compatibility_mode ) async def _read_item( - self, key: str, *, target_cls: StoreItemT | None = None, **kwargs + self, key: str, *, target_cls: type[StoreItemT], **kwargs ) -> tuple[str | None, StoreItemT | None]: + """Read an item from the storage. + + :param key: The key of the item to read. + :param target_cls: The type of the item to read. + :return: A tuple containing the real key and the item, or (None, None) if not found. + :raises ValueError: If the key is empty. + """ if key == "": raise ValueError(str(storage_errors.CosmosDbKeyCannotBeEmpty)) escaped_key: str = self._sanitize(key) - read_item_response: CosmosDict = await ignore_error( + read_item_response: CosmosDict | None = await ignore_error( self._container.read_item( escaped_key, self._get_partition_key(escaped_key) ), @@ -103,10 +116,18 @@ async def _read_item( if read_item_response is None: return None, None - doc: JSON = read_item_response.get("document") + doc: JSON | None = read_item_response.get("document") + if doc is None: + return read_item_response["realId"], None return read_item_response["realId"], target_cls.from_json_to_store_item(doc) async def _write_item(self, key: str, item: StoreItem) -> None: + """Write an item to the storage. + + :param key: The key of the item to write. + :param item: The item to write. + :raises ValueError: If the key is empty. + """ if key == "": raise ValueError(str(storage_errors.CosmosDbKeyCannotBeEmpty)) @@ -120,6 +141,11 @@ async def _write_item(self, key: str, item: StoreItem) -> None: await self._container.upsert_item(body=doc) async def _delete_item(self, key: str) -> None: + """Delete an item from the storage. + + :param key: The key of the item to delete. + :raises ValueError: If the key is empty. + """ if key == "": raise ValueError(str(storage_errors.CosmosDbKeyCannotBeEmpty)) @@ -133,6 +159,7 @@ async def _delete_item(self, key: str) -> None: ) async def _create_container(self) -> None: + """Create the container if it does not exist.""" partition_key = { "paths": ["/id"], "kind": documents.PartitionKind.Hash, @@ -164,6 +191,7 @@ async def _create_container(self) -> None: ) async def initialize(self) -> None: + """Initialize the storage provider.""" if not self._container: async with self._lock: # in case another async task attempted to initialize just before acquiring the lock @@ -178,7 +206,13 @@ async def initialize(self) -> None: await self._create_container() def _get_partition_key(self, key: str): + """Get the partition key for the given key, considering compatibility mode. + + :param key: The key for which to get the partition key. + :return: The partition key value. + """ return NonePartitionKeyValue if self._compatability_mode_partition_key else key async def _close(self) -> None: + """Close the storage provider.""" await self._client.close() diff --git a/tests/_common/storage/utils.py b/tests/_common/storage/utils.py index 65aa42433..3343874cf 100644 --- a/tests/_common/storage/utils.py +++ b/tests/_common/storage/utils.py @@ -256,8 +256,6 @@ async def test_read_errors(self, initial_state): await storage.read(None, target_cls=MockStoreItem) with pytest.raises(ValueError): await storage.read([""], target_cls=MockStoreItem) - with pytest.raises(ValueError): - await storage.read(["key"], target_cls=None) assert initial_state == initial_state_copy @pytest.mark.asyncio @@ -363,9 +361,9 @@ async def test_delete_errors(self, initial_state): initial_state_copy = my_deepcopy(initial_state) async with self.storage(initial_state) as storage: with pytest.raises(ValueError): - await storage.read([]) + await storage.delete([]) with pytest.raises(ValueError): - await storage.read(None) + await storage.delete(None) assert initial_state == initial_state_copy @pytest.mark.asyncio @@ -410,8 +408,6 @@ async def test_flow(self): with pytest.raises(ValueError): await storage.read([], target_cls=MockStoreItem) - with pytest.raises(ValueError): - await storage.read(["key_b"], target_cls=None) change = { "key_c": MockStoreItemB( diff --git a/tests/hosting_core/app/state/test_state.py b/tests/hosting_core/app/state/test_state.py index 923346e43..daf7e102f 100644 --- a/tests/hosting_core/app/state/test_state.py +++ b/tests/hosting_core/app/state/test_state.py @@ -31,7 +31,7 @@ async def load( if not storage: return cls(__key__="test") - data: Dict[str, Any] = await storage.read(["test"]) + data: Dict[str, Any] = await storage.read(["test"], target_cls=MockStoreItem) if "test" in data: if isinstance(data["test"], StoreItem): diff --git a/tests/hosting_core/storage/test_transcript_logger_middleware.py b/tests/hosting_core/storage/test_transcript_logger_middleware.py index 744f0df1e..1a01ace7d 100644 --- a/tests/hosting_core/storage/test_transcript_logger_middleware.py +++ b/tests/hosting_core/storage/test_transcript_logger_middleware.py @@ -6,12 +6,12 @@ from microsoft_agents.activity import Activity, ActivityEventNames, ActivityTypes from microsoft_agents.hosting.core.authorization.claims_identity import ClaimsIdentity from microsoft_agents.hosting.core.middleware_set import TurnContext -from microsoft_agents.hosting.core.storage.transcript_logger import ( +from microsoft_agents.hosting.core.storage.transcript.transcript_logger import ( ConsoleTranscriptLogger, FileTranscriptLogger, TranscriptLoggerMiddleware, ) -from microsoft_agents.hosting.core.storage.transcript_memory_store import ( +from microsoft_agents.hosting.core.storage.transcript.transcript_memory_store import ( TranscriptMemoryStore, ) import pytest diff --git a/tests/hosting_core/storage/test_transcript_store_memory.py b/tests/hosting_core/storage/test_transcript_store_memory.py index 691c3e027..ac59f6ca9 100644 --- a/tests/hosting_core/storage/test_transcript_store_memory.py +++ b/tests/hosting_core/storage/test_transcript_store_memory.py @@ -3,7 +3,7 @@ from datetime import datetime, timezone import pytest -from microsoft_agents.hosting.core.storage.transcript_memory_store import ( +from microsoft_agents.hosting.core.storage.transcript.transcript_memory_store import ( TranscriptMemoryStore, PagedResult, )