AnswerDotAI / AnswerDotAI/ghapi

Same ghapi version returns different results depending on fastcore version (JSON `null` → empty `AttrDict`)

オープン
#201 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る
主要言語
Python
スター
686
フォーク
69
平均マージ
1分
マージ済み PR(30日)
2

説明

### Summary

When using the same ghapi version, the return value of API calls changes depending on the fastcore dependency version.
Specifically, JSON `null` values from the GitHub REST API (e.g. repository `description`) are returned as:
- `None` with `fastcore==1.8.16`
- empty `fastcore.basics.AttrDict` (`{}`) with `fastcore==1.11.2`
This breaks the semantic meaning of the API response and causes downstream issues (e.g. database storage, business logic).

### Why this is a problem

- GitHub API explicitly defines `description: null` as “no value”
- In Python, this should map to `None`
- `{}` (empty mapping) has a different semantic meaning than `None`
- The behavior changes without changing the ghapi version, only by upgrading a dependency

From a user’s perspective, this means:
> The same ghapi version produces different API results depending on dependency resolution

This breaks API contract stability and reproducibility.

### Environment
Component | Version
-- | --
ghapi | 1.0.8
fastcore (local) | 1.8.16
fastcore (sam) | 1.11.2
Python | 3.10.19

### Reproduction Code
```python
from ghapi.core import GhApi

api = GhApi(token="*******", owner="ORG_NAME")

batch = api.repos.list_for_org("ORG_NAME", per_page=1, page=1)
r0 = batch[0]

print("item:", r0.get("description"), type(r0.get("description")))
print("attr:", r0.description, type(r0.description))
print("has key:", "description" in r0)

```

### Actual Results
With `fastcore==1.11.2`

```shell
item: {}
attr: {}
has key: True
```

With `fastcore==1.8.16`
```shell
item: None
attr: None
has key: True

```

### Expected Behavior
JSON `null` values from the GitHub API should consistently map to Python `None`, regardless of fastcore version.
At minimum, ghapi should:
- Preserve the semantic meaning of `null`
- Or pin / constrain fastcore versions to avoid silent behavior changes

### Additional Notes
- The conversion appears to happen during `fastcore.dict2obj` processing
- ghapi currently forwards this behavior directly to users
- This is not a database or SQLAlchemy issue — the value is already `{}` immediately after the ghapi call

This behavior change is unexpected, breaking, and difficult to detect, especially in data ingestion pipelines.
I believe this is worth addressing either in ghapi itself or through tighter fastcore integration.
Thanks for your work on ghapi.

コントリビューションガイド

コントリビューションガイドを開く

調査の方向性

Issue にある GhApi の再現から始め、fastcore 1.8.16 と 1.11.2 でのレスポンス変換を比較し、報告されている fastcore.dict2obj の処理に焦点を当てます。完了条件は、サポート対象の fastcore バージョン全体で GitHub JSON の null 値が一貫して Python None のままになり、示されているリポジトリ一覧取得の呼び出しを通じてその挙動が検証されることです。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
python
領域
api
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
42/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。