首页 > 解决方案 > 在数据类中加载递归字典时出现 ForwardReference NameError

问题描述

我正在使用 marshmallow-dataclass 加载一个表示一系列规则的 json,其中每个规则由一个 LogicalGroup 表示,并对它的子表达式应用一个逻辑运算符,因为我知道一个表达式本身可以是一个 LogicalGroup。

输入字典遵循以下结构:

import marshmallow_dataclass
from dataclasses import field
from api_handler import BaseSchema
from typing import Sequence, Union, Literal, Type, List, ForwardRef, TypeVar, Generic

filter_input = { "rules" :
  [{
    "groupOperator" : "and",
    "expressions" : [
      { "field": "xxxxx", "operator": "eq", "value": 'level1' },
      { "field": "xxxxx", "operator": "eq", "value": 'm'},
      { "field": "xxxxx", "operator": "eq", "value": "test"},
      {
        "groupOperator" : "or",
        "expressions" : [
          { "field": "xxxx", "operator": "eq", "value": 'level2' },
          { "field": "xxxx", "operator": "eq", "value": 'm' },
          { "field": "xxxx", "operator": "eq", "value": "test" }
        ]
      }
    ]
  }]
}

我为此目的使用的数据类如下:

@marshmallow_dataclass.dataclass(base_schema=BaseSchema)
class Expression:
    field    : str
    operator : str
    value    : str 

@marshmallow_dataclass.dataclass(base_schema=BaseSchema)
class LogicalGroup:
    group_operator   : str
    expressions      : List[Union['LogicalGroup', Expression]] = field(default_factory=list)
  
@marshmallow_dataclass.dataclass(base_schema=BaseSchema)
class Filter:
    rules: List[LogicalGroup] = field(default_factory=list)

问题是当我尝试使用过滤器数据类加载字典时,出现以下错误

filt                = Filter.Schema().load(filter_input)
Traceback (most recent call last):
  File "/home/adam/billing/billing/filter/filter.py", line 96, in <module>
    filt                = Filter.Schema().load(filter_input)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow_dataclass/__init__.py", line 628, in load
    all_loaded = super().load(data, many=many, **kwargs)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/schema.py", line 725, in load
    return self._do_load(
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/schema.py", line 859, in _do_load
    result = self._deserialize(
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/schema.py", line 667, in _deserialize
    value = self._call_and_store(
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/schema.py", line 496, in _call_and_store
    value = getter_func(data)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/schema.py", line 664, in <lambda>
    getter = lambda val: field_obj.deserialize(
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/fields.py", line 354, in deserialize
    output = self._deserialize(value, attr, data, **kwargs)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/fields.py", line 726, in _deserialize
    result.append(self.inner.deserialize(each, **kwargs))
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/fields.py", line 354, in deserialize
    output = self._deserialize(value, attr, data, **kwargs)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/fields.py", line 609, in _deserialize
    return self._load(value, data, partial=partial)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/fields.py", line 592, in _load
    valid_data = self.schema.load(value, unknown=self.unknown, partial=partial)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow_dataclass/__init__.py", line 628, in load
    all_loaded = super().load(data, many=many, **kwargs)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/schema.py", line 725, in load
    return self._do_load(
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/schema.py", line 859, in _do_load
    result = self._deserialize(
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/schema.py", line 667, in _deserialize
    value = self._call_and_store(
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/schema.py", line 496, in _call_and_store
    value = getter_func(data)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/schema.py", line 664, in <lambda>
    getter = lambda val: field_obj.deserialize(
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/fields.py", line 354, in deserialize
    output = self._deserialize(value, attr, data, **kwargs)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/fields.py", line 726, in _deserialize
    result.append(self.inner.deserialize(each, **kwargs))
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow/fields.py", line 354, in deserialize
    output = self._deserialize(value, attr, data, **kwargs)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/marshmallow_dataclass/union_field.py", line 56, in _deserialize
    typeguard.check_type(attr or "anonymous", result, typ)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/typeguard/__init__.py", line 655, in check_type
    expected_type = resolve_forwardref(expected_type, memo)
  File "/home/adam/thanos-envv/lib/python3.9/site-packages/typeguard/__init__.py", line 198, in resolve_forwardref
    return evaluate_forwardref(maybe_ref, memo.globals, memo.locals, frozenset())
  File "/usr/lib/python3.9/typing.py", line 533, in _evaluate
    eval(self.__forward_code__, globalns, localns),
  File "<string>", line 1, in <module>
NameError: name 'LogicalGroup' is not defined

我猜这个问题来自于在类型提示 Union 内将 LogicalGroup 声明为 ForwardRef,因为当我只使用 Union['LogicalGroup'] 并将我的字典修改为没有表达式的逻辑组的嵌套字典时,它工作正常。

有人对错误的来源有任何想法吗?或者也许是用另一种方式解决这个问题的提议?

提前致谢 !

标签: pythonpython-3.xmarshmallowpython-dataclasses

解决方案


推荐阅读