Fix Pydantic custom attributes (#229)

* Add custom extension attribute to the test set.

Replicates bug test data from the https://github.com/cloudevents/sdk-python/issues/228

Signed-off-by: Yurii Serhiichuk <savik.ne@gmail.com>

* use modern `super` syntax

Signed-off-by: Yurii Serhiichuk <savik.ne@gmail.com>

* Fix `black` language version

Signed-off-by: Yurii Serhiichuk <savik.ne@gmail.com>

* Fixes https://github.com/cloudevents/sdk-python/issues/228

Pydantic v2 .__dict__ has different behavior from what Pydantic v1 had and is not giving us `extra` fields anymore. On the other hand the iterator over the event gives us extras as well

Signed-off-by: Yurii Serhiichuk <savik.ne@gmail.com>

* Add missing EOF

Signed-off-by: Yurii Serhiichuk <savik.ne@gmail.com>

* Add Pydantic fix to the changelog

Signed-off-by: Yurii Serhiichuk <savik.ne@gmail.com>

* Add links to the changelog

Signed-off-by: Yurii Serhiichuk <savik.ne@gmail.com>

* Bump version

Signed-off-by: Yurii Serhiichuk <savik.ne@gmail.com>

* Update Black and MyPy versions

Signed-off-by: Yurii Serhiichuk <savik.ne@gmail.com>

---------

Signed-off-by: Yurii Serhiichuk <savik.ne@gmail.com>
This commit is contained in:
Yurii Serhiichuk 2023-10-30 06:44:36 +01:00 committed by GitHub
parent 8ada7d947b
commit 21572afb57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 16 additions and 9 deletions

View File

@ -11,12 +11,12 @@ repos:
- id: isort - id: isort
args: [ "--profile", "black", "--filter-files" ] args: [ "--profile", "black", "--filter-files" ]
- repo: https://github.com/psf/black - repo: https://github.com/psf/black
rev: 23.9.1 rev: 23.10.1
hooks: hooks:
- id: black - id: black
language_version: python3.10 language_version: python3.11
- repo: https://github.com/pre-commit/mirrors-mypy - repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.6.0" rev: v1.6.1
hooks: hooks:
- id: mypy - id: mypy
files: ^(cloudevents/) files: ^(cloudevents/)
@ -24,4 +24,4 @@ repos:
types: [ python ] types: [ python ]
args: [ ] args: [ ]
additional_dependencies: additional_dependencies:
- 'pydantic' - "pydantic"

View File

@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [1.10.1]
### Fixed
- Fixed Pydantic v2 `to_json` (and `to_structured`) conversion ([#229])
## [1.10.0] — 2023-09-25 ## [1.10.0] — 2023-09-25
### Added ### Added
- Pydantic v2 support. ([#219]) - Pydantic v2 support. ([#219])
@ -185,6 +190,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Initial release - Initial release
[1.10.1]: https://github.com/cloudevents/sdk-python/compare/1.10.0...1.10.1
[1.10.0]: https://github.com/cloudevents/sdk-python/compare/1.9.0...1.10.0 [1.10.0]: https://github.com/cloudevents/sdk-python/compare/1.9.0...1.10.0
[1.9.0]: https://github.com/cloudevents/sdk-python/compare/1.8.0...1.9.0 [1.9.0]: https://github.com/cloudevents/sdk-python/compare/1.8.0...1.9.0
[1.8.0]: https://github.com/cloudevents/sdk-python/compare/1.7.0...1.8.0 [1.8.0]: https://github.com/cloudevents/sdk-python/compare/1.7.0...1.8.0
@ -266,3 +272,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#218]: https://github.com/cloudevents/sdk-python/pull/218 [#218]: https://github.com/cloudevents/sdk-python/pull/218
[#219]: https://github.com/cloudevents/sdk-python/pull/219 [#219]: https://github.com/cloudevents/sdk-python/pull/219
[#221]: https://github.com/cloudevents/sdk-python/pull/221 [#221]: https://github.com/cloudevents/sdk-python/pull/221
[#229]: https://github.com/cloudevents/sdk-python/pull/229

View File

@ -12,4 +12,4 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
__version__ = "1.10.0" __version__ = "1.10.1"

View File

@ -186,7 +186,7 @@ class CloudEvent(abstract.CloudEvent, BaseModel): # type: ignore
) )
attributes = {k.lower(): v for k, v in attributes.items()} attributes = {k.lower(): v for k, v in attributes.items()}
kwargs.update(attributes) kwargs.update(attributes)
super(CloudEvent, self).__init__(data=data, **kwargs) super().__init__(data=data, **kwargs)
class Config: class Config:
extra: str = "allow" # this is the way we implement extensions extra: str = "allow" # this is the way we implement extensions

View File

@ -134,7 +134,7 @@ class CloudEvent(abstract.CloudEvent, BaseModel): # type: ignore
) )
attributes = {k.lower(): v for k, v in attributes.items()} attributes = {k.lower(): v for k, v in attributes.items()}
kwargs.update(attributes) kwargs.update(attributes)
super(CloudEvent, self).__init__(data=data, **kwargs) super().__init__(data=data, **kwargs)
model_config = ConfigDict( model_config = ConfigDict(
extra="allow", # this is the way we implement extensions extra="allow", # this is the way we implement extensions
@ -209,7 +209,7 @@ class CloudEvent(abstract.CloudEvent, BaseModel): # type: ignore
def _get_attributes(self) -> typing.Dict[str, typing.Any]: def _get_attributes(self) -> typing.Dict[str, typing.Any]:
return { return {
key: conversion.best_effort_encode_attribute_value(value) key: conversion.best_effort_encode_attribute_value(value)
for key, value in self.__dict__.items() for key, value in dict(BaseModel.__iter__(self)).items()
if key not in ["data"] if key not in ["data"]
} }

View File

@ -33,9 +33,9 @@ test_data = json.dumps({"data-key": "val"})
test_attributes = { test_attributes = {
"type": "com.example.string", "type": "com.example.string",
"source": "https://example.com/event-producer", "source": "https://example.com/event-producer",
"extension-attribute": "extension-attribute-test-value",
} }
_pydantic_implementation = { _pydantic_implementation = {
"v1": { "v1": {
"event": PydanticV1CloudEvent, "event": PydanticV1CloudEvent,