Skip to content

Changes to support running the client under future annotations #1

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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 25, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions servicestack/reflection.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import pathlib
import platform
import typing
import sys
from dataclasses import fields, is_dataclass
from datetime import datetime, timedelta
from enum import Enum, IntEnum, EnumMeta
Expand Down Expand Up @@ -58,7 +59,10 @@ def _get_type_vars_map(cls: Type, type_map=None):
generic_type_args = get_args(cls)
i = 0
for t in generic_def.__parameters__:
type_map[t] = generic_type_args[i]
k = t
if type(k) == TypeVar:
k = k.__name__
type_map[k] = generic_type_args[i]
i += 1
return type_map

Expand Down Expand Up @@ -232,9 +236,11 @@ def _resolve_forwardref(cls: Type, orig: Type = None):
return globals()[type_name]


def unwrap(cls: Type):
def unwrap(cls: Type, module:str):
if type(cls) == ForwardRef:
cls = _resolve_forwardref(cls)
if isinstance(cls, str):
cls = eval(cls, {}, vars(sys.modules[module]))
if is_optional(cls):
return generic_arg(cls)
return cls
Expand Down Expand Up @@ -282,16 +288,20 @@ def enum_get(cls: Union[Enum, Type], key: Union[str, int]):
raise TypeError(f"{key} is not a member of {nameof(Enum)}")


def _resolve_type(cls: Type, substitute_types: Dict[Type, type]):
def _resolve_type(cls: Type, substitute_types: Dict[Type, type] ):
if type(cls) == TypeVar:
# TypeVar('T') == TypeVar('T') is false,
# I think this should work
cls = cls.__name__
if substitute_types is None:
return cls
return substitute_types[cls] if cls in substitute_types else cls


def convert(into: Type, obj: Any, substitute_types: Dict[Type, type] = None):
def convert(into: Type, obj: Any, substitute_types: Dict[Type, type] = None, module = None):
if obj is None:
return None
into = unwrap(into)
into = unwrap(into, module)
into = _resolve_type(into, substitute_types)
if Log.debug_enabled():
Log.debug(f"convert({into}, {substitute_types}, {obj})")
Expand All @@ -310,14 +320,14 @@ def convert(into: Type, obj: Any, substitute_types: Dict[Type, type] = None):
for f in fields(into):
val = dict_get(f.name, obj)
# print(f"to[{f.name}] = convert({f.type}, {val}, {substitute_types})")
to[f.name] = convert(f.type, val, substitute_types)
to[f.name] = convert(f.type, val, substitute_types, into.__module__)
# print(f"to[{f.name}] = {to[f.name]}")
return into(**to)
elif is_list(into):
el_type = _resolve_type(generic_arg(into), substitute_types)
to = []
for item in obj:
to.append(convert(el_type, item, substitute_types))
to.append(convert(el_type, item, substitute_types, into.__module__))
return to
elif is_dict(into):
key_type, val_type = generic_args(into)
Expand All @@ -327,8 +337,8 @@ def convert(into: Type, obj: Any, substitute_types: Dict[Type, type] = None):
if not hasattr(obj, 'items'):
Log.warn(f"dict {obj} ({type(type)}) does not have items()")
for key, val in obj.items():
to_key = convert(key_type, key, substitute_types)
to_val = convert(val_type, val, substitute_types)
to_key = convert(key_type, key, substitute_types, into.__module__)
to_val = convert(val_type, val, substitute_types, into.__module__)
to[to_key] = to_val
return to
else:
Expand Down