Skip to content
This repository has been archived by the owner on Jun 14, 2021. It is now read-only.

Commit

Permalink
Merge pull request #165 from benoit-dubreuil/feature/#162/supply-gene…
Browse files Browse the repository at this point in the history
…rics-helper-mixin-to-detect-typevars

Feature/#162/supply generics helper mixin to detect typevars
  • Loading branch information
benoit-dubreuil committed Apr 16, 2021
2 parents 8648bd1 + eff2c03 commit 55a7d83
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 0 deletions.
Empty file.
Empty file.
10 changes: 10 additions & 0 deletions conf/script/src/utils/meta_prog/generics/cls_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import utils.meta_prog.generics.data


class GenericClassMixin(utils.meta_prog.generics.data.GenericsDataMixin):

def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)

def has_generics(self) -> bool:
return len(self.generics_by_type_vars) > 0
51 changes: 51 additions & 0 deletions conf/script/src/utils/meta_prog/generics/cls_proxy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import itertools

import utils.meta_prog.generics.cls_wrapper
import utils.meta_prog.generics.data


class GenericClassProxy(utils.meta_prog.generics.data.GenericsDataMixin,
utils.meta_prog.generics.cls_wrapper.GenericClassWrapperMixin):
from typing import TypeVar

def __init__(self,
generic_cls: utils.meta_prog.generics.cls_wrapper.GenericClassWrapperMixin.TAlias_generic_cls,
*args,
generics: tuple[type] = tuple(),
**kwargs) -> None:
generics_by_type_vars = self.__create_generics_by_type_vars(generic_cls=generic_cls, generics=generics)
super().__init__(*args, generic_cls=generic_cls, generics_by_type_vars=generics_by_type_vars, **kwargs)

def __call__(self, *args, **kwargs):
return self.wrapped_generic_cls(*args, generics_by_type_vars=self.generics_by_type_vars, **kwargs)

@classmethod
def __create_generics_by_type_vars(cls,
generic_cls: utils.meta_prog.generics.cls_wrapper.GenericClassWrapperMixin.TAlias_generic_cls,
generics: tuple[type]) \
-> utils.meta_prog.generics.data.GenericsDataMixin.TAlias_Generics_By_TypeVars:
type_vars = cls.__detect_type_vars(generic_cls=generic_cls)
generics_by_type_vars = dict(itertools.zip_longest(type_vars, generics, fillvalue=None))

return generics_by_type_vars

@classmethod
def __detect_type_vars(cls,
generic_cls: utils.meta_prog.generics.cls_wrapper.GenericClassWrapperMixin.TAlias_generic_cls) \
-> list[TypeVar]:
from typing import TypeVar, Generic, get_args, get_origin

type_vars: list[TypeVar] = []

for orig_base in generic_cls.__orig_bases__:
if get_origin(orig_base) is Generic:
base_type_args = get_args(orig_base)

if len(base_type_args) > 0:
for type_arg in base_type_args:
if isinstance(type_arg, TypeVar):
type_vars.append(type_arg)
else:
type_vars += cls.__detect_type_vars(generic_cls=orig_base)

return type_vars
27 changes: 27 additions & 0 deletions conf/script/src/utils/meta_prog/generics/cls_proxy_injector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import typing

import utils.meta_prog.generics.cls_mixin


class GenericClassProxyInjectorMixin(utils.meta_prog.generics.cls_mixin.GenericClassMixin):
import utils.meta_prog.generics.cls_proxy

__TAlias_Generics_Subscript_Op = typing.Optional[typing.Union[tuple, type]]

def __init__(self,
*args,
generics_by_type_vars: utils.meta_prog.generics.cls_mixin.GenericClassMixin.TAlias_Generics_By_TypeVars = None,
**kwargs) -> None:
if generics_by_type_vars is None:
generic_cls = type(self)
generics = tuple()
cls_proxy = utils.meta_prog.generics.cls_proxy.GenericClassProxy(generic_cls=generic_cls, generics=generics)

generics_by_type_vars = cls_proxy.generics_by_type_vars

super().__init__(*args, generics_by_type_vars=generics_by_type_vars, **kwargs)

@classmethod
def __class_getitem__(cls, item: __TAlias_Generics_Subscript_Op):
generics = item if isinstance(item, tuple) else (item,)
return utils.meta_prog.generics.cls_proxy.GenericClassProxy(generic_cls=cls, generics=generics)
11 changes: 11 additions & 0 deletions conf/script/src/utils/meta_prog/generics/cls_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import utils.meta_prog.generics.cls_wrapper_data


class GenericClassWrapperMixin(utils.meta_prog.generics.cls_wrapper_data.GenericClassWrapperDataMixin):

def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)

@property
def __class__(self) -> utils.meta_prog.generics.cls_wrapper_data.GenericClassWrapperDataMixin.TAlias_generic_cls:
return self.wrapped_generic_cls
13 changes: 13 additions & 0 deletions conf/script/src/utils/meta_prog/generics/cls_wrapper_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import typing

import utils.meta_prog.generics.cls_mixin


class GenericClassWrapperDataMixin:
TAlias_generic_cls = type[utils.meta_prog.generics.cls_mixin.GenericClassMixin, typing.Generic]

wrapped_generic_cls: typing.Final[TAlias_generic_cls]

def __init__(self, generic_cls: TAlias_generic_cls, *args, **kwargs) -> None:
self.wrapped_generic_cls = generic_cls
super().__init__(*args, **kwargs)
13 changes: 13 additions & 0 deletions conf/script/src/utils/meta_prog/generics/data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import typing


class GenericsDataMixin:
TAlias_Generics_By_TypeVars = dict[typing.TypeVar, typing.Optional[type]]

generics_by_type_vars: typing.Final[TAlias_Generics_By_TypeVars]

def __init__(self, *args,
generics_by_type_vars: TAlias_Generics_By_TypeVars = None,
**kwargs) -> None:
self.generics_by_type_vars = generics_by_type_vars if generics_by_type_vars is not None else {}
super().__init__(*args, **kwargs)

0 comments on commit 55a7d83

Please sign in to comment.