chore: Add copyright and fix missing type info

Signed-off-by: Tudor Plugaru <plugaru.tudor@protonmail.com>
This commit is contained in:
Tudor Plugaru 2024-11-09 21:48:03 +02:00
parent 35dee7d2c1
commit 42b4fe1d3a
No known key found for this signature in database
5 changed files with 87 additions and 28 deletions

View File

@ -1,3 +1,17 @@
# Copyright 2018-Present The CloudEvents Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
""" """
CloudEvent implementation for v1.0 CloudEvent implementation for v1.0
""" """

View File

@ -12,34 +12,48 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from typing import Any, Optional from typing import Any, Optional, Final
from datetime import datetime from datetime import datetime
import re import re
REQUIRED_ATTRIBUTES = {"id", "source", "type", "specversion"} REQUIRED_ATTRIBUTES: Final[set[str]] = {"id", "source", "type", "specversion"}
OPTIONAL_ATTRIBUTES = {"datacontenttype", "dataschema", "subject", "time"} OPTIONAL_ATTRIBUTES: Final[set[str]] = {
"datacontenttype",
"dataschema",
"subject",
"time",
}
class CloudEvent: class CloudEvent:
def __init__(self, attributes: dict, data: Optional[dict] = None) -> None: """
The CloudEvent Python wrapper contract exposing generically-available
properties and APIs.
Implementations might handle fields and have other APIs exposed but are
obliged to follow this contract.
"""
def __init__(self, attributes: dict[str, Any], data: Optional[dict] = None) -> None:
""" """
Create a new CloudEvent instance. Create a new CloudEvent instance.
:param attributes: The attributes of the CloudEvent instance. :param attributes: The attributes of the CloudEvent instance.
:type attributes: dict
:param data: The payload of the CloudEvent instance. :param data: The payload of the CloudEvent instance.
:type data: Optional[dict]
:raises ValueError: If any of the required attributes are missing or have invalid values. :raises ValueError: If any of the required attributes are missing or have invalid values.
:raises TypeError: If any of the attributes have invalid types. :raises TypeError: If any of the attributes have invalid types.
""" """
self._validate_attribute(attributes) self._validate_attribute(attributes)
self._attributes = attributes self._attributes: dict = attributes
self._data = data self._data: Optional[dict] = data
def _validate_attribute(self, attributes: dict) -> None: @staticmethod
def _validate_attribute(attributes: dict) -> None:
""" """
Private method that validates the attributes of the CloudEvent as per the CloudEvents specification. Validates the attributes of the CloudEvent as per the CloudEvents specification.
See https://github.com/cloudevents/spec/blob/main/cloudevents/spec.md#required-attributes
""" """
missing_attributes = [ missing_attributes = [
attr for attr in REQUIRED_ATTRIBUTES if attr not in attributes attr for attr in REQUIRED_ATTRIBUTES if attr not in attributes
@ -95,27 +109,22 @@ class CloudEvent:
if not attributes["dataschema"]: if not attributes["dataschema"]:
raise ValueError("Attribute 'dataschema' must not be empty") raise ValueError("Attribute 'dataschema' must not be empty")
for custom_extension in ( for extension_attributes in (
set(attributes.keys()) - REQUIRED_ATTRIBUTES - OPTIONAL_ATTRIBUTES set(attributes.keys()) - REQUIRED_ATTRIBUTES - OPTIONAL_ATTRIBUTES
): ):
if custom_extension == "data": if extension_attributes == "data":
raise ValueError( raise ValueError(
"Extension attribute 'data' is reserved and must not be used" "Extension attribute 'data' is reserved and must not be used"
) )
if not custom_extension[0].isalpha(): if not (1 <= len(extension_attributes) <= 20):
raise ValueError( raise ValueError(
f"Extension attribute '{custom_extension}' should start with a letter" f"Extension attribute '{extension_attributes}' should be between 1 and 20 characters long"
) )
if not (5 <= len(custom_extension) <= 20): if not re.match(r"^[a-z0-9]+$", extension_attributes):
raise ValueError( raise ValueError(
f"Extension attribute '{custom_extension}' should be between 5 and 20 characters long" f"Extension attribute '{extension_attributes}' should only contain lowercase letters and numbers"
)
if not re.match(r"^[a-z0-9]+$", custom_extension):
raise ValueError(
f"Extension attribute '{custom_extension}' should only contain lowercase letters and numbers"
) )
def get_attribute(self, attribute: str) -> Optional[Any]: def get_attribute(self, attribute: str) -> Optional[Any]:
@ -123,10 +132,8 @@ class CloudEvent:
Retrieve a value of an attribute of the event denoted by the given `attribute`. Retrieve a value of an attribute of the event denoted by the given `attribute`.
:param attribute: The name of the event attribute to retrieve the value for. :param attribute: The name of the event attribute to retrieve the value for.
:type attribute: str
:return: The event attribute value. :return: The event attribute value.
:rtype: Optional[Any]
""" """
return self._attributes[attribute] return self._attributes[attribute]
@ -135,6 +142,5 @@ class CloudEvent:
Retrieve data of the event. Retrieve data of the event.
:return: The data of the event. :return: The data of the event.
:rtype: Optional[dict]
""" """
return self._data return self._data

View File

@ -0,0 +1,13 @@
# Copyright 2018-Present The CloudEvents Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

View File

@ -0,0 +1,13 @@
# Copyright 2018-Present The CloudEvents Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

View File

@ -1,3 +1,17 @@
# Copyright 2018-Present The CloudEvents Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from cloudevents.core.v1.event import CloudEvent from cloudevents.core.v1.event import CloudEvent
import pytest import pytest
@ -162,14 +176,13 @@ def test_dataschema_validation(dataschema: Any, error: str) -> None:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"extension_name,error", "extension_name,error",
[ [
("123", "Extension attribute '123' should start with a letter"),
( (
"shrt", "",
"Extension attribute 'shrt' should be between 5 and 20 characters long", "Extension attribute '' should be between 1 and 20 characters long",
), ),
( (
"thisisaverylongextension", "thisisaverylongextension",
"Extension attribute 'thisisaverylongextension' should be between 5 and 20 characters long", "Extension attribute 'thisisaverylongextension' should be between 1 and 20 characters long",
), ),
( (
"ThisIsNotValid", "ThisIsNotValid",