Skip to content

Commit 26e0dac

Browse files
committed
Add to_json for RawPlutusData
1 parent df5ba28 commit 26e0dac

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

pycardano/plutus.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,26 @@ def get_tag(constr_id: int) -> Optional[int]:
449449
return None
450450

451451

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+
452472
def id_map(cls, skip_constructor=False):
453473
"""
454474
Constructs a unique representation of a PlutusData type definition.
@@ -610,6 +630,10 @@ def _dfs(obj):
610630
"constructor": obj.CONSTR_ID,
611631
"fields": [_dfs(getattr(obj, f.name)) for f in fields(obj)],
612632
}
633+
elif isinstance(obj, RawPlutusData):
634+
return obj.to_json()
635+
elif isinstance(obj, RawCBOR):
636+
return RawPlutusData.from_cbor(obj.cbor).to_json()
613637
else:
614638
raise TypeError(f"Unexpected type {type(obj)}")
615639

@@ -765,6 +789,25 @@ def _dfs(obj):
765789

766790
return _dfs(self.data)
767791

792+
def to_json(self, **kwargs) -> str:
793+
def _dfs(obj):
794+
if isinstance(obj, int):
795+
return {"int": obj}
796+
elif isinstance(obj, bytes):
797+
return {"bytes": obj.hex()}
798+
elif isinstance(obj, ByteString):
799+
return {"bytes": obj.value.hex()}
800+
elif isinstance(obj, IndefiniteList) or isinstance(obj, list):
801+
return {"list": [_dfs(item) for item in obj]}
802+
elif isinstance(obj, dict):
803+
return {"map": [{"v": _dfs(v), "k": _dfs(k)} for k, v in obj.items()]}
804+
elif isinstance(obj, CBORTag):
805+
constructor, fields = get_constructor_id_and_fields(obj)
806+
return {"constructor": constructor, "fields": [_dfs(f) for f in fields]}
807+
raise TypeError(f"Unexpected type {type(obj)}")
808+
809+
return json.dumps(_dfs(self.to_primitive()), **kwargs)
810+
768811
@classmethod
769812
@limit_primitive_type(CBORTag)
770813
def from_primitive(cls: Type[RawPlutusData], value: CBORTag) -> RawPlutusData:

test/pycardano/test_plutus.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,31 @@ def test_plutus_data_from_json_wrong_data_structure_type():
207207
MyTest.from_json(test)
208208

209209

210+
def test_raw_plutus_data_json():
211+
key_hash = bytes.fromhex("c2ff616e11299d9094ce0a7eb5b7284b705147a822f4ffbd471f971a")
212+
deadline = 1643235300000
213+
testa = BigTest(MyTest(123, b"1234", IndefiniteList([4, 5, 6]), {1: b"1", 2: b"2"}))
214+
testb = LargestTest()
215+
216+
my_vesting = VestingParam(
217+
beneficiary=key_hash, deadline=deadline, testa=testa, testb=testb
218+
)
219+
220+
encoded_json = RawPlutusData(my_vesting.to_primitive()).to_json(
221+
separators=(",", ":")
222+
)
223+
224+
assert (
225+
'{"constructor":1,"fields":[{"bytes":"c2ff616e11299d9094ce0a7eb5b7284b705147a822f4ffbd471f971a"},'
226+
'{"int":1643235300000},{"constructor":8,"fields":[{"constructor":130,"fields":[{"int":123},'
227+
'{"bytes":"31323334"},{"list":[{"int":4},{"int":5},{"int":6}]},{"map":[{"v":{"bytes":"31"},'
228+
'"k":{"int":1}},{"v":{"bytes":"32"},"k":{"int":2}}]}]}]},{"constructor":9,"fields":[]}]}'
229+
== encoded_json
230+
)
231+
232+
assert my_vesting == VestingParam.from_json(encoded_json)
233+
234+
210235
def test_plutus_data_hash():
211236
assert (
212237
"923918e403bf43c34b4ef6b48eb2ee04babed17320d8d1b9ff9ad086e86f44ec"

0 commit comments

Comments
 (0)