0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

dataclasses-json:オプショナルなプロパティの型を`None | str`にして`schema().load`を実行したらwarningが発生した。

Last updated at Posted at 2023-05-29

この問題はdataclasses-json v0.5.9で解決されました。

環境

起きたこと

以下のコードを実行したらdataclasses_jsonで「Unknown type at Project.project_name: None | str」というwarningが発生しました。

sample1.py
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が発生しませんでした。

sample2.py
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_namemm_fieldを指定する

「It's advised to pass the correct marshmallow type to mm_field.」というメッセージ通り、mm_fieldを指定すればwarningが発生しません。

sample.py
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も一緒に作成されたので、そのうち修正されるかもしれません。

プルリクがマージされました!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?