You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi all, first: thanks for providing this library. It's going to be really useful to have a standard way to work with CloudEvents from Python.
I took a preliminary look at it and my first impression was that the interface provided by this library isn't very "Pythonic", meaning that it doesn't provide an interface in a way that (I believe) would be expected by most Python developers. There are some small things (like using method names like FromRequest instead of from_request, using New in class/method names) but also larger things (like the use of method chaining, setters/getters, etc.)
I'm hoping that since this project is still in alpha, there's still time to improve the interface here (and that y'all are open to suggestions). I'll try to provide some examples below of what I'm talking about but I'm happy to clarify if anything's unclear. I'm also not intimately familiar with the CloudEvents spec, so I may have some misunderstandings as well.
Parsing upstream Event from HTTP Request
The current example for turning an HTTP request into an event:
importiofromcloudevents.sdk.eventimportv02fromcloudevents.sdkimportmarshallerm=marshaller.NewDefaultHTTPMarshaller()
event=m.FromRequest(
v02.Event(),
{
"content-type": "application/cloudevents+json",
"ce-specversion": "0.2",
"ce-time": "2018-10-23T12:28:22.4579346Z",
"ce-id": "96fb5f0b-001e-0108-6dfe-da6e2806f124",
"ce-source": "<source-url>",
"ce-type": "word.found.name",
},
io.BytesIO(b"this is where your CloudEvent data"),
lambdax: x.read()
)
This makes the assumption that the user is only interested in supporting a single spec, but I think it's possible that either they would want to support multiple versions (and automatically detect which one is being used), or be able to upgrade to newer versions of the spec (and this module) without having to change their code.
There's only one type of marshaller provided by the library right now, HTTPMarshaller, and if it's the default maybe we should just get it by default when creating an Event, instead of making the user initialize it every time?
The data_unmarshaller is maybe not necessary? We're taking a bytestring, turning it into a BytesIO object to pass as data, and then using data_unmarshaller to turn it back into a bytestring. Why not just have the user do any data unmarshalling themselves before constructing the event?
Instead, consider:
fromcloudevents.sdkimportEventevent=Event(
headers={
"content-type": "application/cloudevents+json",
"ce-specversion": "0.2",
"ce-time": "2018-10-23T12:28:22.4579346Z",
"ce-id": "96fb5f0b-001e-0108-6dfe-da6e2806f124",
"ce-source": "<source-url>",
"ce-type": "word.found.name",
},
body=b"this is where your CloudEvent data",
)
This initializes a generic Event, detects which spec it matches, and gives back a corresponding Event subclass. (If the user knew which spec they were supporting, instead of constructing an Event they could construct a v02.Event and skip the event detection)
Similar to above, the user has to specify the exact event type they're expecting
Method chaining / fluent API: while this pattern is used by some Python libraries (pandas, various ORMs) it's not typical for the majority of Python libraries and generally not recommended.
Instead, consider the following based on the same Event class proposed above:
The spec is automatically determined, but the user can also use a specific subclass if they prefer.
The constructor uses keyword arguments, so that an Event object can be created with a single method call. If the user needs to modify the event after initialization, they can act on the attributes directly (e.g. event.event_time = "yesterday").
Getting event attributes
Currently, after creating an event, if the user wanted to get one of the fields such as the event time, the user would have to do something like:
event= ...
data=event.ce__eventTime.value
The ce-prefix is a bit unexpected and the double-underscore is unconventional
Having to call .value to get the value is also unexpected
Instead, consider something like:
event= ...
data=event.event_time
No prefix or double underscore
Access the attribute value directly
Final thoughts
I realize this is proposing a pretty big overhaul of the current interface, but I think doing so would probably go a long way to lend towards the usability and maintainability of this library, and it'd be better to do it sooner than later. I'm happy to help out here, including designing/implementing these changes and helping maintain them afterwards, if it makes sense. Thanks!
Hi all, first: thanks for providing this library. It's going to be really useful to have a standard way to work with CloudEvents from Python.
I took a preliminary look at it and my first impression was that the interface provided by this library isn't very "Pythonic", meaning that it doesn't provide an interface in a way that (I believe) would be expected by most Python developers. There are some small things (like using method names like
FromRequestinstead offrom_request, usingNewin class/method names) but also larger things (like the use of method chaining, setters/getters, etc.)I'm hoping that since this project is still in alpha, there's still time to improve the interface here (and that y'all are open to suggestions). I'll try to provide some examples below of what I'm talking about but I'm happy to clarify if anything's unclear. I'm also not intimately familiar with the CloudEvents spec, so I may have some misunderstandings as well.
Parsing upstream
Eventfrom HTTP RequestThe current example for turning an HTTP request into an event:
HTTPMarshaller, and if it's the default maybe we should just get it by default when creating anEvent, instead of making the user initialize it every time?data_unmarshalleris maybe not necessary? We're taking a bytestring, turning it into aBytesIOobject to pass asdata, and then usingdata_unmarshallerto turn it back into a bytestring. Why not just have the user do any data unmarshalling themselves before constructing the event?Instead, consider:
Event, detects which spec it matches, and gives back a correspondingEventsubclass. (If the user knew which spec they were supporting, instead of constructing anEventthey could construct av02.Eventand skip the event detection)HTTPMarshalleris used by default. This also helps avoid issues like Reusing a marshaller causes failures? #12.data_unmarshallerfield is removed (or at the very least, optional)Creating a minimal CloudEvent
The provided example is:
Instead, consider the following based on the same
Eventclass proposed above:Eventobject can be created with a single method call. If the user needs to modify the event after initialization, they can act on the attributes directly (e.g.event.event_time = "yesterday").Getting event attributes
Currently, after creating an event, if the user wanted to get one of the fields such as the event time, the user would have to do something like:
ce-prefix is a bit unexpected and the double-underscore is unconventional.valueto get the value is also unexpectedInstead, consider something like:
Final thoughts
I realize this is proposing a pretty big overhaul of the current interface, but I think doing so would probably go a long way to lend towards the usability and maintainability of this library, and it'd be better to do it sooner than later. I'm happy to help out here, including designing/implementing these changes and helping maintain them afterwards, if it makes sense. Thanks!