Skip to content

Commit

Permalink
feat: use reflection for parsing dataclasses
Browse files Browse the repository at this point in the history
  • Loading branch information
leynier committed Nov 1, 2021
1 parent d224ec1 commit 3d226f5
Showing 1 changed file with 35 additions and 23 deletions.
58 changes: 35 additions & 23 deletions gotrue/types.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,31 @@
from dataclasses import dataclass
from enum import Enum
from inspect import signature
from json import dumps
from time import time
from typing import Any, Callable, Dict, Optional, TypeVar
from typing import Any, Callable, Dict, Optional, Type, TypeVar

T = TypeVar("T")


def parse_none(
value: Optional[T],
func: Callable[[Any], T],
) -> Optional[T]:
if value is None:
def parse_none(v: Optional[T], f: Callable[[Any], T]) -> Optional[T]:
if v is None:
return None
return func(value)
return f(v)


def parse_dict(cls: Type[T], **json: dict) -> T:
cls_fields = {field for field in signature(cls).parameters}
native_args, new_args = {}, {}
for name, val in json.items():
if name in cls_fields:
native_args[name] = val
else:
new_args[name] = val
ret = cls(**native_args)
for new_name, new_val in new_args.items():
setattr(ret, new_name, new_val)
return ret


@dataclass
Expand All @@ -25,8 +37,8 @@ def __post_init__(self) -> None:
self.msg = str(self.msg)
self.code = int(str(self.code))

@staticmethod
def from_dict(data: dict) -> "ApiError":
@classmethod
def from_dict(cls, data: dict) -> "ApiError":
if "msg" in data and "code" in data:
return ApiError(
msg=data["msg"],
Expand All @@ -41,7 +53,7 @@ def from_dict(data: dict) -> "ApiError":
msg=data["error_description"],
code=code,
)
return ApiError(**data)
return parse_dict(cls, **data)

def to_dict(self) -> Dict[str, Any]:
return {
Expand Down Expand Up @@ -78,9 +90,9 @@ def __post_init__(self) -> None:
self.path = str(self.path)
self.same_site = str(self.same_site)

@staticmethod
def from_dict(data: dict) -> "CookieOptions":
return CookieOptions(**data)
@classmethod
def from_dict(cls, data: dict) -> "CookieOptions":
return parse_dict(cls, **data)

def to_dict(self) -> Dict[str, Any]:
return {
Expand Down Expand Up @@ -133,9 +145,9 @@ def __post_init__(self) -> None:
self.user_metadata = parse_none(self.user_metadata, dict)
self.invited_at = parse_none(self.invited_at, str)

@staticmethod
def from_dict(data: dict) -> "User":
return User(**data)
@classmethod
def from_dict(cls, data: dict) -> "User":
return parse_dict(cls, **data)

def to_dict(self) -> Dict[str, Any]:
return {
Expand Down Expand Up @@ -176,9 +188,9 @@ def __post_init__(self) -> None:
self.password = parse_none(self.password, str)
self.email_change_token = parse_none(self.email_change_token, str)

@staticmethod
def from_dict(data: dict) -> "UserAttributes":
return UserAttributes(**data)
@classmethod
def from_dict(cls, data: dict) -> "UserAttributes":
return parse_dict(cls, **data)

def to_dict(self) -> Dict[str, Any]:
return {
Expand Down Expand Up @@ -214,14 +226,14 @@ def __post_init__(self) -> None:
if self.user:
self.user.__post_init__()

@staticmethod
def from_dict(data: dict) -> "Session":
@classmethod
def from_dict(cls, data: dict) -> "Session":
user: Optional[User] = None
user_data = data.get("user")
if user_data:
user = User.from_dict(user_data)
del data["user"]
return Session(**data, user=user)
data["user"] = user
return parse_dict(cls, **data)

def to_dict(self) -> Dict[str, Any]:
data: Dict[str, Any] = {
Expand Down

0 comments on commit 3d226f5

Please sign in to comment.