Skip to content

Commit a0acdcf

Browse files
authored
Merge pull request #1 from denismakogon/initial-build
Initial release: CloudEvents Python SDK 0.0.1a0
2 parents 159332b + abe8b6f commit a0acdcf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+17214
-2
lines changed

.github/pull_request_template.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
- Link to issue this resolves
2+
3+
- What I did
4+
5+
- How I did it
6+
7+
- How to verify it
8+
9+
- One line description for the changelog

.gitignore

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
env/
12+
build/
13+
develop-eggs/
14+
dist/
15+
downloads/
16+
eggs/
17+
.eggs/
18+
lib/
19+
lib64/
20+
parts/
21+
sdist/
22+
var/
23+
wheels/
24+
*.egg-info/
25+
.installed.cfg
26+
*.egg
27+
28+
# PyInstaller
29+
# Usually these files are written by a python script from a template
30+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
31+
*.manifest
32+
*.spec
33+
34+
# Installer logs
35+
pip-log.txt
36+
pip-delete-this-directory.txt
37+
38+
# Unit test / coverage reports
39+
htmlcov/
40+
.tox/
41+
.coverage
42+
.coverage.*
43+
.cache
44+
nosetests.xml
45+
coverage.xml
46+
*.cover
47+
.hypothesis/
48+
49+
# Translations
50+
*.mo
51+
*.pot
52+
53+
# Django stuff:
54+
*.log
55+
local_settings.py
56+
57+
# Flask stuff:
58+
instance/
59+
.webassets-cache
60+
61+
# Scrapy stuff:
62+
.scrapy
63+
64+
# Sphinx documentation
65+
docs/_build/
66+
67+
# PyBuilder
68+
target/
69+
70+
# Jupyter Notebook
71+
.ipynb_checkpoints
72+
73+
# pyenv
74+
.python-version
75+
76+
# celery beat schedule file
77+
celerybeat-schedule
78+
79+
# SageMath parsed files
80+
*.sage.py
81+
82+
# dotenv
83+
.env
84+
85+
# virtualenv
86+
.venv
87+
venv/
88+
ENV/
89+
90+
# Spyder project settings
91+
.spyderproject
92+
.spyproject
93+
94+
# Rope project settings
95+
.ropeproject
96+
97+
# mkdocs documentation
98+
/site
99+
100+
# mypy
101+
.mypy_cache/
102+
*.pyc
103+
.testrepository
104+
.tox/*
105+
dist/*
106+
build/*
107+
html/*
108+
*.egg*
109+
cover/*
110+
.coverage
111+
rdserver.txt
112+
python-troveclient.iml
113+
114+
# Files created by releasenotes build
115+
releasenotes/build
116+
.coverage.*
117+
*.json
118+
.cache
119+
*.log*
120+
*.csv
121+
venv
122+
.venv
123+
ChangeLog
124+
AUTHORS
125+
.pytest_cache/

Makefile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Minimal makefile for Sphinx documentation
2+
#
3+
4+
# You can set these variables from the command line.
5+
SPHINXOPTS =
6+
SPHINXBUILD = sphinx-build
7+
SOURCEDIR = etc/docs_conf
8+
BUILDDIR = docs
9+
10+
# Put it first so that "make" without argument is like "make help".
11+
help:
12+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
13+
14+
.PHONY: help Makefile
15+
16+
# Catch-all target: route all unknown targets to Sphinx using the new
17+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
18+
%: Makefile
19+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

README.md

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,68 @@
1-
# sdk-python
2-
Python SDK for CloudEvents
1+
# Python SDK for [CloudEvents](https://github.com/cloudevents/spec)
2+
3+
**NOTE: This SDK is still considered work in progress, things might (and will) break with every update.**
4+
5+
Package **cloudevents** provides primitives to work with CloudEvents specification: https://github.com/cloudevents/spec.
6+
7+
Parsing upstream Event from HTTP Request:
8+
```python
9+
from cloudevents.sdk.event import upstream
10+
from cloudevents.sdk import marshaller
11+
12+
data = "<this is where your CloudEvent comes from>"
13+
m = marshaller.NewDefaultHTTPMarshaller(upstream.Event)
14+
event = m.FromRequest(
15+
{"Content-Type": "application/cloudevents+json"},
16+
data,
17+
lambda x: x.read()
18+
)
19+
20+
```
21+
22+
Creating a minimal CloudEvent in version 0.1:
23+
```python
24+
from cloudevents.sdk.event import v01
25+
26+
event = (
27+
v01.Event().
28+
WithContentType("application/json").
29+
WithData('{"name":"john"}').
30+
WithEventID("my-id").
31+
WithSource("from-galaxy-far-far-away").
32+
WithEventTime("tomorrow").
33+
WithEventType("cloudevent.greet.you")
34+
)
35+
36+
```
37+
38+
Creating HTTP request from CloudEvent:
39+
```python
40+
from cloudevents.sdk import converters
41+
from cloudevents.sdk import marshaller
42+
from cloudevents.sdk.converters import structured
43+
from cloudevents.sdk.event import v01
44+
45+
event = (
46+
v01.Event().
47+
WithContentType("application/json").
48+
WithData('{"name":"john"}').
49+
WithEventID("my-id").
50+
WithSource("from-galaxy-far-far-away").
51+
WithEventTime("tomorrow").
52+
WithEventType("cloudevent.greet.you")
53+
)
54+
m = marshaller.NewHTTPMarshaller(
55+
[
56+
structured.NewJSONHTTPCloudEventConverter(type(event))
57+
]
58+
)
59+
60+
headers, body = m.ToRequest(event, converters.TypeStructured, lambda x: x)
61+
62+
```
63+
64+
The goal of this package is to provide support for all released versions of CloudEvents, ideally while maintaining
65+
the same API. It will use semantic versioning with following rules:
66+
* MAJOR version increments when backwards incompatible changes is introduced.
67+
* MINOR version increments when backwards compatible feature is introduced INCLUDING support for new CloudEvents version.
68+
* PATCH version increments when a backwards compatible bug fix is introduced.

circle.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
version: 2
2+
jobs:
3+
build:
4+
docker:
5+
- image: circleci/python:3.7.0
6+
working_directory: ~/sdk-python
7+
steps:
8+
- checkout
9+
- restore_cache:
10+
key: deps1-{{ .Branch }}-{{ checksum "requirements.txt" }}
11+
- setup_remote_docker:
12+
docker_layer_caching: true
13+
- run:
14+
command: |
15+
python3 -m venv venv
16+
. venv/bin/activate
17+
pip install tox
18+
pip install -r requirements.txt
19+
- save_cache:
20+
key: deps1-{{ .Branch }}-{{ checksum "requirements.txt" }}
21+
paths:
22+
- "venv"
23+
- run:
24+
command: |
25+
. venv/bin/activate
26+
tox -epep8
27+
- run:
28+
command: |
29+
. venv/bin/activate
30+
tox -epy3.7

cloudevents/__init__.py

Whitespace-only changes.

cloudevents/sdk/__init__.py

Whitespace-only changes.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
from cloudevents.sdk.converters import binary
16+
from cloudevents.sdk.converters import structured
17+
18+
TypeBinary = binary.BinaryHTTPCloudEventConverter.TYPE
19+
TypeStructured = structured.JSONHTTPCloudEventConverter.TYPE

cloudevents/sdk/converters/base.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
import typing
16+
17+
from cloudevents.sdk.event import base
18+
19+
20+
class Converter(object):
21+
22+
TYPE = None
23+
24+
def __init__(
25+
self, event_class: base.BaseEvent,
26+
supported_media_types: typing.Mapping[str, bool]):
27+
self.event = event_class()
28+
self.supported_media_types = supported_media_types
29+
30+
def can_read(self, media_type: str) -> bool:
31+
return media_type in self.supported_media_types
32+
33+
def read(self, headers: dict, body: typing.IO,
34+
data_unmarshaller: typing.Callable) -> base.BaseEvent:
35+
raise Exception("not implemented")
36+
37+
def write(self, event: base.BaseEvent,
38+
data_marshaller: typing.Callable) -> (dict, typing.IO):
39+
raise Exception("not implemented")

cloudevents/sdk/converters/binary.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4+
# not use this file except in compliance with the License. You may obtain
5+
# a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12+
# License for the specific language governing permissions and limitations
13+
# under the License.
14+
15+
import typing
16+
17+
from cloudevents.sdk import exceptions
18+
from cloudevents.sdk.converters import base
19+
from cloudevents.sdk.event import base as event_base
20+
from cloudevents.sdk.event import v01
21+
22+
23+
class BinaryHTTPCloudEventConverter(base.Converter):
24+
25+
TYPE = "binary"
26+
27+
def __init__(self, event_class: event_base.BaseEvent,
28+
supported_media_types: typing.Mapping[str, bool]):
29+
if event_class == v01.Event:
30+
raise exceptions.UnsupportedEvent(event_class)
31+
32+
super().__init__(event_class, supported_media_types)
33+
34+
def read(self,
35+
headers: dict, body: typing.IO,
36+
data_unmarshaller: typing.Callable) -> event_base.BaseEvent:
37+
# we ignore headers, since the whole CE is in request body
38+
event = self.event
39+
event.UnmarshalBinary(headers, body, data_unmarshaller)
40+
return event
41+
42+
def write(self, event: event_base.BaseEvent,
43+
data_marshaller: typing.Callable) -> (dict, typing.IO):
44+
if not isinstance(data_marshaller, typing.Callable):
45+
raise exceptions.InvalidDataMarshaller()
46+
47+
hs, data = event.MarshalBinary()
48+
return hs, data_marshaller(data)
49+
50+
51+
def NewBinaryHTTPCloudEventConverter(
52+
event_class: event_base.BaseEvent) -> BinaryHTTPCloudEventConverter:
53+
media_types = {
54+
"application/json": True,
55+
"application/xml": True,
56+
"application/octet-stream": True,
57+
}
58+
return BinaryHTTPCloudEventConverter(event_class, media_types)

0 commit comments

Comments
 (0)