Skip to content

Commit

Permalink
Implemented python properties in base.py (cloudevents#41)
Browse files Browse the repository at this point in the history
* Added SetCloudEventVersion

Signed-off-by: Curtis Mason <cumason@google.com>
Signed-off-by: Dustin Ingram <di@users.noreply.github.com>

* began adding python properties

Signed-off-by: Curtis Mason <cumason@google.com>
Signed-off-by: Dustin Ingram <di@users.noreply.github.com>

* added pythonic properties to base class

Signed-off-by: Curtis Mason <cumason@google.com>
Signed-off-by: Dustin Ingram <di@users.noreply.github.com>

* began testing for getters/setters

Signed-off-by: Curtis Mason <cumason@google.com>
Signed-off-by: Dustin Ingram <di@users.noreply.github.com>

* added general setter tests

Signed-off-by: Curtis Mason <cumason@google.com>
Signed-off-by: Dustin Ingram <di@users.noreply.github.com>

* fixed spacing in base.py

Signed-off-by: Curtis Mason <cumason@google.com>
Signed-off-by: Dustin Ingram <di@users.noreply.github.com>

* added __eq__ to option and datacontentencoding property to v03

Signed-off-by: Curtis Mason <cumason@google.com>
Signed-off-by: Dustin Ingram <di@users.noreply.github.com>

* lint fixes

Signed-off-by: Curtis Mason <cumason@google.com>
Signed-off-by: Dustin Ingram <di@users.noreply.github.com>

* testing extensions and old getters

Signed-off-by: Curtis Mason <cumason@google.com>
Signed-off-by: Dustin Ingram <di@users.noreply.github.com>

* removed versions v01 and v02 from test_data_encaps_refs.py

Signed-off-by: Curtis Mason <cumason@google.com>
Signed-off-by: Dustin Ingram <di@users.noreply.github.com>

* fixed inheritance issue in CloudEvent

Signed-off-by: Curtis Mason <cumason@google.com>

* added prefixed_headers dict to test

Signed-off-by: Curtis Mason <cumason@google.com>
  • Loading branch information
cumason123 authored and Curtis Mason committed Jul 22, 2020
1 parent 30931df commit d73731e
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 24 deletions.
117 changes: 98 additions & 19 deletions cloudevents/sdk/event/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,61 +35,141 @@
# TODO(slinkydeveloper) is this really needed?
class EventGetterSetter(object):

# ce-specversion
def CloudEventVersion(self) -> str:
raise Exception("not implemented")

# CloudEvent attribute getters
def EventType(self) -> str:
raise Exception("not implemented")
@property
def specversion(self):
return self.CloudEventVersion()

def Source(self) -> str:
def SetCloudEventVersion(self, specversion: str) -> object:
raise Exception("not implemented")

def EventID(self) -> str:
raise Exception("not implemented")
@specversion.setter
def specversion(self, value: str):
self.SetCloudEventVersion(value)

def EventTime(self) -> str:
# ce-type
def EventType(self) -> str:
raise Exception("not implemented")

def SchemaURL(self) -> str:
raise Exception("not implemented")
@property
def type(self):
return self.EventType()

def Data(self) -> object:
def SetEventType(self, eventType: str) -> object:
raise Exception("not implemented")

def Extensions(self) -> dict:
raise Exception("not implemented")
@type.setter
def type(self, value: str):
self.SetEventType(value)

def ContentType(self) -> str:
# ce-source
def Source(self) -> str:
raise Exception("not implemented")

# CloudEvent attribute constructors
# Each setter return an instance of its class
# in order to build a pipeline of setter
def SetEventType(self, eventType: str) -> object:
raise Exception("not implemented")
@property
def source(self):
return self.Source()

def SetSource(self, source: str) -> object:
raise Exception("not implemented")

@source.setter
def source(self, value: str):
self.SetSource(value)

# ce-id
def EventID(self) -> str:
raise Exception("not implemented")

@property
def id(self):
return self.EventID()

def SetEventID(self, eventID: str) -> object:
raise Exception("not implemented")

@id.setter
def id(self, value: str):
self.SetEventID(value)

# ce-time
def EventTime(self) -> str:
raise Exception("not implemented")

@property
def time(self):
return self.EventTime()

def SetEventTime(self, eventTime: str) -> object:
raise Exception("not implemented")

@time.setter
def time(self, value: str):
self.SetEventTime(value)

# ce-schema
def SchemaURL(self) -> str:
raise Exception("not implemented")

@property
def schema(self) -> str:
return self.SchemaURL()

def SetSchemaURL(self, schemaURL: str) -> object:
raise Exception("not implemented")

@schema.setter
def schema(self, value: str):
self.SetSchemaURL(value)

# data
def Data(self) -> object:
raise Exception("not implemented")

@property
def data(self) -> object:
return self.Data()

def SetData(self, data: object) -> object:
raise Exception("not implemented")

@data.setter
def data(self, value: object):
self.SetData(value)

# ce-extensions
def Extensions(self) -> dict:
raise Exception("not implemented")

@property
def extensions(self) -> dict:
return self.Extensions()

def SetExtensions(self, extensions: dict) -> object:
raise Exception("not implemented")

@extensions.setter
def extensions(self, value: dict):
self.SetExtensions(value)

# Content-Type
def ContentType(self) -> str:
raise Exception("not implemented")

@property
def content_type(self) -> str:
return self.ContentType()

def SetContentType(self, contentType: str) -> object:
raise Exception("not implemented")

@content_type.setter
def content_type(self, value: str):
self.SetContentType(value)


class BaseEvent(EventGetterSetter):
def Properties(self, with_nullable=False) -> dict:
Expand Down Expand Up @@ -120,7 +200,6 @@ def Set(self, key: str, value: object):
attr.set(value)
setattr(self, formatted_key, attr)
return

exts = self.Extensions()
exts.update({key: value})
self.Set("extensions", exts)
Expand Down
6 changes: 6 additions & 0 deletions cloudevents/sdk/event/opt.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,9 @@ def get(self):

def required(self):
return self.is_required

def __eq__(self, obj):
return isinstance(obj, Option) and \
obj.name == self.name and \
obj.value == self.value and \
obj.is_required == self.is_required
8 changes: 8 additions & 0 deletions cloudevents/sdk/event/v03.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ def ContentType(self) -> str:
def ContentEncoding(self) -> str:
return self.ce__datacontentencoding.get()

@property
def datacontentencoding(self):
return self.ContentEncoding()

def SetEventType(self, eventType: str) -> base.BaseEvent:
self.Set("type", eventType)
return self
Expand Down Expand Up @@ -107,3 +111,7 @@ def SetContentType(self, contentType: str) -> base.BaseEvent:
def SetContentEncoding(self, contentEncoding: str) -> base.BaseEvent:
self.Set("datacontentencoding", contentEncoding)
return self

@datacontentencoding.setter
def datacontentencoding(self, value: str):
self.SetContentEncoding(value)
2 changes: 1 addition & 1 deletion cloudevents/sdk/http_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from cloudevents.sdk.event import v03, v1


class CloudEvent(base.BaseEvent):
class CloudEvent():
"""
Python-friendly cloudevent class supporting v1 events
Currently only supports binary content mode CloudEvents
Expand Down
114 changes: 114 additions & 0 deletions cloudevents/tests/test_data_encaps_refs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# All Rights Reserved.
#
# 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.

import io
import json
import copy
import pytest

from uuid import uuid4

from cloudevents.sdk import converters
from cloudevents.sdk import marshaller

from cloudevents.sdk.converters import structured
from cloudevents.sdk.event import v03, v1


from cloudevents.tests import data


@pytest.mark.parametrize("event_class", [ v03.Event, v1.Event])
def test_general_binary_properties(event_class):
m = marshaller.NewDefaultHTTPMarshaller()
event = m.FromRequest(
event_class(),
{"Content-Type": "application/cloudevents+json"},
io.StringIO(json.dumps(data.json_ce[event_class])),
lambda x: x.read(),
)

new_headers, _ = m.ToRequest(event, converters.TypeBinary, lambda x: x)
assert new_headers is not None
assert "ce-specversion" in new_headers

# Test properties
assert event is not None
assert event.type == data.ce_type
assert event.id == data.ce_id
assert event.content_type == data.contentType
assert event.source == data.source

# Test setters
new_type = str(uuid4())
new_id = str(uuid4())
new_content_type = str(uuid4())
new_source = str(uuid4())

event.extensions = {'test': str(uuid4)}
event.type = new_type
event.id = new_id
event.content_type = new_content_type
event.source = new_source

assert event is not None
assert (event.type == new_type) and (event.type == event.EventType())
assert (event.id == new_id) and (event.id == event.EventID())
assert (event.content_type == new_content_type) and (event.content_type == event.ContentType())
assert (event.source == new_source) and (event.source == event.Source())
assert event.extensions['test'] == event.Extensions()['test']
assert (event.specversion == event.CloudEventVersion())


@pytest.mark.parametrize("event_class", [v03.Event, v1.Event])
def test_general_structured_properties(event_class):
copy_of_ce = copy.deepcopy(data.json_ce[event_class])
m = marshaller.NewDefaultHTTPMarshaller()
http_headers = {"content-type": "application/cloudevents+json"}
event = m.FromRequest(
event_class(), http_headers, io.StringIO(json.dumps(data.json_ce[event_class])), lambda x: x.read()
)
# Test python properties
assert event is not None
assert event.type == data.ce_type
assert event.id == data.ce_id
assert event.content_type == data.contentType
assert event.source == data.source

new_headers, _ = m.ToRequest(event, converters.TypeStructured, lambda x: x)
for key in new_headers:
if key == "content-type":
assert new_headers[key] == http_headers[key]
continue
assert key in copy_of_ce

# Test setters
new_type = str(uuid4())
new_id = str(uuid4())
new_content_type = str(uuid4())
new_source = str(uuid4())

event.extensions = {'test': str(uuid4)}
event.type = new_type
event.id = new_id
event.content_type = new_content_type
event.source = new_source

assert event is not None
assert (event.type == new_type) and (event.type == event.EventType())
assert (event.id == new_id) and (event.id == event.EventID())
assert (event.content_type == new_content_type) and (event.content_type == event.ContentType())
assert (event.source == new_source) and (event.source == event.Source())
assert event.extensions['test'] == event.Extensions()['test']
assert (event.specversion == event.CloudEventVersion())
9 changes: 5 additions & 4 deletions cloudevents/tests/test_http_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,23 +101,24 @@ def test_emit_binary_event(specversion):

@pytest.mark.parametrize("specversion", ['1.0', '0.3'])
def test_missing_ce_prefix_binary_event(specversion):
prefixed_headers = {}
headers = {
"ce-id": "my-id",
"ce-source": "<event-source>",
"ce-type": "cloudevent.event.type",
"ce-specversion": specversion
}
for key in headers:
val = headers.pop(key)


# breaking prefix e.g. e-id instead of ce-id
headers[key[1:]] = val
prefixed_headers[key[1:]] = headers[key]

with pytest.raises((TypeError, NotImplementedError)):
# CloudEvent constructor throws TypeError if missing required field
# and NotImplementedError because structured calls aren't
# implemented. In this instance one of the required keys should have
# prefix e-id instead of ce-id therefore it should throw
_ = CloudEvent(headers, test_data)
_ = CloudEvent(prefixed_headers, test_data)


@pytest.mark.parametrize("specversion", ['1.0', '0.3'])
Expand Down

0 comments on commit d73731e

Please sign in to comment.