この問題はdataclasses-json v0.5.9で解決されました。
環境
- Python 3.11.2
- dataclasses-json 0.5.7
起きたこと
以下のコードを実行したらdataclasses_json
で「Unknown type at Project.project_name: None | str」というwarningが発生しました。
from dataclasses import dataclass
from dataclasses_json import DataClassJsonMixin
@dataclass(frozen=True)
class Project(DataClassJsonMixin):
project_id: str
project_name: None | str = None
print("Use `Project.from_dict()`")
print(Project.from_dict({"project_id": "1"}))
print("Use `Project.schema().load()`")
print(Project.schema().load([{"project_id": "2"}], many=True))
$ python sample1.py
Use `Project.from_dict()`
Project(project_id='1', project_name=None)
Use `Project.schema().load()`
/home/vagrant/.pyenv/versions/3.11.2/lib/python3.11/site-packages/dataclasses_json/mm.py:271: UserWarning: Unknown type <class 'NoneType'> at Project.project_name: None | str It's advised to pass the correct marshmallow type to `mm_field`.
warnings.warn(
[Project(project_id='2', project_name=None)]
Project.from_dict()
ではwarningは発生しなかったのですが、Project.schema().load()
ではwarningが発生しました。
解決方法
project_name
の型をOptional[str]
にする
project_name
の型をNone | str
ではなくOptional[str]
にすると、Project.schema().load()
でwanringが発生しませんでした。
from dataclasses import dataclass
from dataclasses_json import DataClassJsonMixin
from typing import Optional
@dataclass(frozen=True)
class Project(DataClassJsonMixin):
project_id: str
project_name: Optional[str] = None
print("Use `Project.from_dict()`")
print(Project.from_dict({"project_id": "1"}))
print("Use `Project.schema().load()`")
print(Project.schema().load([{"project_id": "2"}], many=True))
$ python sample2.py
Use `Project.from_dict()`
Project(project_id='1', project_name=None)
Use `Project.schema().load()`
[Project(project_id='2', project_name=None)]
project_name
にmm_field
を指定する
「It's advised to pass the correct marshmallow type to mm_field
.」というメッセージ通り、mm_field
を指定すればwarningが発生しません。
from dataclasses_json import DataClassJsonMixin
from marshmallow import fields
from dataclasses import dataclass, field
from dataclasses_json import config
@dataclass(frozen=True)
class Project(DataClassJsonMixin):
project_id: str
project_name: None | str = field(
metadata=config(mm_field=fields.Str(load_default=None))
)
print("Use `Project.from_dict()`")
print(Project.from_dict({"project_id": "1"}, infer_missing=True))
print("Use `Project.schema().load()`")
print(Project.schema().load([{"project_id": "2"}], many=True))
$ python sample3.py
Use `Project.from_dict()`
Project(project_id='1', project_name=None)
Use `Project.schema().load()`
[Project(project_id='2', project_name=None)]
ただしProject.from_dict()
でinfer_missing=True
を指定しないと、エラーが発生します。
まとめ
dataclass-json
を利用したデータクラスで、オプショナルなプロパティの型はNone | T
よりOptional[T]
の方がよいです。その方が、 dataclasses-jsonとmarshmallow schemaの挙動が(たぶん)同じになるためです。
補足
issueを作成しました。PRも一緒に作成されたので、そのうち修正されるかもしれません。
プルリクがマージされました!