73 lines
2.5 KiB
Python
Executable File
73 lines
2.5 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
# https://github.com/FelixTheC/strongtyping/tree/main?tab=readme-ov-file
|
|
# git clone --depth 1 --recurse-submodules --shallow-submodules https://github.com/FelixTheC/strongtyping.git
|
|
|
|
import dataclasses
|
|
import inspect
|
|
import itertools
|
|
import typing
|
|
from functools import wraps
|
|
from inspect import signature
|
|
from types import *
|
|
from typing import *
|
|
|
|
from ._logger_ import log
|
|
from ._typeCheck_ import *
|
|
|
|
# TODO setattr verification
|
|
|
|
# == patch dataclass
|
|
def patchDataClassWithRunTimeValidator():
|
|
postInitStr = '__post_init__'
|
|
initStr = '__init__'
|
|
|
|
def _dataclassWrap(*args, **kargs):
|
|
ret = dataclasses._process_class_hidden(*args, **kargs)
|
|
|
|
def wrapOut(init):
|
|
def wrapIn(self, *args, **kargs):
|
|
__logIgnoreFrame__ = True
|
|
# log.info(type(self), args, kargs)
|
|
#| `init` is the class's __init__
|
|
#| `self` is the instantiated object
|
|
res = init(self, *args, **kargs) #| probably always None
|
|
|
|
myMod = inspect.getmodule(patchDataClassWithRunTimeValidator)
|
|
resMod = inspect.getmodule(self.__class__)
|
|
# log.info(self.__class__, myMod.__package__, resMod.__package__, resMod.__name__)
|
|
if (
|
|
myMod.__package__ != resMod.__package__ and # different package
|
|
resMod.__name__ != '__main__' # not defined in __main__
|
|
):
|
|
return res
|
|
|
|
#| validate args after __post_init__
|
|
checkObjectType(obj=self)
|
|
return res
|
|
|
|
return wrapIn
|
|
|
|
if (init := getattr(ret, initStr) if hasattr(ret, initStr) else None):
|
|
#| override signiture
|
|
try:
|
|
sig = signature(ret)
|
|
except ValueError as e:
|
|
e.add_note(str(ret))
|
|
e.add_note('make sure self is defined in function params.')
|
|
raise e
|
|
|
|
res = wrapOut(init)
|
|
res.__signature__ = sig
|
|
setattr(ret, initStr, res)
|
|
return ret
|
|
|
|
if not hasattr(dataclasses, '_process_class_hidden'):
|
|
dataclasses._process_class_hidden = dataclasses._process_class
|
|
dataclasses._process_class = _dataclassWrap
|
|
|
|
def unpatchDataClassWithRunTimeValidator():
|
|
if hasattr(dataclasses, '_process_class_hidden'):
|
|
dataclasses._process_class = dataclasses._process_class_hidden
|
|
del dataclasses._process_class_hidden
|