t | def Record(slots_str, **readonly_fields): | t | def Record(slots_str, **readonly_fields): |
| | | |
| def decorator(cls): | | def decorator(cls): |
| if not hasattr(cls, '__slots__'): | | if not hasattr(cls, '__slots__'): |
| raise TypeError('Class must use __slots__ as its object model') | | raise TypeError('Class must use __slots__ as its object model') |
| new_slots = sorted(set(cls.__slots__) | set(slots_str.split())) | | new_slots = sorted(set(cls.__slots__) | set(slots_str.split())) |
| setattr(cls, '__slots__', new_slots) | | setattr(cls, '__slots__', new_slots) |
| for field in dir(cls): | | for field in dir(cls): |
| if field.startswith('_') is False: | | if field.startswith('_') is False: |
| setattr(cls, field, getattr(cls, field)) | | setattr(cls, field, getattr(cls, field)) |
| for field, value in readonly_fields.items(): | | for field, value in readonly_fields.items(): |
| if field.startswith('_') is False: | | if field.startswith('_') is False: |
| setattr(cls, field, value) | | setattr(cls, field, value) |
| | | |
| def set_obj(self, attr, value): | | def set_obj(self, attr, value): |
| if attr in cls.__slots__: | | if attr in cls.__slots__: |
| setattr(cls, attr, value) | | setattr(cls, attr, value) |
| cls.__setattr__ = set_obj | | cls.__setattr__ = set_obj |
| | | |
| def iter_obj(self): | | def iter_obj(self): |
| for attr in sorted(set(dir(cls) + cls.__slots__)): | | for attr in sorted(set(dir(cls) + cls.__slots__)): |
| if not attr.startswith('_'): | | if not attr.startswith('_'): |
| yield attr | | yield attr |
| cls.__iter__ = iter_obj | | cls.__iter__ = iter_obj |
| | | |
| def str_obj(self): | | def str_obj(self): |
| parts = [] | | parts = [] |
| for attr in iter_obj(self): | | for attr in iter_obj(self): |
| value = getattr(self, attr, None) | | value = getattr(self, attr, None) |
| if attr in cls.__slots__ and value is not None: | | if attr in cls.__slots__ and value is not None: |
| parts.append(f'{attr}={value}') | | parts.append(f'{attr}={value}') |
| elif value is not None: | | elif value is not None: |
| parts.append(f'{attr}:{value}') | | parts.append(f'{attr}:{value}') |
| else: | | else: |
| parts.append(attr) | | parts.append(attr) |
| return '|'.join(parts) | | return '|'.join(parts) |
| cls.__str__ = str_obj | | cls.__str__ = str_obj |
| return cls | | return cls |
| return decorator | | return decorator |