1

I'm having trouble using the attribute field of marshmallow dataclasses (v3.x).

My problem: I get the input keys for schema.load as dict with non-python-valid names e.g. "external.id" and I want the output keys with schema.dump to be different e.g. "externalId". So I need to load and dump with two different keys.

The data_key is not enough, because it would dump it with the same naming. Using the attribute key additionally, does not help. My example code here:

import marshmallow_dataclass
from dataclasses import field

@marshmallow_dataclass.dataclass
class Uao:
    externalId: str = field(metadata=dict(data_key="external.id", attribute="externalId"))

schema = marshmallow_dataclass.class_schema(Uao)
uao_loaded = schema().load({"external.id": "1234"})
uao_dumped = schema().dump(uao_loaded)

should return: {'externalId': '1234'}
but returns: {'external.id': '1234'}

What am I doing wrong? I already know, there is an old marshmallow version with load_from and dump_to where my requirement probably was possible - but it is no option to use an old version of the lib.
Also, it's not pythonic to write the instance attribute of the class in camelCase. I would prefer it to name it "external_id", but then it throws TypeError: __init__() got an unexpected keyword argument 'externalId'

nikitira
  • 86
  • 7

2 Answers2

0

I'm honestly not too familiar with marshmallow dataclasses, however if you're ok working without marshmallow schemas, I have come up with a (de)serialization library called the dataclass-wizard which is built on top of dataclasses, that could alternatively work for you - see below.

from dataclasses import dataclass
from dataclass_wizard import fromdict, asdict, json_field

@dataclass
class Uao:
    external_id: str = json_field('external.id')

uao_loaded = fromdict(Uao, {"external.id": "1234"})

uao_dumped = asdict(uao_loaded)
print(uao_dumped)  # {'externalId': '1234'}

The default key transform for dump is camelCase, so an explicit key alias for the dump process is not needed. However in case where this is desired, you can:

  • pass in a tuple of alias names, where the first name is used in the dump process.
  • enable all flag so the alias names apply to the dump process, which is desired in this case.

For example:

>>> from dataclasses import dataclass
>>> from dataclass_wizard import fromdict, asdict, json_field
>>> @dataclass
... class Uao:
...   external_id: str = json_field(('dumpedKey', 'external.id'), all=True)
... 
>>> uao_loaded = fromdict(Uao, {"external.id": "1234"})
>>> asdict(uao_loaded)
{'dumpedKey': '1234'}
rv.kvetch
  • 9,940
  • 3
  • 24
  • 53
0

Indeed, marshmallow 2 would allow using different keys for load and dump but this was removed (by me).

You may achieve this by using two schemas, one for the load, one for the dump.

This is assuming you want to load to a dataclass then dump from that dataclass.

If you only want to load from a dict to a dict, you may drop the dataclass stuff and use a single schema and a single load operation.

This is the part where your use case is unclear to me.

Jérôme
  • 13,328
  • 7
  • 56
  • 106