dataclass-wizard icon indicating copy to clipboard operation
dataclass-wizard copied to clipboard

Avoid any transformation on key names

Open raxod502 opened this issue 11 months ago • 3 comments

  • Dataclass Wizard version: 0.22.2
  • Python version: 3.10.6
  • Operating System: Pop!_OS 22.04 LTS

Description

I found that by default, when serializing a dataclass, all the key names are changed to camelCase. This was surprising to me. By reading the documentation I found that it is possible to change this, but I could not find documentation on what alternative behaviors are supported (i.e., what values of key_transform are supported). I spent some time reading the source code, and found the following:

https://github.com/rnag/dataclass-wizard/blob/e3fe0760422613eaf79e0236840a50f27caec064/dataclass_wizard/enums.py#L16-L29

Based on this code it seems the supported behaviors are to transform into camelCase, PascalCase, lisp-case, and snake_case. However, what I actually want is for no transformation whatsoever to happen. Is this possible?

Ideally, I want to be able to inhibit the key transformation entirely, without having to modify all (or any) dataclasses in my application. Based on the design of other json/yaml libraries for Python, I would expect to be able to accomplish this by passing a keyword argument to the asdict function, but as far as I can tell, this does not seem to be possible. Instead, one must globally modify the dataclass definition at runtime by invoking DumpMeta.bind_to. This was also surprising to me.

The ask:

  1. It should be possible to disable key transformation, instead of just change it to a different transformation.
  2. It should be possible to accomplish with a keyword argument to asdict, without changing any dataclass definition either in code or at runtime.
  3. It should be documented what are the possible ways to configure key transformation, and/or how to add your own (if this is supported).

I'm happy to implement a feature like this in a pull request and add tests, but have I missed some reason this would be a bad idea / did I miss documentation that explains it?

What I Did

I have dataclasses that look like this, no special meta annotations:

@dataclass
class Transaction:
    date_posted: datetime
    date_cleared: datetime
    currency: str
    amount: Decimal

Then I am converting them to json like this, ideally without date_posted being changed to datePosted:

print(json.dumps(dataclass_wizard.asdict(transaction), indent=2, default=str))

Of course, specifying SNAKE_CASE as the transform is a workaround in this case, but really I do not want any transformation.

raxod502 avatar Jul 07 '23 22:07 raxod502

Adding

diff --git a/dataclass_wizard/enums.py b/dataclass_wizard/enums.py
index 1b9757e..4fb5356 100644
--- a/dataclass_wizard/enums.py
+++ b/dataclass_wizard/enums.py
@@ -27,6 +27,9 @@ class LetterCase(Enum):
     # Converts strings (generally in camel case) to snake case.
     #   ex: `myFieldName` -> `my_field_name`
     SNAKE = FuncWrapper(to_snake_case)
+    # Perfoms no conversion on strings.
+    #   ex: `MY_FIELD_NAME` -> `MY_FIELD_NAME`
+    NONE = FuncWrapper(str)

     def __call__(self, *args):
         return self.value.f(*args)

and setting up the dataclass like

@dataclass
class MyDataclass(JSONWizard):
    VAR_1: int
    vAr__2: int
    VAr3__: int

    class _(JSONWizard.Meta):
        key_transform_with_dump = "NONE"

data = """{
    "VAR_1": 1,
    "vAr__2": 2,
    "VAr3__": 3
}
"""

foo = MyDataclass.from_json(data)
print("JSON -> Dataclass", foo)
print("Dataclass -> JSON", foo.to_json())

prints with no transformations

JSON -> Dataclass {
  "VAR_1": 1,
  "vAr__2": 2,
  "VAr3__": 3
}
Dataclass -> JSON {"VAR_1": 1, "vAr__2": 2, "VAr3__": 3}

cquick01 avatar Aug 29 '23 14:08 cquick01

Hey @raxod502 and @cquick01, thanks for asking and contributing to this issue. I think the PR forgot to be linked but just adding it here -- #94 and I added a comment on there.

Seems like a simple change though, and I am ok with this, but once comment with justification is added I'm ok to go ahead and merge. I feel this could be a useful addition for others. Thanks!

rnag avatar Jan 30 '24 21:01 rnag

Looks pretty good to me, I think the only thing missing now is documenting the existence of the feature!

raxod502 avatar Feb 09 '24 01:02 raxod502