Closed
Description
The following snippet:
import asyncio
from datetime import datetime, timezone
from githubkit.github import GitHub
github = GitHub()
async def main():
await github.rest.checks.async_create(
"user",
"repo",
name="name",
head_sha="0000000000000000000000000000000000000000",
started_at=datetime.now(timezone.utc) # problematic line here
)
asyncio.run(main())
Fails with the following exception(s):
Traceback (most recent call last):
File "[redacted]/.venv/lib/python3.10/site-packages/githubkit/core.py", line 265, in _arequest
return await client.request(
File "[redacted]/.venv/lib/python3.10/site-packages/httpx/_client.py", line 1520, in request
request = self.build_request(
File "[redacted]/.venv/lib/python3.10/site-packages/httpx/_client.py", line 360, in build_request
return Request(
File "[redacted]/.venv/lib/python3.10/site-packages/httpx/_models.py", line 339, in __init__
headers, stream = encode_request(
File "[redacted]/.venv/lib/python3.10/site-packages/httpx/_content.py", line 215, in encode_request
return encode_json(json)
File "[redacted]/.venv/lib/python3.10/site-packages/httpx/_content.py", line 178, in encode_json
body = json_dumps(json).encode("utf-8")
File "/usr/lib/python3.10/json/__init__.py", line 231, in dumps
return _default_encoder.encode(obj)
File "/usr/lib/python3.10/json/encoder.py", line 199, in encode
chunks = self.iterencode(o, _one_shot=True)
File "/usr/lib/python3.10/json/encoder.py", line 257, in iterencode
return _iterencode(o, 0)
File "/usr/lib/python3.10/json/encoder.py", line 179, in default
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type datetime is not JSON serializable
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "[redacted]/main.py", line 34, in <module>
asyncio.run(main())
File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
return future.result()
File "[redacted]/main.py", line 20, in main
x = await github.rest.checks.async_create(
File "[redacted]/.venv/lib/python3.10/site-packages/githubkit/rest/checks.py", line 276, in async_create
return await self._github.arequest(
File "[redacted]/.venv/lib/python3.10/site-packages/githubkit/core.py", line 346, in arequest
raw_resp = await self._arequest(
File "[redacted]/.venv/lib/python3.10/site-packages/githubkit/core.py", line 279, in _arequest
raise RequestError(repr(e)) from e
githubkit.exception.RequestError: TypeError('Object of type datetime is not JSON serializable')
When you look at the code for the async_check
function:
githubkit/githubkit/rest/checks.py
Line 274 in bc1eb96
You will see that the .dict()
method is called, which will return a Python dict, not a JSON-safe dict (which is what the json
variable implies). This "json" object gets propogated all the way to httpx
, and when it tries to JSON encode it, it fails.
Some ideas for how to fix this:
- Pydantic does have a
.json()
function, though it returns a string and not adict
. We could replace every call tojson.dict(...)
withloads(json.json(...))
, whereloads
is thejson.loads
method from the stdlib, though there are a lot of API calls we would have to do this for, and it would introduce some overhead. - Write a function that walks a
dict
object that stringifiesdatetime
objects using.isoformat()
. By adding said function right here (and to all the other API helper functions):Lines 346 to 356 in bc1eb96
We could stringify all datetime objects without changing every API function. There might be other object types other than datetimes which we might also want to support, datetimes just happened to be the ones that where giving me trouble.
I really like this library, but this bug is keeping me from using it in production 😢. I wouldn't mind opening a PR for this, it sounds easy enough, assuming we go with option 2.