@@ -449,6 +449,26 @@ def get_tag(constr_id: int) -> Optional[int]:
449
449
return None
450
450
451
451
452
+ def get_constructor_id_and_fields (
453
+ raw_tag : CBORTag ,
454
+ ) -> typing .Tuple [int , typing .List [Any ]]:
455
+ tag = raw_tag .tag
456
+ if tag == 102 :
457
+ if len (raw_tag .value ) != 2 :
458
+ raise DeserializeException (
459
+ f"Expect the length of value to be exactly 2, got { len (raw_tag .value )} instead."
460
+ )
461
+ return raw_tag .value [0 ], raw_tag .value [1 ]
462
+ else :
463
+ if 121 <= tag < 128 :
464
+ constr = tag - 121
465
+ elif 1280 <= tag < 1536 :
466
+ constr = tag - 1280 + 7
467
+ else :
468
+ raise DeserializeException (f"Unexpected tag for RawPlutusData: { tag } " )
469
+ return constr , raw_tag .value
470
+
471
+
452
472
def id_map (cls , skip_constructor = False ):
453
473
"""
454
474
Constructs a unique representation of a PlutusData type definition.
@@ -579,14 +599,12 @@ def from_primitive(cls: Type[PlutusData], value: CBORTag) -> PlutusData:
579
599
def hash (self ) -> DatumHash :
580
600
return datum_hash (self )
581
601
582
- def to_json (self , ** kwargs ) -> str :
583
- """Convert to a json string
584
-
585
- Args:
586
- **kwargs: Extra key word arguments to be passed to `json.dumps()`
602
+ def to_dict (self ) -> dict :
603
+ """
604
+ Convert to a dictionary.
587
605
588
606
Returns:
589
- str: a JSON encoded PlutusData .
607
+ str: a dict PlutusData that can be JSON encoded.
590
608
"""
591
609
592
610
def _dfs (obj ):
@@ -610,10 +628,26 @@ def _dfs(obj):
610
628
"constructor" : obj .CONSTR_ID ,
611
629
"fields" : [_dfs (getattr (obj , f .name )) for f in fields (obj )],
612
630
}
631
+ elif isinstance (obj , RawPlutusData ):
632
+ return obj .to_dict ()
633
+ elif isinstance (obj , RawCBOR ):
634
+ return RawPlutusData .from_cbor (obj .cbor ).to_dict ()
613
635
else :
614
636
raise TypeError (f"Unexpected type { type (obj )} " )
615
637
616
- return json .dumps (_dfs (self ), ** kwargs )
638
+ return _dfs (self )
639
+
640
+ def to_json (self , ** kwargs ) -> str :
641
+ """Convert to a json string
642
+
643
+ Args:
644
+ **kwargs: Extra key word arguments to be passed to `json.dumps()`
645
+
646
+ Returns:
647
+ str: a JSON encoded PlutusData.
648
+ """
649
+
650
+ return json .dumps (self .to_dict (), ** kwargs )
617
651
618
652
@classmethod
619
653
def from_dict (cls : Type [PlutusData ], data : dict ) -> PlutusData :
@@ -640,6 +674,8 @@ def _dfs(obj):
640
674
f_info .type , PlutusData
641
675
):
642
676
converted_fields .append (f_info .type .from_dict (f ))
677
+ elif f_info .type == Datum :
678
+ converted_fields .append (RawPlutusData .from_dict (f ))
643
679
elif (
644
680
hasattr (f_info .type , "__origin__" )
645
681
and f_info .type .__origin__ is Union
@@ -765,11 +801,104 @@ def _dfs(obj):
765
801
766
802
return _dfs (self .data )
767
803
804
+ def to_dict (self ) -> dict :
805
+ """
806
+ Convert to a dictionary.
807
+
808
+ Returns:
809
+ str: a dict RawPlutusData that can be JSON encoded.
810
+ """
811
+
812
+ def _dfs (obj ):
813
+ if isinstance (obj , int ):
814
+ return {"int" : obj }
815
+ elif isinstance (obj , bytes ):
816
+ return {"bytes" : obj .hex ()}
817
+ elif isinstance (obj , ByteString ):
818
+ return {"bytes" : obj .value .hex ()}
819
+ elif isinstance (obj , IndefiniteList ) or isinstance (obj , list ):
820
+ return {"list" : [_dfs (item ) for item in obj ]}
821
+ elif isinstance (obj , dict ):
822
+ return {"map" : [{"v" : _dfs (v ), "k" : _dfs (k )} for k , v in obj .items ()]}
823
+ elif isinstance (obj , CBORTag ):
824
+ constructor , fields = get_constructor_id_and_fields (obj )
825
+ return {"constructor" : constructor , "fields" : [_dfs (f ) for f in fields ]}
826
+ raise TypeError (f"Unexpected type { type (obj )} " )
827
+
828
+ return _dfs (RawPlutusData .to_primitive (self ))
829
+
830
+ def to_json (self , ** kwargs ) -> str :
831
+ """Convert to a json string
832
+
833
+ Args:
834
+ **kwargs: Extra key word arguments to be passed to `json.dumps()`
835
+
836
+ Returns:
837
+ str: a JSON encoded RawPlutusData.
838
+ """
839
+
840
+ return json .dumps (RawPlutusData .to_dict (self ), ** kwargs )
841
+
768
842
@classmethod
769
843
@limit_primitive_type (CBORTag )
770
844
def from_primitive (cls : Type [RawPlutusData ], value : CBORTag ) -> RawPlutusData :
771
845
return cls (value )
772
846
847
+ @classmethod
848
+ def from_dict (cls : Type [RawPlutusData ], data : dict ) -> RawPlutusData :
849
+ """Convert a dictionary to RawPlutusData
850
+
851
+ Args:
852
+ data (dict): A dictionary.
853
+
854
+ Returns:
855
+ RawPlutusData: Restored RawPlutusData.
856
+ """
857
+
858
+ def _dfs (obj ):
859
+ if isinstance (obj , dict ):
860
+ if "constructor" in obj :
861
+ converted_fields = []
862
+ for f in obj ["fields" ]:
863
+ converted_fields .append (_dfs (f ))
864
+ tag = get_tag (obj ["constructor" ])
865
+ if tag is None :
866
+ return CBORTag (
867
+ 102 , [obj ["constructor" ], IndefiniteList (converted_fields )]
868
+ )
869
+ else :
870
+ return CBORTag (tag , converted_fields )
871
+ elif "map" in obj :
872
+ return {_dfs (pair ["k" ]): _dfs (pair ["v" ]) for pair in obj ["map" ]}
873
+ elif "int" in obj :
874
+ return obj ["int" ]
875
+ elif "bytes" in obj :
876
+ if len (obj ["bytes" ]) > 64 :
877
+ return ByteString (bytes .fromhex (obj ["bytes" ]))
878
+ else :
879
+ return bytes .fromhex (obj ["bytes" ])
880
+ elif "list" in obj :
881
+ return IndefiniteList ([_dfs (item ) for item in obj ["list" ]])
882
+ else :
883
+ raise DeserializeException (f"Unexpected data structure: { obj } " )
884
+ else :
885
+ raise TypeError (f"Unexpected data type: { type (obj )} " )
886
+
887
+ return cls (_dfs (data ))
888
+
889
+ @classmethod
890
+ def from_json (cls : Type [RawPlutusData ], data : str ) -> RawPlutusData :
891
+ """Restore a json encoded string to a RawPlutusData.
892
+
893
+ Args:
894
+ data (str): An encoded json string.
895
+
896
+ Returns:
897
+ RawPlutusData: The restored RawPlutusData.
898
+ """
899
+ obj = json .loads (data )
900
+ return cls .from_dict (obj )
901
+
773
902
def __deepcopy__ (self , memo ):
774
903
return self .__class__ .from_cbor (self .to_cbor_hex ())
775
904
0 commit comments