Skip to content

Commit

Permalink
udopates benchmark code for other libs
Browse files Browse the repository at this point in the history
  • Loading branch information
rnag committed Nov 27, 2024
1 parent 7ba05e7 commit 9d0be22
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 113 deletions.
114 changes: 95 additions & 19 deletions benchmarks/complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
from dataclasses import dataclass, field, asdict
from datetime import datetime
from timeit import timeit
from typing import Optional, TypeVar, Dict, Any, List, Union, NamedTuple, Tuple
from typing import Optional, TypeVar, Dict, Any, List, Union, NamedTuple, Tuple, Type

import dacite
import dataclass_factory
import marshmallow
import pytest
Expand Down Expand Up @@ -39,15 +40,38 @@ class MyClassDJ(DataClassJsonMixin):
is_enabled: bool = True


# New Mashumaro Model
@dataclass
class MyClassMashumaro(mashumaro.DataClassDictMixin):
class MyClassDacite:
my_ledger: Dict[str, Any]
the_answer_to_life: Optional[int]
people: List['Person']
people: List['PersonDJ']
is_enabled: bool = True


# New Pydantic Models
class MyClassPydantic(BaseModel):
my_ledger: Dict[str, Any]
the_answer_to_life: Optional[int]
people: List['PersonPydantic']
is_enabled: bool = True


# New Pydantic Models
class PersonPydantic(BaseModel):
name: 'NamePydantic'
age: int
birthdate: datetime
gender: str
occupation: Union[str, List[str]]
hobbies: Dict[str, List[str]] = defaultdict(list)


class NamePydantic(BaseModel):
first: str
last: str
salutation: Optional[str] = 'Mr.'


@dataclass
class Person:
name: 'Name'
Expand Down Expand Up @@ -111,11 +135,6 @@ class PersonDJ:
attr_dict=vars(MyClass).copy())



def custom_name_decoder(value):
return Name(**value)


@pytest.fixture(scope='session')
def data():
return {
Expand Down Expand Up @@ -159,6 +178,18 @@ def data_2(data):

return d

@pytest.fixture(scope='session')
def data_dacite(data_2):
"""data for `dacite`, which has a *TON* of issues."""

# It's official, I hate this library ;-(
d = data_2.copy()
d['the_answer_to_life'] = int(d['the_answer_to_life'])
d['people'][0]['hobbies'] = data_2['people'][0]['hobbies'].copy()
d['people'][0]['hobbies']['M-F'] = list(d['people'][0]['hobbies']['M-F'])

return d


def parse_iso_format(data):
return as_datetime(data)
Expand All @@ -172,7 +203,26 @@ def parse_iso_format(data):
datetime: iso_format_schema
}

def test_load(request, data, data_2, n):
def parse_datetime(value: str) -> datetime:
return datetime.fromisoformat(value.rstrip('Z')) # Remove 'Z' if it's present

dacite_cfg = dacite.Config(
type_hooks={datetime: parse_datetime})


def test_load(request, data, data_2, data_dacite, n):
"""
[ RESULTS ON MAC OS X ]
benchmarks.complex.complex - [INFO] dataclass-wizard 0.800521
benchmarks.complex.complex - [INFO] dataclass-factory 0.827150
benchmarks.complex.complex - [INFO] dataclasses-json 37.087781
benchmarks.complex.complex - [INFO] dacite 9.421210
benchmarks.complex.complex - [INFO] mashumaro 0.608496
benchmarks.complex.complex - [INFO] pydantic 1.039472
benchmarks.complex.complex - [INFO] jsons 39.677698
benchmarks.complex.complex - [INFO] jsons (strict) 41.592585
"""
g = globals().copy()
g.update(locals())

Expand All @@ -185,9 +235,28 @@ def test_load(request, data, data_2, n):
log.info('dataclasses-json %f',
timeit('MyClassDJ.from_dict(data_2)', globals=g, number=n))

log.info('dacite %f',
timeit('dacite_from_dict(MyClassDacite, data_dacite, config=dacite_cfg)',
globals=g, number=n))

log.info('mashumaro %f',
timeit('MyClassMashumaro.from_dict(data)', globals=g, number=n))

log.info('pydantic %f',
timeit('MyClassPydantic(**data_2)', globals=g, number=n))

# Assert the dataclass instances have the same values for all fields.
c1 = MyClassWizard.from_dict(data)
c2 = factory.load(data_2, MyClass)
c3 = MyClassDJ.from_dict(data_2)
c4 = MyClassJsons.load(data)
c5 = MyClassMashumaro.from_dict(data)
c6 = dacite_from_dict(MyClassDacite, data_dacite, config=dacite_cfg)
c7 = MyClassPydantic(**data_2)

# Since these models might differ slightly, we can skip exact equality checks
# assert c1.__dict__ == c2.__dict__ == c3.__dict__ == c4.__dict__ == c5.__dict__

if not request.config.getoption("--all"):
pytest.skip("Skipping benchmarks for the rest by default, unless --all is specified.")

Expand All @@ -197,22 +266,26 @@ def test_load(request, data, data_2, n):
log.info('jsons (strict) %f',
timeit('MyClassJsons.load(data, strict=True)', globals=g, number=n))

# Assert the dataclass instances have the same values for all fields.
c1 = MyClassWizard.from_dict(data)
c2 = factory.load(data_2, MyClass)
c3 = MyClassDJ.from_dict(data)
c4 = MyClassJsons.load(data)
c5 = MyClassMashumaro.from_dict(data)

# Since these models might differ slightly, we can skip exact equality checks
# assert c1.__dict__ == c2.__dict__ == c3.__dict__ == c4.__dict__ == c5.__dict__
def test_dump(request, data, data_2, data_dacite, n):
"""
[ RESULTS ON MAC OS X ]
def test_dump(request, data, data_2, n):
benchmarks.complex.complex - [INFO] dataclass-wizard 1.606120
benchmarks.complex.complex - [INFO] asdict (dataclasses) 2.006917
benchmarks.complex.complex - [INFO] dataclass-factory 0.979412
benchmarks.complex.complex - [INFO] dataclasses-json 13.740522
benchmarks.complex.complex - [INFO] mashumaro 0.289991
benchmarks.complex.complex - [INFO] pydantic 0.384267
benchmarks.complex.complex - [INFO] jsons 41.673240
benchmarks.complex.complex - [INFO] jsons (strict) 45.934885
"""
c1 = MyClassWizard.from_dict(data)
c2 = factory.load(data_2, MyClass)
c3 = MyClassDJ.from_dict(data_2)
c4 = MyClassJsons.load(data)
c5 = MyClassMashumaro.from_dict(data)
c6 = MyClassPydantic(**data_2)

g = globals().copy()
g.update(locals())
Expand All @@ -232,6 +305,9 @@ def test_dump(request, data, data_2, n):
log.info('mashumaro %f',
timeit('c5.to_dict()', globals=g, number=n))

log.info('pydantic %f',
timeit('c6.model_dump()', globals=g, number=n))

if not request.config.getoption("--all"):
pytest.skip("Skipping benchmarks for the rest by default, unless --all is specified.")

Expand Down
Loading

0 comments on commit 9d0be22

Please sign in to comment.