Attrs benchmark

This commit is contained in:
Eden Kirin
2023-10-19 22:04:13 +02:00
parent b4b0a7f72d
commit 4b838383ed
11 changed files with 105 additions and 22 deletions

1
.gitignore vendored
View File

@ -1,3 +1,2 @@
/vscode /vscode
__pycache__ __pycache__
/test_data.json

View File

View File

@ -0,0 +1,10 @@
import json
from benchmark.base import BenchmarkBase
from benchmark.attrs_benchmark.models import PlanogramsBulkInputPayload
class AttrsBenchmark(BenchmarkBase):
def _benchmark(self) -> None:
test_data = self._read_test_file()
json_data = json.loads(test_data)
data = PlanogramsBulkInputPayload(**json_data)

View File

@ -0,0 +1,58 @@
from enum import Enum
from typing import Optional
from uuid import uuid4
from attr import define, field
import attrs
class ColumnItemType(str, Enum):
PRODUCT = "PRODUCT"
COMPONENT = "COMPONENT"
@define
class CorrelationId:
correlation_id: str = field(factory=lambda: uuid4().hex)
@define
class ColumnsInput:
column_number: int = field(
default=None, validator=[attrs.validators.ge(0), attrs.validators.lt(32767)]
)
external_product_id: Optional[str] = field(
default=None,
validator=[attrs.validators.min_len(1), attrs.validators.max_len(32)],
)
old_qty: Optional[int] = field(
default=None,
validator=[attrs.validators.ge(0), attrs.validators.lt(2147483647)],
)
new_qty: Optional[int] = field(
default=None,
validator=[attrs.validators.ge(0), attrs.validators.lt(2147483647)],
)
old_price: Optional[float] = field(
default=None,
validator=[attrs.validators.ge(0), attrs.validators.lt(99999999.99)],
)
new_price: Optional[float] = field(
default=None,
validator=[attrs.validators.ge(0), attrs.validators.lt(99999999.99)],
)
select_map: Optional[list[int]] = field(default=None)
item_type: Optional[ColumnItemType] = field(factory=lambda: ColumnItemType.PRODUCT)
@define
class PlanogramInput(CorrelationId):
machine_external_id: Optional[str] = field(
default=None,
validator=[attrs.validators.min_len(1), attrs.validators.max_len(32)],
)
columns: list[ColumnsInput] = field(factory=list)
@define
class PlanogramsBulkInputPayload:
planograms: list[PlanogramInput] = field(factory=list)

View File

@ -9,8 +9,8 @@ from benchmark.pydantic_benchmark.models import (
) )
COLUMNS_COUNT = 100 COLUMNS_COUNT = 1000
PLANOGRAMS_COUNT = 100 PLANOGRAMS_COUNT = 1000
class ColumnsInputFactory(ModelFactory): class ColumnsInputFactory(ModelFactory):

View File

@ -21,12 +21,12 @@ class CorrelationId(Struct, rename="camel"):
class ColumnsInput(Struct, rename="camel"): class ColumnsInput(Struct, rename="camel"):
column_number: StrictSmallInt column_number: StrictSmallInt
external_product_id: Optional[ExternalId] = field(default=None) external_product_id: Optional[ExternalId] = None
old_qty: Optional[QuantityInt] = field(default_factory=lambda: None) old_qty: Optional[QuantityInt] = None
new_qty: Optional[QuantityInt] = field(default_factory=lambda: None) new_qty: Optional[QuantityInt] = None
old_price: Optional[PriceFloat] = field(default_factory=lambda: None) old_price: Optional[PriceFloat] = None
new_price: Optional[PriceFloat] = field(default_factory=lambda: None) new_price: Optional[PriceFloat] = None
select_map: Optional[list[StrictSmallInt]] = field(default_factory=lambda: None) select_map: Optional[list[StrictSmallInt]] = None
item_type: Optional[ColumnItemType] = field( item_type: Optional[ColumnItemType] = field(
default_factory=lambda: ColumnItemType.PRODUCT default_factory=lambda: ColumnItemType.PRODUCT
) )
@ -36,16 +36,6 @@ class PlanogramInput(CorrelationId, Struct, rename="camel"):
machine_external_id: ExternalId = field(default="") machine_external_id: ExternalId = field(default="")
columns: list[ColumnsInput] = field(default_factory=list) columns: list[ColumnsInput] = field(default_factory=list)
# class Config:
# title = "Planogram"
# alias_generator = to_camel_case
# populate_by_name = True
# str_strip_whitespace = True
class PlanogramsBulkInputPayload(Struct, rename="camel"): class PlanogramsBulkInputPayload(Struct, rename="camel"):
planograms: list[PlanogramInput] = field(default_factory=list) planograms: list[PlanogramInput] = field(default_factory=list)
# class Config:
# populate_by_name = True
# alias_generator = to_camel_case

View File

@ -1,4 +1,6 @@
from pathlib import Path from pathlib import Path
from benchmark.attrs_benchmark.benchmark import AttrsBenchmark
from benchmark.factories import create_test_file from benchmark.factories import create_test_file
from benchmark.msgspec_benchmark.benchmark import MsgSpecBenchmark from benchmark.msgspec_benchmark.benchmark import MsgSpecBenchmark
from benchmark.pydantic_benchmark.benchmark import PydanticBenchmark from benchmark.pydantic_benchmark.benchmark import PydanticBenchmark
@ -12,10 +14,13 @@ def main(test_file: Path) -> None:
pydantic_benchmark = PydanticBenchmark(test_file) pydantic_benchmark = PydanticBenchmark(test_file)
pydantic_benchmark.execute() pydantic_benchmark.execute()
attrs_benchmark = AttrsBenchmark(test_file)
attrs_benchmark.execute()
msgspec_benchmark = MsgSpecBenchmark(test_file) msgspec_benchmark = MsgSpecBenchmark(test_file)
msgspec_benchmark.execute() msgspec_benchmark.execute()
if __name__ == "__main__": if __name__ == "__main__":
# create_test_file(TEST_DATA_FILE) # create_test_file(BIG_TEST_DATA_FILE)
main(TEST_DATA_FILE) main(BIG_TEST_DATA_FILE)

20
poetry.lock generated
View File

@ -11,6 +11,24 @@ files = [
{file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"},
] ]
[[package]]
name = "attrs"
version = "23.1.0"
description = "Classes Without Boilerplate"
optional = false
python-versions = ">=3.7"
files = [
{file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"},
{file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"},
]
[package.extras]
cov = ["attrs[tests]", "coverage[toml] (>=5.3)"]
dev = ["attrs[docs,tests]", "pre-commit"]
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"]
tests = ["attrs[tests-no-zope]", "zope-interface"]
tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
[[package]] [[package]]
name = "faker" name = "faker"
version = "19.9.0" version = "19.9.0"
@ -277,4 +295,4 @@ files = [
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.11" python-versions = "^3.11"
content-hash = "f67f7e3c078da6291615ead8743e8eb520d31e62bab449b5cd5f3e9b3b3f540e" content-hash = "43640240ca1c3ae251a946f70979654201b8adac0d9a770c92d64deb83d13610"

View File

@ -11,6 +11,7 @@ python = "^3.11"
pydantic = "^2.4.2" pydantic = "^2.4.2"
msgspec = "^0.18.4" msgspec = "^0.18.4"
polyfactory = "^2.9.0" polyfactory = "^2.9.0"
attrs = "^23.1.0"
[build-system] [build-system]

1
test_data-big.json Normal file

File diff suppressed because one or more lines are too long

1
test_data.json Normal file

File diff suppressed because one or more lines are too long