Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore/backing store support #101

Merged
merged 18 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions kiota_abstractions/serialization/parse_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,40 +174,43 @@ def get_bytes_value(self) -> BytesIO:
"""
pass

@property
@abstractmethod
def get_on_before_assign_field_values(self) -> Callable[[Parsable], None]:
def on_before_assign_field_values(self) -> Callable[[Parsable], None]:
"""Gets the callback called before the node is deserialized.

Returns:
Callable[[Parsable], None]: the callback called before the node is deserialized.
"""
pass

@on_before_assign_field_values.setter
@abstractmethod
def get_on_after_assign_field_values(self) -> Optional[Callable[[Parsable], None]]:
"""Gets the callback called before the node is deserialized.
def on_before_assign_field_values(self) -> Optional[Callable[[Parsable], None]]:
"""Sets the callback called before the node is deserialized.

Returns:
Callable[[Parsable], None]: the callback called before the node is deserialized.
"""
pass

@property
@abstractmethod
def set_on_before_assign_field_values(self, value: Callable[[Parsable], None]) -> None:
"""Sets the callback called before the node is deserialized.
def on_after_assign_field_values(self) -> Optional[Callable[[Parsable], None]]:
"""Gets the callback called after the node is deserialized.

Args:
value (Callable[[Parsable], None]): the callback called before the node is
deserialized.
Returns:
Callable[[Parsable], None]: the callback called before the node is deserialized.
"""
pass

@on_after_assign_field_values.setter
@abstractmethod
def set_on_after_assign_field_values(self, value: Callable[[Parsable], None]) -> None:
"""Sets the callback called after the node is deserialized.
def on_after_assign_field_values(self, value: Callable[[Parsable], None]) -> None:
"""Sets the callback after before the node is deserialized.

Args:
value (Callable[[Parsable], None]): the callback called after the node is
value (Callable[[Parsable], None]): the callback called before the node is
deserialized.
"""
pass
20 changes: 14 additions & 6 deletions kiota_abstractions/serialization/parse_node_proxy_factory.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# ------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All Rights Reserved.
# Licensed under the MIT License.
# See License in the project root for license information.
# ------------------------------------------------------------------------------

from io import BytesIO
from typing import Callable

Expand All @@ -20,11 +26,13 @@ def __init__(
Args:
concrete (ParseNodeFactory): The concrete factory to wrap.
on_before (Callable[[Parsable], None]): The callback to invoke before the
deserialization
of any model object.
deserialization of any model object.
on_after (Callable[[Parsable], None]): The callback to invoke after the deserialization
of any model object.
"""
if not concrete:
raise ValueError("Concrete factory cannot be None")

self._concrete = concrete
self._on_before = on_before
self._on_after = on_after
Expand All @@ -47,23 +55,23 @@ def get_root_parse_node(self, content_type: str, content: BytesIO) -> ParseNode:
ParseNode: A parse node.
"""
node = self._concrete.get_root_parse_node(content_type, content)
original_before = node.get_on_before_assign_field_values()
original_after = node.get_on_after_assign_field_values()
original_before = node.on_before_assign_field_values
original_after = node.on_after_assign_field_values

def before_callback(value):
if self._on_before:
self._on_before(value)
if callable(original_before):
original_before(value)

node.set_on_before_assign_field_values(before_callback)
node.on_before_assign_field_values = before_callback

def after_callback(value):
if self._on_after:
self._on_after(value)
if callable(original_after):
original_after(value)

node.set_on_after_assign_field_values(after_callback)
node.on_after_assign_field_values = after_callback

return node
50 changes: 26 additions & 24 deletions kiota_abstractions/serialization/serialization_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,9 @@ def get_serialized_content(self) -> BytesIO:
"""
pass

@property
@abstractmethod
def get_on_before_object_serialization(self) -> Optional[Callable[[Parsable], None]]:
def on_before_object_serialization(self) -> Optional[Callable[[Parsable], None]]:
"""Gets the callback called before the object gets serialized.

Returns:
Expand All @@ -216,54 +217,55 @@ def get_on_before_object_serialization(self) -> Optional[Callable[[Parsable], No
"""
pass

@on_before_object_serialization.setter
@abstractmethod
def get_on_after_object_serialization(self) -> Optional[Callable[[Parsable], None]]:
"""Gets the callback called after the object gets serialized.
def on_before_object_serialization(self, value: Optional[Callable[[Parsable], None]]) -> None:
"""Sets the callback called before the objects gets serialized.

Returns:
Optional[Optional[Callable[[Parsable], None]]]: the callback called after the object
Args:
value (Optional[Callable[[Parsable], None]]): the callback called before the objects
gets serialized.
"""
pass

@property
@abstractmethod
def get_on_start_object_serialization(
self
) -> Optional[Callable[[Parsable, SerializationWriter], None]]:
"""Gets the callback called right after the serialization process starts.
def on_after_object_serialization(self) -> Optional[Callable[[Parsable], None]]:
"""Gets the callback called after the object gets serialized.

Returns:
Optional[Callable[[Parsable, SerializationWriter], None]]: the callback called
right after the serialization process starts.
Optional[Optional[Callable[[Parsable], None]]]: the callback called after the object
gets serialized.
"""
pass

@on_after_object_serialization.setter
@abstractmethod
def set_on_before_object_serialization(
self, value: Optional[Callable[[Parsable], None]]
) -> None:
"""Sets the callback called before the objects gets serialized.
def on_after_object_serialization(self, value: Optional[Callable[[Parsable], None]]) -> None:
"""Sets the callback called after the objects gets serialized.

Args:
value (Optional[Callable[[Parsable], None]]): the callback called before the objects
value (Optional[Callable[[Parsable], None]]): the callback called after the objects
gets serialized.
"""
pass

@property
@abstractmethod
def set_on_after_object_serialization(
self, value: Optional[Callable[[Parsable], None]]
) -> None:
"""Sets the callback called after the objects gets serialized.
def on_start_object_serialization(
self
) -> Optional[Callable[[Parsable, SerializationWriter], None]]:
"""Gets the callback called right after the serialization process starts.

Args:
value (Optional[Callable[[Parsable], None]]): the callback called after the objects
gets serialized.
Returns:
Optional[Callable[[Parsable, SerializationWriter], None]]: the callback called
right after the serialization process starts.
"""
pass

@on_start_object_serialization.setter
@abstractmethod
def set_on_start_object_serialization(
def on_start_object_serialization(
self, value: Optional[Callable[[Parsable, SerializationWriter], None]]
) -> None:
"""Sets the callback called right after the serialization process starts.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# ------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All Rights Reserved.
# Licensed under the MIT License.
# See License in the project root for license information.
# ------------------------------------------------------------------------------

from typing import Callable, Optional

from .parsable import Parsable
Expand Down Expand Up @@ -26,6 +32,9 @@ def __init__(
on_start (Optional[Callable[[Parsable, SerializationWriter], None]]): the callback to
invoke when the serialization of a model object starts
"""
if not concrete:
raise ValueError("concrete SerializationWriterFactory cannot be None.")

self._concrete = concrete
self._on_before = on_before
self._on_after = on_after
Expand All @@ -48,32 +57,32 @@ def get_serialization_writer(self, content_type: str) -> SerializationWriter:
SerializationWriter: A new SerializationWriter instance for the given content type.
"""
writer = self._concrete.get_serialization_writer(content_type)
original_before = writer.get_on_before_object_serialization()
original_after = writer.get_on_after_object_serialization()
original_start = writer.get_on_start_object_serialization()
original_before = writer.on_before_object_serialization
original_after = writer.on_after_object_serialization
original_start = writer.on_start_object_serialization

def before_callback(value):
if self._on_before:
self._on_before(value)
if original_before:
original_before(value)

writer.set_on_before_object_serialization(before_callback)
writer.on_before_object_serialization = before_callback

def after_callback(value):
if self._on_after:
self._on_after(value)
if original_after:
original_after(value)

writer.set_on_after_object_serialization(after_callback)
writer.on_after_object_serialization = after_callback

def start_callback(value1, value2):
if self._on_start:
self._on_start(value1, value2)
if original_start:
original_start(value1, value2)

writer.set_on_start_object_serialization(start_callback)
writer.on_start_object_serialization = start_callback

return writer
29 changes: 21 additions & 8 deletions kiota_abstractions/store/backed_model.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
# ------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All Rights Reserved.
# Licensed under the MIT License.
# See License in the project root for license information.
# ------------------------------------------------------------------------------

from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Optional

from .backing_store import BackingStore


class BackedModel(ABC):
@dataclass
class BackedModel:
"""Defines the contracts for a model that is backed by a store.
"""
# Stores model information.
backing_store: BackingStore

@abstractmethod
def get_backing_store(self) -> BackingStore:
"""Gets the store that is backing the model
def __setattr__(self, prop, val):
if prop == "backing_store":
super().__setattr__(prop, val)
else:
self.backing_store.set(prop, val)

Returns:
BackingStore: The store backing the model
"""
pass
def __getattribute__(self, prop):
if prop == "backing_store":
return super().__getattribute__(prop)
return self.backing_store.get(prop)
37 changes: 26 additions & 11 deletions kiota_abstractions/store/backing_store.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# ------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All Rights Reserved.
# Licensed under the MIT License.
# See License in the project root for license information.
# ------------------------------------------------------------------------------

from abc import ABC, abstractmethod
from typing import Any, Callable, Generic, List, Optional, Tuple, TypeVar

Expand All @@ -7,8 +13,7 @@
class BackingStore(ABC, Generic[T]):
"""Stores model information in a different location than the object properties.
Implementations can provide dirty tracking capabilities, caching capabilities
or integration with 3rd party stores
"""
or integration with 3rd party stores"""

@abstractmethod
def get(self, key: str) -> Optional[T]:
Expand Down Expand Up @@ -54,7 +59,9 @@ def enumerate_keys_for_values_changed_to_null(self) -> List[str]:

@abstractmethod
def subscribe(
self, callback: Callable[[str, Any, Any], None], subscription_id: Optional[str]
self,
callback: Callable[[str, Any, Any], None],
subscription_id: Optional[str] = None
) -> str:
"""Creates a subscription to any data change happening.

Expand Down Expand Up @@ -83,8 +90,9 @@ def clear(self) -> None:
"""Clears the data stored in the backing store. Doesn't trigger any subscription."""
pass

@property
@abstractmethod
def get_is_initialization_completed(self) -> bool:
def is_initialization_completed(self) -> bool:
"""Whether the initialization of the object and/or the initial deserialization has been
completed to track whether objects have changed.

Expand All @@ -93,15 +101,20 @@ def get_is_initialization_completed(self) -> bool:
"""
pass

@is_initialization_completed.setter
@abstractmethod
def set_is_initialization_completed(self, completed) -> None:
"""Sets whether the initialization of the object and/or the initial deserialization has been
completed to track whether objects have changed.
def is_initialization_completed(self, completed: bool) -> None:
"""Sets the initialization completed state of the object.

Args:
completed (bool): Whether the initialization of the object and/or the initial
deserialization has been completed to track whether objects have changed.
"""
pass

@property
@abstractmethod
def get_return_only_changed_values(self) -> bool:
def return_only_changed_values(self) -> bool:
"""Whether to return only values that have changed since the initialization of the object
when calling the Get and Enumerate methods.

Expand All @@ -110,12 +123,14 @@ def get_return_only_changed_values(self) -> bool:
"""
pass

@return_only_changed_values.setter
@abstractmethod
def set_return_only_changed_values(self, changed) -> None:
def return_only_changed_values(self, changed: bool) -> None:
"""Sets whether to return only values that have changed since the initialization of the
object when calling the Get and Enumerate methods.

Returns:
bool:
Args:
changed (bool): Whether to return only values that have changed since the
initialization of the object when calling the Get and Enumerate methods.
"""
pass
6 changes: 6 additions & 0 deletions kiota_abstractions/store/backing_store_factory.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# ------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All Rights Reserved.
# Licensed under the MIT License.
# See License in the project root for license information.
# ------------------------------------------------------------------------------

from abc import ABC, abstractmethod

from .backing_store import BackingStore
Expand Down
Loading