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 all 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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.6.1] - 2023-07-18
## [0.7.0] - 2023-07-27

### Added
- Added an abstract translator method that should convert a `RequestInformation` object into the native client HTTP request object.
- Enable backing store for Python.

### Changed

Expand Down
2 changes: 1 addition & 1 deletion kiota_abstractions/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
VERSION: str = "0.6.1"
VERSION: str = "0.7.0"
4 changes: 2 additions & 2 deletions kiota_abstractions/request_information.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ def set_content_from_parsable(
writer = self._get_serialization_writer(request_adapter, content_type, values)

if isinstance(values, list):
writer.writer = writer.write_collection_of_object_values(None, values)
writer.write_collection_of_object_values(None, values)
else:
writer.writer = writer.write_object_value(None, values)
writer.write_object_value(None, values)

self._set_content_and_content_type_header(writer, content_type)

Expand Down
26 changes: 15 additions & 11 deletions kiota_abstractions/serialization/parse_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,36 +174,40 @@ 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, value: Callable[[Parsable], None]) -> None:
"""Sets the callback called before the node is deserialized.

Returns:
Callable[[Parsable], None]: the callback called before the node is deserialized.
Args:
value (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:
def on_after_assign_field_values(self, value: Callable[[Parsable], None]) -> None:
"""Sets the callback called after the node is deserialized.

Args:
Expand Down
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
37 changes: 28 additions & 9 deletions kiota_abstractions/store/backed_model.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
from abc import ABC, abstractmethod
# ------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All Rights Reserved.
# Licensed under the MIT License.
# See License in the project root for license information.
# ------------------------------------------------------------------------------

from dataclasses import dataclass

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)
if self.backing_store.get(prop) is not None:
return self.backing_store.get(prop)
try:
attr = super().__getattribute__(prop)
if callable(attr): # methods such as serialize and get_field_deserializers
return attr
return None
except AttributeError:
return None
Loading