Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TupleDataclass #590

Merged
merged 6 commits into from Dec 14, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Empty file.
41 changes: 41 additions & 0 deletions starknet_py/utils/tuple_dataclass.py
@@ -0,0 +1,41 @@
from __future__ import annotations
from dataclasses import dataclass, fields, make_dataclass
from typing import Dict, Optional, Tuple


@dataclass(frozen=True)
class TupleDataclass:
"""
Dataclass that behaves like a tuple at the same time.
"""

# getattr is called when attribute is not found in object. For instance when using object.unknown_attribute.
# This way pyright will know that there might be some arguments it doesn't know about and will stop complaining
# about some fields that don't exist statically.
def __getattr__(self, item):
# This should always fail - only attributes that don't exist end up in here.
# We use __getattribute__ to get the native error.
return super().__getattribute__(item)
Solpatium marked this conversation as resolved.
Show resolved Hide resolved
cptartur marked this conversation as resolved.
Show resolved Hide resolved

def __getitem__(self, item: int):
field = fields(self)[item]
Solpatium marked this conversation as resolved.
Show resolved Hide resolved
return getattr(self, field.name)

def __iter__(self):
return (getattr(self, field.name) for field in fields(self))

def as_tuple(self) -> Tuple:
return tuple(self)

def as_dict(self) -> Dict:
return {field.name: getattr(self, field.name) for field in fields(self)}

@staticmethod
def from_dict(data: Dict, *, name: Optional[str] = None) -> TupleDataclass:
result_class = make_dataclass(
name or "TupleDataclass",
fields=[(key, type(value)) for key, value in data.items()],
bases=(TupleDataclass,),
frozen=True,
)
return result_class(**data)
22 changes: 22 additions & 0 deletions starknet_py/utils/tuple_dataclass_test.py
@@ -0,0 +1,22 @@
from starknet_py.utils.tuple_dataclass import TupleDataclass


def test_wrapped_named_tuple():
input_dict = {
"first": 1,
"second": 2,
"third": {"key": "value"},
}
input_tuple = tuple(input_dict.values())

result = TupleDataclass.from_dict(input_dict)
assert result.as_tuple() == input_tuple
assert result.as_dict() == input_dict
assert (result[0], result[1], result[2]) == input_tuple
assert (result.first, result.second, result.third) == input_tuple
assert str(result) == "TupleDataclass(first=1, second=2, third={'key': 'value'})"
assert repr(result) == "TupleDataclass(first=1, second=2, third={'key': 'value'})"

result = TupleDataclass.from_dict(input_dict, name="CustomClass")
assert str(result) == "CustomClass(first=1, second=2, third={'key': 'value'})"
assert repr(result) == "CustomClass(first=1, second=2, third={'key': 'value'})"