-
Notifications
You must be signed in to change notification settings - Fork 56
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
The from_http
returns CloudEvent with inaccessible attributes
#246
Comments
Perhaps try accessing the attributes thusly:
If that doesn't work, I'll dig deeper 👍🏻 |
import logging
from cloudevents.http import from_http
from http.server import BaseHTTPRequestHandler, HTTPServer
logging.basicConfig(level=logging.DEBUG)
class CloudEventHandler(BaseHTTPRequestHandler):
def do_POST(self):
headers = {key.lower(): value for key, value in self.headers.items()}
content_length = int(self.headers.get("content-length", 0))
body = self.rfile.read(content_length).decode("utf-8")
logging.info(f"Received headers: {headers}")
logging.info(f"Received body: {body}")
try:
# Parse the CloudEvent
event = from_http(headers, body)
logging.info(f"Parsed CloudEvent: {event}")
# Access attributes as struct-like members
specversion = event.specversion
event_type = event.type
source = event.source
logging.info(f"Specversion: {specversion}, Type: {event_type}, Source: {source}")
response_body = {
"specversion": specversion,
"type": event_type,
"source": source,
}
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(str(response_body).encode("utf-8"))
except Exception as e:
logging.error(f"Error parsing CloudEvent: {e}")
self.send_response(500)
self.end_headers()
self.wfile.write(f"Error: {e}".encode("utf-8"))
def run(server_class=HTTPServer, handler_class=CloudEventHandler, port=8080):
server_address = ("", port)
httpd = server_class(server_address, handler_class)
logging.info(f"Starting HTTP server on port {port}")
httpd.serve_forever()
if __name__ == "__main__":
run() Gives me
|
Hey,
Can you please try to access the attributes by their names either with
`.get` method on the event or with `['atrribute name']` accessor?
The available APIs are defined here:
https://github.com/cloudevents/sdk-python/blob/main/cloudevents%2Fabstract%2Fevent.py.
and
https://github.com/cloudevents/sdk-python/blob/main/cloudevents%2Ftests%2Ftest_http_cloudevent.py
should have some tests.
And `attributes` is not a known attribute. It's a container that's accessed
by the `get` method.
Sorry, I'm answering from a mobile and can't prep an example right now 🙂
…On Fri, Dec 20, 2024, 11:46 Matthias Wessendorf ***@***.***> wrote:
import loggingfrom cloudevents.http import from_httpfrom http.server import BaseHTTPRequestHandler, HTTPServer
logging.basicConfig(level=logging.DEBUG)
class CloudEventHandler(BaseHTTPRequestHandler):
def do_POST(self):
headers = {key.lower(): value for key, value in self.headers.items()}
content_length = int(self.headers.get("content-length", 0))
body = self.rfile.read(content_length).decode("utf-8")
logging.info(f"Received headers: {headers}")
logging.info(f"Received body: {body}")
try:
# Parse the CloudEvent
event = from_http(headers, body)
logging.info(f"Parsed CloudEvent: {event}")
# Access attributes as struct-like members
specversion = event.specversion
event_type = event.type
source = event.source
logging.info(f"Specversion: {specversion}, Type: {event_type}, Source: {source}")
response_body = {
"specversion": specversion,
"type": event_type,
"source": source,
}
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(str(response_body).encode("utf-8"))
except Exception as e:
logging.error(f"Error parsing CloudEvent: {e}")
self.send_response(500)
self.end_headers()
self.wfile.write(f"Error: {e}".encode("utf-8"))
def run(server_class=HTTPServer, handler_class=CloudEventHandler, port=8080):
server_address = ("", port)
httpd = server_class(server_address, handler_class)
logging.info(f"Starting HTTP server on port {port}")
httpd.serve_forever()
if __name__ == "__main__":
run()
Gives me 500:
http -j -v POST http://127.0.0.1:8080/ \
Content-Type:application/json \
ce-specversion:1.0 \
ce-type:event.registry \
ce-source:/dev/console/web/form \
ce-id:$(uuidgen)
POST / HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 0
Content-Type: application/json
Host: 127.0.0.1:8080
User-Agent: HTTPie/3.2.3
ce-id: 8e76d231-ea5c-4de8-b16a-0262006b7e50
ce-source: /dev/console/web/form
ce-specversion: 1.0
ce-type: event.registry
HTTP/1.0 500 Internal Server Error
Date: Fri, 20 Dec 2024 10:44:46 GMT
Server: BaseHTTP/0.6 Python/3.13.0
Error: 'CloudEvent' object has no attribute 'specversion'
—
Reply to this email directly, view it on GitHub
<#246 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABLJVKO6PFQIAFYCOSUDVOD2GPYSBAVCNFSM6AAAAABT4RZNF6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDKNJWG42DONBYHA>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
@matzew can you please try it out? Just tag me if you see it's not working. I'll dig into the code then |
You must use event.get(<attribute_name>), here's a functional example: import sys
import logging
from cloudevents.http import from_http
from http.server import BaseHTTPRequestHandler, HTTPServer
logging.basicConfig(level=logging.DEBUG)
class CloudEventHandler(BaseHTTPRequestHandler):
def do_POST(self):
headers = {key.lower(): value for key, value in self.headers.items()}
content_length = int(self.headers.get("content-length", 0))
body = self.rfile.read(content_length).decode("utf-8")
logging.info(f"Received headers: {headers}")
logging.info(f"Received body: {body}")
try:
event = from_http(headers, body)
specversion = event.get("specversion")
event_type = event.get("type")
source = event.get("source")
logging.info(
f"Specversion: {specversion} "
f"Type: {event_type} "
f"Source: {source}"
)
response_body = {
"specversion": specversion,
"type": event_type,
"source": source,
}
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(str(response_body).encode("utf-8") + "\n".encode("utf-8"))
except Exception as e:
logging.error(f"Error parsing CloudEvent: {e}")
self.send_response(500)
self.end_headers()
self.wfile.write(f"Error: {e}".encode("utf-8"))
raise
def run(server_class=HTTPServer, handler_class=CloudEventHandler, port=8080):
server_address = ("", port)
httpd = server_class(server_address, handler_class)
logging.info(f"Starting HTTP server on port {port}")
httpd.serve_forever()
if __name__ == "__main__":
try:
run()
except KeyboardInterrupt:
print("User interrupted")
sys.exit(1) $ curl -v \
-H "Content-Type: application/json" \
-H "ce-specversion: 1.0" \
-H "ce-type: debugging" \
-H "ce-source: /" \
-H "ce-id: 12345" \
-d '{"attributes": "acquired"}' \
http://127.0.0.1:8080
* Trying 127.0.0.1:8080...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> POST / HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.88.1
> Accept: */*
> Content-Type: application/json
> ce-specversion: 1.0
> ce-type: debugging
> ce-source: /
> ce-id: 12345
> Content-Length: 26
>
INFO:root:Received headers: {'host': '127.0.0.1:8080', 'user-agent': 'curl/7.88.1', 'accept': '*/*', 'content-type': 'application/json', 'ce-specversion': '1.0', 'ce-type': 'debugging', 'ce-source': '/', 'ce-id': '12345', 'content-length': '26'}
INFO:root:Received body: {"attributes": "acquired"}
INFO:root:Specversion: 1.0 Type: debugging Source: /
127.0.0.1 - - [22/Dec/2024 00:09:01] "POST / HTTP/1.1" 200 -
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: BaseHTTP/0.6 Python/3.12.7
< Date: Sun, 22 Dec 2024 05:09:01 GMT
< Content-Type: application/json
<
{'specversion': '1.0', 'type': 'debugging', 'source': '/'}
* Closing connection 0 Introspecting the event object lead me to the abstract.CloudEvent class. This class overrides the def __getitem__(self, key: str) -> typing.Any:
"""
Returns a value of an attribute of the event denoted by the given `key`.
The `data` of the event should be accessed by the `.data` accessor rather
than this mapping.
:param key: The name of the event attribute to retrieve the value for.
:returns: The event attribute value.
"""
return self._get_attributes()[key] |
Expected Behavior
The
from_http
function should return a CloudEvent object where attributes likespecversion
,type
, andsource
are accessible viaevent["attributes"]
or similar documented methods.Actual Behavior
But for me the
from_http
function returns a CloudEvent object with an empty attributes field. Attempting to accessspecversion
,type
, orsource
returns missing.Steps to Reproduce the Problem
Run the script via
python reproducer.py
Access the server, like:
Specifications
pip show cloudevents
:The text was updated successfully, but these errors were encountered: