Skip to content

Readme overhaul #55

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

Closed
wants to merge 9 commits into from
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
4 changes: 4 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[settings]
line_length = 80
multi_line_output = 3
include_trailing_comma = True
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
repos:
- repo: https://github.com/timothycrosley/isort/
rev: 5.0.4
hooks:
- id: isort
- repo: https://github.com/psf/black
rev: 19.10b0
hooks:
- id: black
language_version: python3.8
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
201 changes: 74 additions & 127 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,159 +14,95 @@ This SDK current supports the following versions of CloudEvents:

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

Parsing upstream structured Event from HTTP request:
## Sending CloudEvents:

```python
import io

from cloudevents.sdk.event import v1
from cloudevents.sdk import marshaller

m = marshaller.NewDefaultHTTPMarshaller()

event = m.FromRequest(
v1.Event(),
{"content-type": "application/cloudevents+json"},
io.StringIO(
"""
{
"specversion": "1.0",
"datacontenttype": "application/json",
"type": "word.found.name",
"id": "96fb5f0b-001e-0108-6dfe-da6e2806f124",
"time": "2018-10-23T12:28:22.4579346Z",
"source": "<source-url>"
}
"""
),
lambda x: x.read(),
)
```
Below we will provide samples on how to send cloudevents using the popular
[`requests`](http://docs.python-requests.org/en/master/) library.

Parsing upstream binary Event from HTTP request:
### Binary HTTP CloudEvent

```python
import io

from cloudevents.sdk.event import v1
from cloudevents.sdk import marshaller

m = marshaller.NewDefaultHTTPMarshaller()

event = m.FromRequest(
v1.Event(),
{
"ce-specversion": "1.0",
"content-type": "application/json",
"ce-type": "word.found.name",
"ce-id": "96fb5f0b-001e-0108-6dfe-da6e2806f124",
"ce-time": "2018-10-23T12:28:22.4579346Z",
"ce-source": "<source-url>",
},
io.BytesIO(b"this is where your CloudEvent data"),
lambda x: x.read(),
)
```
from cloudevents.sdk import converters
from cloudevents.sdk.http_events import CloudEvent
import requests

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")
)
# This data defines a binary cloudevent
attributes = {
"Content-Type": "application/json",
"type": "com.readme.binary",
"id": "A234-1234-1234",
"source": "/mycontext",
}
data = {"message": "Hello World!"}

event = CloudEvent(attributes, data)
headers, body = event.to_http(converters.TypeBinary)

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

Creating HTTP request from CloudEvent:
### Structured HTTP CloudEvent

```python
from cloudevents.sdk import converters
from cloudevents.sdk import marshaller
from cloudevents.sdk.converters import structured
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")
)

m = marshaller.NewHTTPMarshaller([structured.NewJSONHTTPCloudEventConverter()])

headers, body = m.ToRequest(event, converters.TypeStructured, lambda x: x)
from cloudevents.sdk.http_events import CloudEvent
import requests


# This data defines a structured cloudevent
attributes = {
"type": "com.readme.structured",
"id": "B234-1234-1234",
"source": "/mycontext",
}
data = {"message": "Hello World!"}
event = CloudEvent(attributes, data)
headers, body = event.to_http()

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

## HOWTOs with various Python HTTP frameworks
You can find a complete example of turning a CloudEvent into a HTTP request [here](samples/http-cloudevents/client.py).

#### Request to CloudEvent

In this topic you'd find various example how to integrate an SDK with various HTTP frameworks.
The code below shows how to consume a cloudevent using the popular python web framework
[flask](https://flask.palletsprojects.com/en/1.1.x/quickstart/):

### Python requests
```python
from flask import Flask, request

One of popular framework is [`requests`](http://docs.python-requests.org/en/master/).
from cloudevents.sdk.http_events import CloudEvent

#### CloudEvent to request
app = Flask(__name__)

The code below shows how integrate both libraries in order to convert a CloudEvent into an HTTP request:

```python
def run_binary(event, url):
binary_headers, binary_data = http_marshaller.ToRequest(
event, converters.TypeBinary, json.dumps)

print("binary CloudEvent")
for k, v in binary_headers.items():
print("{0}: {1}\r\n".format(k, v))
print(binary_data.getvalue())
response = requests.post(url,
headers=binary_headers,
data=binary_data.getvalue())
response.raise_for_status()


def run_structured(event, url):
structured_headers, structured_data = http_marshaller.ToRequest(
event, converters.TypeStructured, json.dumps
)
print("structured CloudEvent")
print(structured_data.getvalue())

response = requests.post(url,
headers=structured_headers,
data=structured_data.getvalue())
response.raise_for_status()
# create an endpoint at http://localhost:/3000/
@app.route("/", methods=["POST"])
def home():
# create a CloudEvent
event = CloudEvent.from_http(request.get_data(), request.headers)

```
# you can access cloudevent fields as seen below
assert event['specversion'] == "1.0"
print(f"Found CloudEvent from {event['source']}")

Complete example of turning a CloudEvent into a request you can find [here](samples/python-requests/cloudevent_to_request.py).
if event['type'] == 'com.readme.binary':
print(f"CloudEvent {event['id']} is binary")

#### Request to CloudEvent
elif event['type'] == 'com.readme.structured':
print(f"CloudEvent {event['id']} is structured")

The code below shows how integrate both libraries in order to create a CloudEvent from an HTTP request:
return "", 204

```python
response = requests.get(url)
response.raise_for_status()
headers = response.headers
data = io.BytesIO(response.content)
event = v1.Event()
http_marshaller = marshaller.NewDefaultHTTPMarshaller()
event = http_marshaller.FromRequest(
event, headers, data, json.load)

if __name__ == "__main__":
app.run(port=3000)
```

Complete example of turning a CloudEvent into a request you can find [here](samples/python-requests/request_to_cloudevent.py).
You can find a complete example of turning a CloudEvent into a request [here](samples/http-cloudevents/server.py).

## SDK versioning

Expand All @@ -189,3 +125,14 @@ the same API. It will use semantic versioning with following rules:
[CNCF's Slack workspace](https://slack.cncf.io/).
- Email: https://lists.cncf.io/g/cncf-cloudevents-sdk
- Contact for additional information: Denis Makogon (`@denysmakogon` on slack).

## Maintenance

We use black and isort for autoformatting. We setup a tox environment to reformat
the codebase.

e.g.
```python
pip install tox
tox -e reformat
```
3 changes: 1 addition & 2 deletions cloudevents/sdk/converters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.

from cloudevents.sdk.converters import binary
from cloudevents.sdk.converters import structured
from cloudevents.sdk.converters import binary, structured

TypeBinary = binary.BinaryHTTPCloudEventConverter.TYPE
TypeStructured = structured.JSONHTTPCloudEventConverter.TYPE
6 changes: 2 additions & 4 deletions cloudevents/sdk/converters/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def read(
event,
headers: dict,
body: typing.IO,
data_unmarshaller: typing.Callable
data_unmarshaller: typing.Callable,
) -> base.BaseEvent:
raise Exception("not implemented")

Expand All @@ -37,8 +37,6 @@ def can_read(self, content_type: str) -> bool:
raise Exception("not implemented")

def write(
self,
event: base.BaseEvent,
data_marshaller: typing.Callable
self, event: base.BaseEvent, data_marshaller: typing.Callable
) -> (dict, object):
raise Exception("not implemented")
10 changes: 5 additions & 5 deletions cloudevents/sdk/converters/binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@

import typing

from cloudevents.sdk import exceptions
from cloudevents.sdk import exceptions, types
from cloudevents.sdk.converters import base
from cloudevents.sdk.event import base as event_base
from cloudevents.sdk.event import v03, v1
from cloudevents.sdk.event import v1, v03


class BinaryHTTPCloudEventConverter(base.Converter):
Expand All @@ -36,16 +36,16 @@ def read(
event: event_base.BaseEvent,
headers: dict,
body: typing.IO,
data_unmarshaller: typing.Callable,
data_unmarshaller: types.UnmarshallerType,
) -> event_base.BaseEvent:
if type(event) not in self.SUPPORTED_VERSIONS:
raise exceptions.UnsupportedEvent(type(event))
event.UnmarshalBinary(headers, body, data_unmarshaller)
return event

def write(
self, event: event_base.BaseEvent, data_marshaller: typing.Callable
) -> (dict, typing.IO):
self, event: event_base.BaseEvent, data_marshaller: types.MarshallerType
) -> (dict, bytes):
return event.MarshalBinary(data_marshaller)


Expand Down
9 changes: 5 additions & 4 deletions cloudevents/sdk/converters/structured.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import typing

from cloudevents.sdk import types
from cloudevents.sdk.converters import base
from cloudevents.sdk.event import base as event_base

Expand All @@ -35,16 +36,16 @@ def read(
event: event_base.BaseEvent,
headers: dict,
body: typing.IO,
data_unmarshaller: typing.Callable,
data_unmarshaller: types.UnmarshallerType,
) -> event_base.BaseEvent:
event.UnmarshalJSON(body, data_unmarshaller)
return event

def write(
self, event: event_base.BaseEvent, data_marshaller: typing.Callable
) -> (dict, typing.IO):
self, event: event_base.BaseEvent, data_marshaller: types.MarshallerType
) -> (dict, bytes):
http_headers = {"content-type": self.MIME_TYPE}
return http_headers, event.MarshalJSON(data_marshaller)
return http_headers, event.MarshalJSON(data_marshaller).encode("utf-8")


def NewJSONHTTPCloudEventConverter() -> JSONHTTPCloudEventConverter:
Expand Down
Loading