mirror of
				https://github.com/pocketpy/pocketpy
				synced 2025-10-31 08:50: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} |