mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
75 lines
2.4 KiB
Python
75 lines
2.4 KiB
Python
def _get_annotations(cls: type):
|
|
inherits = []
|
|
while cls is not object:
|
|
inherits.append(cls)
|
|
cls = cls.__base__
|
|
inherits.reverse()
|
|
res = {}
|
|
for cls in inherits:
|
|
res.update(cls.__annotations__)
|
|
return res.keys()
|
|
|
|
def _wrapped__init__(self, *args, **kwargs):
|
|
cls = type(self)
|
|
cls_d = cls.__dict__
|
|
fields = _get_annotations(cls)
|
|
i = 0 # index into args
|
|
for field in fields:
|
|
if field in kwargs:
|
|
setattr(self, field, kwargs.pop(field))
|
|
else:
|
|
if i < len(args):
|
|
setattr(self, field, args[i])
|
|
i += 1
|
|
elif field in cls_d: # has default value
|
|
setattr(self, field, cls_d[field])
|
|
else:
|
|
raise TypeError(f"{cls.__name__} missing required argument {field!r}")
|
|
if len(args) > i:
|
|
raise TypeError(f"{cls.__name__} takes {len(fields)} positional arguments but {len(args)} were given")
|
|
if len(kwargs) > 0:
|
|
raise TypeError(f"{cls.__name__} got an unexpected keyword argument {next(iter(kwargs))!r}")
|
|
|
|
def _wrapped__repr__(self):
|
|
fields = _get_annotations(type(self))
|
|
obj_d = self.__dict__
|
|
args: list = [f"{field}={obj_d[field]!r}" for field in fields]
|
|
return f"{type(self).__name__}({', '.join(args)})"
|
|
|
|
def _wrapped__eq__(self, other):
|
|
if type(self) is not type(other):
|
|
return False
|
|
fields = _get_annotations(type(self))
|
|
for field in fields:
|
|
if getattr(self, field) != getattr(other, field):
|
|
return False
|
|
return True
|
|
|
|
def _wrapped__ne__(self, other):
|
|
return not self.__eq__(other)
|
|
|
|
def dataclass(cls: type):
|
|
assert type(cls) is type
|
|
cls_d = cls.__dict__
|
|
if '__init__' not in cls_d:
|
|
cls.__init__ = _wrapped__init__
|
|
if '__repr__' not in cls_d:
|
|
cls.__repr__ = _wrapped__repr__
|
|
if '__eq__' not in cls_d:
|
|
cls.__eq__ = _wrapped__eq__
|
|
if '__ne__' not in cls_d:
|
|
cls.__ne__ = _wrapped__ne__
|
|
fields = _get_annotations(cls)
|
|
has_default = False
|
|
for field in fields:
|
|
if field in cls_d:
|
|
has_default = True
|
|
else:
|
|
if has_default:
|
|
raise TypeError(f"non-default argument {field!r} follows default argument")
|
|
return cls
|
|
|
|
def asdict(obj) -> dict:
|
|
fields = _get_annotations(type(obj))
|
|
obj_d = obj.__dict__
|
|
return {field: obj_d[field] for field in fields} |