Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Fix MetaBase.from_dict with Optional #4041

Merged
merged 2 commits into from
Feb 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added etl/catalog/utils.py
Empty file.
14 changes: 12 additions & 2 deletions lib/catalog/owid/catalog/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,21 @@ def dataclass_from_dict(cls: Optional[Type[T]], d: Dict[str, Any]) -> T:
if type(None) in args:
filtered_args = tuple(a for a in args if a is not type(None))
if len(filtered_args) == 1:
# Save the original field_type for Optional[List[...]] case
field_type = filtered_args[0]
# For Optional[List[...]] case, update the origin and args
if get_origin(field_type) is list:
origin = list
args = get_args(field_type)

if origin is list:
item_type = args[0]
init_args[field_name] = [dataclass_from_dict(item_type, item) for item in v]
# Check if we have type arguments (e.g. List[str])
if args:
item_type = args[0]
init_args[field_name] = [dataclass_from_dict(item_type, item) for item in v]
else:
# No type arguments, just use the values as-is
init_args[field_name] = v
elif origin is dict:
key_type, value_type = args
init_args[field_name] = {k: dataclass_from_dict(value_type, item) for k, item in v.items()}
Expand Down
16 changes: 15 additions & 1 deletion lib/catalog/tests/test_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#

from dataclasses import dataclass
from typing import Any, Dict, Optional
from typing import Any, Dict, List, Optional

import pytest
import yaml
Expand Down Expand Up @@ -121,3 +121,17 @@ def test_hash():
var_c = meta.VariableMeta(display={"d": {"a": 1, "b": 2, "c": 3}})
assert var_a == var_b
assert var_a != var_c


def test_from_dict():
@dataclass
class X(meta.MetaBase):
a: int

@dataclass
class Y(meta.MetaBase):
x_list: Optional[List[X]] = None

# list of objects should be correctly loaded as that object
y = Y.from_dict({"x_list": [{"a": 1}]})
assert isinstance(y.x_list[0], X)