89 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			89 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			Python
		
	
	
# piker: trading gear for hackers
 | 
						|
# Copyright (C) Guillermo Rodriguez (in stewardship for piker0)
 | 
						|
 | 
						|
# This program is free software: you can redistribute it and/or modify
 | 
						|
# it under the terms of the GNU Affero General Public License as published by
 | 
						|
# the Free Software Foundation, either version 3 of the License, or
 | 
						|
# (at your option) any later version.
 | 
						|
 | 
						|
# This program is distributed in the hope that it will be useful,
 | 
						|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
# GNU Affero General Public License for more details.
 | 
						|
 | 
						|
# You should have received a copy of the GNU Affero General Public License
 | 
						|
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
"""
 | 
						|
Built-in (extension) types.
 | 
						|
 | 
						|
"""
 | 
						|
import sys
 | 
						|
from typing import Optional
 | 
						|
from pprint import pformat
 | 
						|
 | 
						|
import msgspec
 | 
						|
 | 
						|
 | 
						|
class Struct(
 | 
						|
    msgspec.Struct,
 | 
						|
 | 
						|
    # https://jcristharif.com/msgspec/structs.html#tagged-unions
 | 
						|
    # tag='pikerstruct',
 | 
						|
    # tag=True,
 | 
						|
):
 | 
						|
    '''
 | 
						|
    A "human friendlier" (aka repl buddy) struct subtype.
 | 
						|
 | 
						|
    '''
 | 
						|
    def to_dict(self) -> dict:
 | 
						|
        return {
 | 
						|
            f: getattr(self, f)
 | 
						|
            for f in self.__struct_fields__
 | 
						|
        }
 | 
						|
 | 
						|
    # Lul, doesn't seem to work that well..
 | 
						|
    # def __repr__(self):
 | 
						|
    #     # only turn on pprint when we detect a python REPL
 | 
						|
    #     # at runtime B)
 | 
						|
    #     if (
 | 
						|
    #         hasattr(sys, 'ps1')
 | 
						|
    #         # TODO: check if we're in pdb
 | 
						|
    #     ):
 | 
						|
    #         return self.pformat()
 | 
						|
 | 
						|
    #     return super().__repr__()
 | 
						|
 | 
						|
    def pformat(self) -> str:
 | 
						|
        return f'Struct({pformat(self.to_dict())})'
 | 
						|
 | 
						|
    def copy(
 | 
						|
        self,
 | 
						|
        update: Optional[dict] = None,
 | 
						|
 | 
						|
    ) -> msgspec.Struct:
 | 
						|
        '''
 | 
						|
        Validate-typecast all self defined fields, return a copy of us
 | 
						|
        with all such fields.
 | 
						|
 | 
						|
        This is kinda like the default behaviour in `pydantic.BaseModel`.
 | 
						|
 | 
						|
        '''
 | 
						|
        if update:
 | 
						|
            for k, v in update.items():
 | 
						|
                setattr(self, k, v)
 | 
						|
 | 
						|
        # roundtrip serialize to validate
 | 
						|
        return msgspec.msgpack.Decoder(
 | 
						|
            type=type(self)
 | 
						|
        ).decode(
 | 
						|
            msgspec.msgpack.Encoder().encode(self)
 | 
						|
        )
 | 
						|
 | 
						|
    def typecast(
 | 
						|
        self,
 | 
						|
        # fields: Optional[list[str]] = None,
 | 
						|
    ) -> None:
 | 
						|
        for fname, ftype in self.__annotations__.items():
 | 
						|
            setattr(self, fname, ftype(getattr(self, fname)))
 |