yanyongyu / githubkit

The modern, all-batteries-included GitHub SDK for Python, including rest api, graphql, webhooks, like octokit!
https://yanyongyu.github.io/githubkit/
MIT License
177 stars 25 forks source link

Fix: Remove `UNSET` objects from lists #26

Closed dosisod closed 1 year ago

dosisod commented 1 year ago

Example repro:

from datetime import datetime, timezone
import asyncio

from githubkit import GitHub

async def main():
    github = GitHub()

    now = datetime.now(timezone.utc)

    await github.rest.checks.async_create(
        "example",
        "repo",
        data={
            "name": "name",
            "head_sha": "0000000000000000000000000000000000000000",
            "external_id": "0000000000000000000000000000000000000000",
            "status": "completed",
            "conclusion": "failure",
            "started_at": now,
            "completed_at": now,
            "output": {
                "title": "some title",
                "summary": "some summary",
                "annotations": [
                    {
                        "path": "file.txt",
                        "start_line": 1,
                        "end_line": 1,
                        "start_column": 1,
                        "annotation_level": "failure",
                        "message": "some message",

                        # Missing default fields here are causing the issue
                    }
                ],
            },
        },
    )

asyncio.run(main())

Running with githubkit version 0.9.8:

$ python3 file.py
Traceback (most recent call last):
  File "REDACTED/.venv/lib/python3.10/site-packages/githubkit/core.py", line 273, in _arequest
    json=obj_to_jsonable(json),
  File "REDACTED/.venv/lib/python3.10/site-packages/githubkit/utils.py", line 55, in obj_to_jsonable
    return {k: obj_to_jsonable(v) for k, v in obj.items()}
  File "REDACTED/.venv/lib/python3.10/site-packages/githubkit/utils.py", line 55, in <dictcomp>
    return {k: obj_to_jsonable(v) for k, v in obj.items()}
  File "REDACTED/.venv/lib/python3.10/site-packages/githubkit/utils.py", line 55, in obj_to_jsonable
    return {k: obj_to_jsonable(v) for k, v in obj.items()}
  File "REDACTED/.venv/lib/python3.10/site-packages/githubkit/utils.py", line 55, in <dictcomp>
    return {k: obj_to_jsonable(v) for k, v in obj.items()}
  File "REDACTED/.venv/lib/python3.10/site-packages/githubkit/utils.py", line 58, in obj_to_jsonable
    return [obj_to_jsonable(item) for item in obj]
  File "REDACTED/.venv/lib/python3.10/site-packages/githubkit/utils.py", line 58, in <listcomp>
    return [obj_to_jsonable(item) for item in obj]
  File "REDACTED/.venv/lib/python3.10/site-packages/githubkit/utils.py", line 55, in obj_to_jsonable
    return {k: obj_to_jsonable(v) for k, v in obj.items()}
  File "REDACTED/.venv/lib/python3.10/site-packages/githubkit/utils.py", line 55, in <dictcomp>
    return {k: obj_to_jsonable(v) for k, v in obj.items()}
  File "REDACTED/.venv/lib/python3.10/site-packages/githubkit/utils.py", line 63, in obj_to_jsonable
    return pydantic_encoder(obj)
  File "pydantic/json.py", line 90, in pydantic.json.pydantic_encoder
TypeError: Object of type 'Unset' is not JSON serializable

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "REDACTED/file.py", line 41, 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/file.py", line 11, in main
    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 347, in arequest
    raw_resp = await self._arequest(
  File "REDACTED/.venv/lib/python3.10/site-packages/githubkit/core.py", line 280, in _arequest
    raise RequestError(repr(e)) from e
githubkit.exception.RequestError: TypeError("Object of type 'Unset' is not JSON serializable")

I figured out that the exclude_unset() function doesn't traverse lists, so UNSET objects inside dicts are not excluded if they are inside a list.

There might be other data types we might want to add to this list (set, tuple, etc), though I didn't check to see how often these where used in the models (if at all).