-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: add automatic
camelCase
mashumaro aliases for `snake_case…
…` attrs (#26) This commit adds automatic mashumaro camel case aliases for all fields in our models. This will make them more scalable and less error-prone.
- Loading branch information
1 parent
34782ef
commit 2062850
Showing
8 changed files
with
85 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
kind: Under the Hood | ||
body: Changed how field aliases to make it easier to define new models | ||
time: 2024-06-28T16:48:12.280623+02:00 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
from dataclasses import fields, is_dataclass | ||
from types import MappingProxyType | ||
|
||
from mashumaro import DataClassDictMixin, field_options | ||
from mashumaro.config import BaseConfig | ||
|
||
|
||
def snake_case_to_camel_case(s: str) -> str: | ||
"""Convert a snake_case_string into a camelCaseString.""" | ||
tokens = s.split("_") | ||
return tokens[0] + "".join(t.title() for t in tokens[1:]) | ||
|
||
|
||
class BaseModel(DataClassDictMixin): | ||
"""Base class for all serializable models. | ||
Adds some functionality like automatically creating camelCase aliases. | ||
""" | ||
|
||
class Config(BaseConfig): # noqa: D106 | ||
lazy_compilation = True | ||
|
||
@classmethod | ||
def _apply_aliases(cls) -> None: | ||
"""Apply camelCase aliases to all subclasses.""" | ||
for subclass in cls.__subclasses__(): | ||
assert is_dataclass(subclass), "Subclass of BaseModel must be dataclass" | ||
|
||
for field in fields(subclass): | ||
camel_name = snake_case_to_camel_case(field.name) | ||
if field.name != camel_name: | ||
field.metadata = MappingProxyType(field_options(alias=camel_name)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
from dataclasses import dataclass | ||
|
||
from mashumaro.codecs.basic import decode | ||
|
||
from dbtsl.models.base import BaseModel | ||
from dbtsl.models.base import snake_case_to_camel_case as stc | ||
|
||
|
||
def test_snake_case_to_camel_case() -> None: | ||
assert stc("hello") == "hello" | ||
assert stc("hello_world") == "helloWorld" | ||
assert stc("Hello_world") == "HelloWorld" | ||
assert stc("hello world") == "hello world" | ||
assert stc("helloWorld") == "helloWorld" | ||
|
||
|
||
def test_base_model_auto_alias() -> None: | ||
@dataclass | ||
class SubModel(BaseModel): | ||
hello_world: str | ||
|
||
BaseModel._apply_aliases() | ||
|
||
data = { | ||
"helloWorld": "asdf", | ||
} | ||
|
||
model = SubModel.from_dict(data) | ||
assert model.hello_world == "asdf" | ||
|
||
codec_model = decode(data, SubModel) | ||
assert codec_model.hello_world == "asdf" |