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

Specversion changelog adjustment with clean history #53

Closed
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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ 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).

## [1.0.0]
### Added
- Added a user friendly CloudEvent class with data validation ([#36])
- CloudEvent structured cloudevent support ([#47])

### Removed
- Removed support for Cloudevents V0.2 and V0.1 ([#43])

## [0.3.0]
### Added
- Added Cloudevents V0.3 and V1 implementations ([#22])
Expand Down Expand Up @@ -66,3 +74,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#23]: https://github.com/cloudevents/sdk-python/pull/23
[#25]: https://github.com/cloudevents/sdk-python/pull/25
[#27]: https://github.com/cloudevents/sdk-python/pull/27
[#36]: https://github.com/cloudevents/sdk-python/pull/36
[#43]: https://github.com/cloudevents/sdk-python/pull/43
[#47]: https://github.com/cloudevents/sdk-python/pull/47
67 changes: 51 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,57 @@ This SDK current supports the following versions of CloudEvents:

Package **cloudevents** provides primitives to work with CloudEvents specification: https://github.com/cloudevents/spec.

Sending CloudEvents:

### Binary HTTP CloudEvent

```python
from cloudevents.sdk.http_events import CloudEvent
import requests


# This data defines a binary cloudevent
headers = {
"Content-Type": "application/json",
"ce-specversion": "1.0",
"ce-type": "README.sample.binary",
"ce-id": "binary-event",
"ce-time": "2018-10-23T12:28:22.4579346Z",
"ce-source": "README",
}
data = {"message": "Hello World!"}

event = CloudEvent(data, headers=headers)
headers, body = event.to_request()

# POST
requests.post("<some-url>", json=body, headers=headers)
```

### Structured HTTP CloudEvent

```python
from cloudevents.sdk.http_events import CloudEvent
import requests


# This data defines a structured cloudevent
data = {
"specversion": "1.0",
"type": "README.sample.structured",
"id": "structured-event",
"source": "README",
"data": {"message": "Hello World!"}
}
event = CloudEvent(data)
headers, body = event.to_request()

# POST
requests.post("<some-url>", json=body, headers=headers)
```

### Event base classes usage

Parsing upstream structured Event from HTTP request:

```python
Expand Down Expand Up @@ -68,22 +119,6 @@ event = m.FromRequest(
)
```

Creating a minimal CloudEvent in version 0.1:

```python
from cloudevents.sdk.event import v1

event = (
v1.Event()
.SetContentType("application/json")
.SetData('{"name":"john"}')
.SetEventID("my-id")
.SetSource("from-galaxy-far-far-away")
.SetEventTime("tomorrow")
.SetEventType("cloudevent.greet.you")
)
```

Creating HTTP request from CloudEvent:

```python
Expand Down
119 changes: 99 additions & 20 deletions cloudevents/sdk/event/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,61 +20,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 @@ -105,7 +185,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 All @@ -117,6 +196,7 @@ def MarshalJSON(self, data_marshaller: typing.Callable) -> typing.IO:

def UnmarshalJSON(self, b: typing.IO, data_unmarshaller: typing.Callable):
raw_ce = json.load(b)

for name, value in raw_ce.items():
if name == "data":
value = data_unmarshaller(value)
Expand All @@ -134,7 +214,6 @@ def UnmarshalBinary(
self.SetContentType(value)
elif header.startswith("ce-"):
self.Set(header[3:], value)

self.Set("data", data_unmarshaller(body))

def MarshalBinary(
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
23 changes: 23 additions & 0 deletions cloudevents/sdk/event/v03.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@


class Event(base.BaseEvent):
_ce_required_fields = {
'id',
'source',
'type',
'specversion'
}

_ce_optional_fields = {
'datacontentencoding',
'datacontenttype',
'schemaurl',
'subject',
'time'
}

def __init__(self):
self.ce__specversion = opt.Option("specversion", "0.3", True)
self.ce__id = opt.Option("id", None, True)
Expand Down Expand Up @@ -68,6 +83,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 +126,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)
14 changes: 14 additions & 0 deletions cloudevents/sdk/event/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,20 @@


class Event(base.BaseEvent):
_ce_required_fields = {
'id',
'source',
'type',
'specversion'
}

_ce_optional_fields = {
'datacontenttype',
'dataschema',
'subject',
'time'
}

def __init__(self):
self.ce__specversion = opt.Option("specversion", "1.0", True)
self.ce__id = opt.Option("id", None, True)
Expand Down
Loading