diff --git a/.github/workflows/build_publish.yml b/.github/workflows/build_publish.yml index 08db611..db937a3 100644 --- a/.github/workflows/build_publish.yml +++ b/.github/workflows/build_publish.yml @@ -23,23 +23,22 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install pipenv - pipenv install -r requirements-dev.txt + pip install -r requirements-dev.txt - name: Check code format run: | - pipenv run yapf -dr kiota_serialization_json + yapf -dr kiota_serialization_json - name: Check import order run: | - pipenv run isort kiota_serialization_json + isort kiota_serialization_json - name: Lint with Pylint run: | - pipenv run pylint kiota_serialization_json --disable=W --rcfile=.pylintrc + pylint kiota_serialization_json --disable=W --rcfile=.pylintrc - name: Static type checking with Mypy run: | - pipenv run mypy kiota_serialization_json + mypy kiota_serialization_json - name: Run tests with Pytest run: | - pipenv run pytest + pytest publish: name: Publish distribution to PyPI diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ea20be..ec562e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ 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.4.0] - 2023-07-27 + +### Added + +### Changed +- Enabled backing store support + ## [0.3.7] - 2023-07-04 ### Added diff --git a/Pipfile b/Pipfile deleted file mode 100644 index c4950e5..0000000 --- a/Pipfile +++ /dev/null @@ -1,54 +0,0 @@ -[[source]] -url = "https://pypi.org/simple" -verify_ssl = true -name = "pypi" - -[packages] -microsoft-kiota-abstractions = "==0.6.0" -python-dateutil = "==2.8.2" -astroid = "==2.15.6" -certifi = "==2023.7.22" -charset-normalizer = "==3.2.0" -colorama = "==0.4.6" -coverage = {version = "==7.2.7", extras = ["toml"]} -dill = "==0.3.7" -docutils = "==0.20.1" -exceptiongroup = "==1.1.2" -flit = "==3.9.0" -flit-core = "==3.9.0" -idna = "==3.4" -iniconfig = "==2.0.0" -isort = "==5.12.0" -lazy-object-proxy = "==1.9.0" -mccabe = "==0.7.0" -mypy = "==1.4.1" -mypy-extensions = "==1.0.0" -packaging = "==23.1" -platformdirs = "==3.10.0" -pluggy = "==1.2.0" -pylint = "==2.17.5" -pytest = "==7.4.0" -pytest-cov = "==4.1.0" -requests = "==2.31.0" -toml = "==0.10.2" -tomli = "==2.0.1" -tomli-w = "==1.0.0" -tomlkit = "==0.12.1" -types-python-dateutil = "==2.8.19.14" -typing-extensions = "==4.7.1" -urllib3 = "==2.0.4" -wrapt = "==1.15.0" -yapf = "==0.40.1" -six = "==1.16.0" -uritemplate = "==4.1.1" - -[dev-packages] -flit = "==3.9.0" -pylint = "==2.17.5" -mypy = "==1.4.1" -yapf = "==0.40.1" -isort = "==5.12.0" -pytest = "==7.4.0" -pytest-cov = "==4.1.0" -types-python-dateutil = "*" -toml = "==0.10.2" diff --git a/kiota_serialization_json/_version.py b/kiota_serialization_json/_version.py index 1970751..8dd7053 100644 --- a/kiota_serialization_json/_version.py +++ b/kiota_serialization_json/_version.py @@ -1 +1 @@ -VERSION: str = '0.3.7' +VERSION: str = '0.4.0' diff --git a/kiota_serialization_json/json_parse_node.py b/kiota_serialization_json/json_parse_node.py index d7525e8..9845529 100644 --- a/kiota_serialization_json/json_parse_node.py +++ b/kiota_serialization_json/json_parse_node.py @@ -19,9 +19,6 @@ class JsonParseNode(ParseNode, Generic[T, U]): - on_before_assign_field_values: Optional[Callable[[Parsable], None]] = None - on_after_assign_field_values: Optional[Callable[[Parsable], None]] = None - def __init__(self, node: Any) -> None: """ Args: @@ -29,6 +26,8 @@ def __init__(self, node: Any) -> None: to initialize the node with """ self._json_node = node + self._on_before_assign_field_values: Optional[Callable[[Parsable], None]] = None + self._on_after_assign_field_values: Optional[Callable[[Parsable], None]] = None def get_child_node(self, identifier: str) -> Optional[ParseNode]: """Gets a new parse node for the given identifier @@ -41,7 +40,7 @@ def get_child_node(self, identifier: str) -> Optional[ParseNode]: raise ValueError("identifier cannot be None or empty.") if isinstance(node := self._json_node, dict) and identifier in node: - return JsonParseNode(node[identifier]) + return self._create_new_node(node[identifier]) return None def get_str_value(self) -> Optional[str]: @@ -142,7 +141,7 @@ def get_collection_of_primitive_values(self, primitive_type: Any) -> Optional[Li def func(item): generic_type = primitive_type if primitive_type else type(item) - current_parse_node = JsonParseNode(item) + current_parse_node = self._create_new_node(item) if generic_type in primitive_types: method = getattr(current_parse_node, f'get_{generic_type.__name__.lower()}_value') return method() @@ -160,7 +159,7 @@ def get_collection_of_object_values(self, factory: ParsableFactory) -> List[U]: if isinstance(self._json_node, list): return list( map( - lambda x: JsonParseNode(x).get_object_value(factory), # type: ignore + lambda x: self._create_new_node(x).get_object_value(factory), # type: ignore self._json_node, ) ) @@ -172,7 +171,9 @@ def get_collection_of_enum_values(self, enum_class: K) -> List[Optional[K]]: List[K]: The collection of enum values """ if isinstance(self._json_node, list): - return list(map(lambda x: JsonParseNode(x).get_enum_value(enum_class), self._json_node)) + return list( + map(lambda x: self._create_new_node(x).get_enum_value(enum_class), self._json_node) + ) return [] def get_enum_value(self, enum_class: K) -> Optional[K]: @@ -203,11 +204,11 @@ def get_object_value(self, factory: ParsableFactory) -> U: """ result = factory.create_from_discriminator_value(self) - if self.on_before_assign_field_values: - self.on_before_assign_field_values(result) + if on_before := self.on_before_assign_field_values: + on_before(result) self._assign_field_values(result) - if self.on_after_assign_field_values: - self.on_after_assign_field_values(result) + if on_after := self.on_after_assign_field_values: + on_after(result) return result def get_bytes_value(self) -> Optional[bytes]: @@ -220,35 +221,39 @@ def get_bytes_value(self) -> Optional[bytes]: return None return base64_string.encode("utf-8") - def get_on_before_assign_field_values(self) -> Optional[Callable[[Parsable], None]]: - """Gets the callback called before the node is deserialized. - Returns: - Callable[[Parsable], None]: the callback called before the node is deserialized. - """ - return self.on_before_assign_field_values - - def get_on_after_assign_field_values(self) -> Optional[Callable[[Parsable], None]]: + @property + def on_before_assign_field_values(self) -> Optional[Callable[[Parsable], None]]: """Gets the callback called before the node is deserialized. Returns: Callable[[Parsable], None]: the callback called before the node is deserialized. """ - return self.on_after_assign_field_values + return self._on_before_assign_field_values - def set_on_before_assign_field_values(self, value: Callable[[Parsable], None]) -> None: + @on_before_assign_field_values.setter + def on_before_assign_field_values(self, value: Callable[[Parsable], None]) -> None: """Sets the callback called before the node is deserialized. Args: value (Callable[[Parsable], None]): the callback called before the node is deserialized. """ - self.on_before_assign_field_values = value + self._on_before_assign_field_values = value - def set_on_after_assign_field_values(self, value: Callable[[Parsable], None]) -> None: + @property + def on_after_assign_field_values(self) -> Optional[Callable[[Parsable], None]]: + """Gets the callback called before the node is deserialized. + Returns: + Callable[[Parsable], None]: the callback called before the node is deserialized. + """ + return self._on_after_assign_field_values + + @on_after_assign_field_values.setter + def on_after_assign_field_values(self, value: Callable[[Parsable], None]) -> None: """Sets the callback called after the node is deserialized. Args: value (Callable[[Parsable], None]): the callback called after the node is deserialized. """ - self.on_after_assign_field_values = value + self._on_after_assign_field_values = value def _assign_field_values(self, item: U) -> None: """Assigns the field values to the model object""" @@ -306,3 +311,9 @@ def try_get_anything(self, value: Any) -> Any: pass return value raise ValueError(f"Unexpected additional value type {type(value)} during deserialization.") + + def _create_new_node(self, node: Any) -> JsonParseNode: + new_node: JsonParseNode = JsonParseNode(node) + new_node.on_before_assign_field_values = self.on_before_assign_field_values + new_node.on_after_assign_field_values = self.on_after_assign_field_values + return new_node diff --git a/kiota_serialization_json/json_serialization_writer.py b/kiota_serialization_json/json_serialization_writer.py index cacf6b5..39f235c 100644 --- a/kiota_serialization_json/json_serialization_writer.py +++ b/kiota_serialization_json/json_serialization_writer.py @@ -17,16 +17,15 @@ class JsonSerializationWriter(SerializationWriter): PROPERTY_SEPARATOR: str = ',' - _on_start_object_serialization: Optional[Callable[[Parsable, SerializationWriter], None]] = None - - _on_before_object_serialization: Optional[Callable[[Parsable], None]] = None - - _on_after_object_serialization: Optional[Callable[[Parsable], None]] = None - def __init__(self) -> None: self.writer: Dict = {} self.value: Any = None + self._on_start_object_serialization: Optional[Callable[[Parsable, SerializationWriter], + None]] = None + self._on_before_object_serialization: Optional[Callable[[Parsable], None]] = None + self._on_after_object_serialization: Optional[Callable[[Parsable], None]] = None + def write_str_value(self, key: Optional[str], value: Optional[str]) -> None: """Writes the specified string value to the stream with an optional given key. Args: @@ -147,7 +146,7 @@ def write_collection_of_primitive_values( if isinstance(values, list): result = [] for val in values: - temp_writer = JsonSerializationWriter() + temp_writer = self._create_new_writer() temp_writer.write_any_value(None, val) result.append(temp_writer.value) @@ -168,7 +167,7 @@ def write_collection_of_object_values( if isinstance(values, list): obj_list = [] for val in values: - temp_writer = JsonSerializationWriter() + temp_writer = self._create_new_writer() temp_writer.write_object_value(None, val) obj_list.append(temp_writer.value) @@ -188,7 +187,7 @@ def write_collection_of_enum_values( if isinstance(values, list): result = [] for val in values: - temp_writer = JsonSerializationWriter() + temp_writer = self._create_new_writer() temp_writer.write_enum_value(None, val) result.append(temp_writer.value) @@ -223,7 +222,7 @@ def write_object_value( main value when serializing an intersection wrapper. """ if value or additional_values_to_merge: - temp_writer = JsonSerializationWriter() + temp_writer = self._create_new_writer() if value: self._serialize_value(temp_writer, value) @@ -231,8 +230,8 @@ def write_object_value( if additional_values_to_merge: for additional_value in filter(lambda x: x is not None, additional_values_to_merge): self._serialize_value(temp_writer, additional_value) - if self._on_after_object_serialization: - self._on_after_object_serialization(additional_value) + if on_after := self.on_after_object_serialization: + on_after(additional_value) if value and self._on_after_object_serialization: self._on_after_object_serialization(value) @@ -278,7 +277,7 @@ def get_serialized_content(self) -> bytes: Returns: bytes: The value of the serialized content. """ - if self.writer and self.value is not None: + if self.writer and self.value: # Json output is invalid if it has a mix of values # and key-value pairs. raise ValueError("Invalid Json output") @@ -293,7 +292,8 @@ def get_serialized_content(self) -> bytes: stream = json_string.encode('utf-8') return stream - def get_on_before_object_serialization(self) -> Optional[Callable[[Parsable], None]]: + @property + def on_before_object_serialization(self) -> Optional[Callable[[Parsable], None]]: """Gets the callback called before the object gets serialized. Returns: Optional[Callable[[Parsable], None]]:the callback called before the object @@ -301,7 +301,17 @@ def get_on_before_object_serialization(self) -> Optional[Callable[[Parsable], No """ return self._on_before_object_serialization - def get_on_after_object_serialization(self) -> Optional[Callable[[Parsable], None]]: + @on_before_object_serialization.setter + def on_before_object_serialization(self, value: Optional[Callable[[Parsable], None]]) -> None: + """Sets the callback called before the objects gets serialized. + Args: + value (Optional[Callable[[Parsable], None]]): the callback called before the objects + gets serialized. + """ + self._on_before_object_serialization = value + + @property + def on_after_object_serialization(self) -> Optional[Callable[[Parsable], None]]: """Gets the callback called after the object gets serialized. Returns: Optional[Optional[Callable[[Parsable], None]]]: the callback called after the object @@ -309,7 +319,17 @@ def get_on_after_object_serialization(self) -> Optional[Callable[[Parsable], Non """ return self._on_after_object_serialization - def get_on_start_object_serialization( + @on_after_object_serialization.setter + 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 after the objects + gets serialized. + """ + self._on_after_object_serialization = value + + @property + def on_start_object_serialization( self ) -> Optional[Callable[[Parsable, SerializationWriter], None]]: """Gets the callback called right after the serialization process starts. @@ -319,27 +339,8 @@ def get_on_start_object_serialization( """ return self._on_start_object_serialization - def set_on_before_object_serialization( - self, value: Optional[Callable[[Parsable], None]] - ) -> None: - """Sets the callback called before the objects gets serialized. - Args: - value (Optional[Callable[[Parsable], None]]): the callback called before the objects - gets serialized. - """ - self._on_before_object_serialization = value - - def set_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 after the objects - gets serialized. - """ - self._on_after_object_serialization = value - - def set_on_start_object_serialization( + @on_start_object_serialization.setter + def on_start_object_serialization( self, value: Optional[Callable[[Parsable, SerializationWriter], None]] ) -> None: """Sets the callback called right after the serialization process starts. @@ -397,8 +398,15 @@ def write_any_value(self, key: Optional[str], value: Any) -> Any: ) def _serialize_value(self, temp_writer: JsonSerializationWriter, value: U): - if self._on_before_object_serialization: - self._on_before_object_serialization(value) - if self._on_start_object_serialization: - self._on_start_object_serialization(value, self) + if on_before := self.on_before_object_serialization: + on_before(value) + if on_start := self.on_start_object_serialization: + on_start(value, self) value.serialize(temp_writer) + + def _create_new_writer(self) -> SerializationWriter: + writer = JsonSerializationWriter() + writer.on_before_object_serialization = self.on_before_object_serialization + writer.on_after_object_serialization = self.on_after_object_serialization + writer.on_start_object_serialization = self.on_start_object_serialization + return writer diff --git a/requirements-dev.txt b/requirements-dev.txt index b2fe904..849c397 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,47 +1,78 @@ -# -# These requirements were autogenerated by pipenv -# To regenerate from the project's Pipfile, run: -# -# pipenv lock --requirements -# - --i https://pypi.org/simple/ +-i https://pypi.org/simple + astroid==2.15.6 + certifi==2023.7.22 + charset-normalizer==3.2.0 -colorama==0.4.6 + coverage[toml]==7.2.7 + dill==0.3.7 + docutils==0.20.1 -exceptiongroup==1.1.2 -flit-core==3.9.0 + flit==3.9.0 + +flit-core==3.9.0 + idna==3.4 -importlib-metadata==6.8.0; python_version >= '3.8' + +importlib-metadata==6.8.0 ; python_version >= '3.8' + iniconfig==2.0.0 + isort==5.12.0 + lazy-object-proxy==1.9.0 + mccabe==0.7.0 -microsoft-kiota-abstractions==0.6.0 -mypy-extensions==1.0.0 + mypy==1.4.1 + +mypy-extensions==1.0.0 + packaging==23.1 + platformdirs==3.10.0 + pluggy==1.2.0 + pylint==2.17.5 -pytest-cov==4.1.0 + pytest==7.4.0 -python-dateutil==2.8.2 + +pytest-cov==4.1.0 + requests==2.31.0 -six==1.16.0 + toml==0.10.2 -tomli-w==1.0.0 + tomli==2.0.1 + tomlkit==0.12.1 + types-python-dateutil==2.8.19.14 + typing-extensions==4.7.1 -uritemplate==4.1.1 + urllib3==2.0.4 + wrapt==1.15.0 + yapf==0.40.1 -zipp==3.16.2; python_version >= '3.8' + +zipp==3.16.2 ; python_version >= '3.8' + +colorama==0.4.6 + +exceptiongroup==1.1.2 + +microsoft-kiota-abstractions==0.7.0 + +python-dateutil==2.8.2 + +six==1.16.0 + +uritemplate==4.1.1 +