22
33import argparse
44import json
5- import os
65import subprocess
76import sys
87import tempfile
8+ from pathlib import Path
99from typing import TYPE_CHECKING
1010
1111from Cryptodome .Hash import keccak
12+ from pyk .cli .utils import file_path
1213from pyk .kast .inner import KApply , KSequence , KToken , Subst
1314from pyk .kast .manip import split_config_from
1415from pyk .kdist import kdist
1516from pyk .ktool .krun import KRun
1617from pyk .prelude .collections import set_of
18+ from pyk .utils import abs_or_rel_to , check_file_path
1719from pykwasm .kwasm_ast import KBytes , KInt , KString
1820
1921from kmultiversx .utils import (
@@ -294,7 +296,7 @@ def mandos_arguments_to_klist(arguments: list[str]) -> KInner:
294296 return ListBytes (wrapped )
295297
296298
297- def mandos_to_set_account (address : str , sections : dict , filename : str , output_dir : str ) -> list [KApply ]:
299+ def mandos_to_set_account (address : str , sections : dict , filename : Path , output_dir : Path ) -> list [KApply ]:
298300 """Creates a K account cell from a Mandos account description."""
299301 address_value = mandos_argument_to_kbytes (address )
300302 nonce_value = mandos_int_to_kint (sections .get ('nonce' , '0' ))
@@ -404,7 +406,7 @@ def str_to_kast(s: str) -> KInner:
404406 return [str_to_kast (r ) for r in v ['roles' ]]
405407
406408
407- def mandos_to_check_account (address : str , sections : dict , filename : str ) -> list :
409+ def mandos_to_check_account (address : str , sections : dict , filename : Path ) -> list :
408410 k_steps : list [KInner ] = []
409411 address_value = mandos_argument_to_kbytes (address )
410412 if ('nonce' in sections ) and (sections ['nonce' ] != '*' ):
@@ -424,9 +426,8 @@ def mandos_to_check_account(address: str, sections: dict, filename: str) -> list
424426 storage_value = KMapBytesToBytes (wrapped_pairs )
425427 k_steps .append (KApply ('checkAccountStorage' , [address_value , storage_value ]))
426428 if ('code' in sections ) and (sections ['code' ] != '*' ):
427- code_path = get_contract_code (sections ['code' ], filename )
428- if code_path is None :
429- code_path = ''
429+ code_path_ = get_contract_code (sections ['code' ], filename )
430+ code_path = '' if code_path_ is None else str (code_path_ )
430431 k_code_path = KString (code_path )
431432 k_steps .append (KApply ('checkAccountCode' , [address_value , k_code_path ]))
432433 if ('esdt' in sections ) and (sections ['esdt' ] != '*' ):
@@ -447,15 +448,15 @@ def mandos_to_check_account(address: str, sections: dict, filename: str) -> list
447448 return k_steps
448449
449450
450- def mandos_to_deploy_tx (tx : dict , filename : str , output_dir : str ) -> KInner :
451+ def mandos_to_deploy_tx (tx : dict , filename : Path , output_dir : Path ) -> KInner :
451452 sender = mandos_argument_to_kbytes (tx ['from' ])
452453 value = mandos_int_to_kint (get_egld_value (tx ))
453454 arguments = mandos_arguments_to_klist (tx ['arguments' ])
454455 gas_limit = mandos_int_to_kint (tx ['gasLimit' ])
455456 gas_price = mandos_int_to_kint (tx .get ('gasPrice' , '0' ), default_when_empty = 0 )
456457
457458 code = get_contract_code (tx ['contractCode' ], filename )
458- assert isinstance ( code , str )
459+ assert code is not None
459460 module = file_to_module_decl (code , output_dir )
460461
461462 return KApply ('deployTx' , [sender , value , module , arguments , gas_limit , gas_price ])
@@ -576,24 +577,25 @@ def register(with_name: str) -> KInner:
576577 return KApply ('register' , [KString (with_name )])
577578
578579
579- def file_to_module_decl (filename : str , output_dir : str ) -> KInner :
580- if filename [ - 5 :] == '.wasm' :
580+ def file_to_module_decl (filename : Path , output_dir : Path ) -> KInner :
581+ if filename . suffix == '.wasm' :
581582 return load_wasm (filename )
582- if filename [ - 5 :] == '.wast' or filename [ - 4 :] == '.wat' :
583+ if filename . suffix == '.wast' or filename . suffix == '.wat' :
583584 return wat_file_to_module_decl (filename , output_dir )
584- if filename [ - 10 :] == '.mxsc.json' :
585+ if filename . name . endswith ( '.mxsc.json' ) :
585586 return load_wasm_from_mxsc (filename )
586587
587588 raise ValueError (f'Filetype not yet supported: { filename } ' )
588589
589590
590- def wat_file_to_module_decl (filename : str , output_dir : str ) -> KInner :
591- if not os .path .exists (filename ):
592- raise Exception (f'file { filename } does not exist' )
591+ def wat_file_to_module_decl (file_path : Path , output_dir : Path ) -> KInner :
592+ file_path = file_path .resolve ()
593+ check_file_path (file_path )
594+
595+ new_wasm_file_path = output_dir / file_path .with_suffix ('.wasm' ).name
593596
594- new_wasm_filename = os .path .join (output_dir , os .path .basename (filename ) + '.wasm' )
595597 try :
596- subprocess .check_output (f'wat2wasm { filename } --output={ new_wasm_filename } ' , shell = True )
598+ subprocess .check_output (f'wat2wasm { file_path } --output={ new_wasm_file_path } ' , shell = True )
597599 except subprocess .CalledProcessError as e :
598600 print ('Failed: %s' % e .cmd )
599601 print ('return code: %d' % e .returncode )
@@ -602,24 +604,22 @@ def wat_file_to_module_decl(filename: str, output_dir: str) -> KInner:
602604 print ('stderr:' )
603605 print (e .stderr )
604606 raise e
605- return load_wasm (new_wasm_filename )
607+ return load_wasm (new_wasm_file_path )
606608
607609
608- def get_external_file_path (test_file : str , rel_path_to_new_file : str ) -> str :
609- test_file_path = os .path .dirname (test_file )
610- ext_file = os .path .normpath (os .path .join (test_file_path , rel_path_to_new_file ))
611- return ext_file
610+ def get_external_file_path (test_file : Path , rel_path_to_new_file : Path ) -> Path :
611+ return abs_or_rel_to (rel_path_to_new_file , test_file .parent ).resolve ()
612612
613613
614- def get_contract_code (code : str , filename : str ) -> str | None :
614+ def get_contract_code (code : str , filename : Path ) -> Path | None :
615615 if code [0 :5 ] in ('file:' , 'mxsc:' ):
616- return get_external_file_path (filename , code [5 :])
616+ return get_external_file_path (filename , Path ( code [5 :]) )
617617 if code == '' :
618618 return None
619619 raise Exception ('Currently only support getting code from file, or empty code.' )
620620
621621
622- def get_steps_sc_deploy (step : dict , filename : str , output_dir : str ) -> list :
622+ def get_steps_sc_deploy (step : dict , filename : Path , output_dir : Path ) -> list :
623623 k_steps = []
624624 tx = mandos_to_deploy_tx (step ['tx' ], filename , output_dir )
625625 k_steps .append (tx )
@@ -682,7 +682,7 @@ def get_steps_new_addresses(new_addresses: dict | None) -> list[KApply]:
682682 return ret
683683
684684
685- def get_steps_set_state (step : dict , filename : str , output_dir : str ) -> list [KApply ]:
685+ def get_steps_set_state (step : dict , filename : Path , output_dir : Path ) -> list [KApply ]:
686686 k_steps : list [KApply ] = []
687687 if 'accounts' in step :
688688 set_accounts = [
@@ -706,7 +706,7 @@ def get_steps_set_state(step: dict, filename: str, output_dir: str) -> list[KApp
706706 return k_steps
707707
708708
709- def get_steps_check_state (step : dict , filename : str ) -> list :
709+ def get_steps_check_state (step : dict , filename : Path ) -> list :
710710 k_steps = []
711711 if 'accounts' in step :
712712 for address , sections in step ['accounts' ].items ():
@@ -720,8 +720,8 @@ def get_steps_check_state(step: dict, filename: str) -> list:
720720 return k_steps
721721
722722
723- def get_steps_as_kseq (filename : str , output_dir : str , args : argparse .Namespace ) -> list :
724- with open (filename ) as f :
723+ def get_steps_as_kseq (filename : Path , output_dir : Path , args : argparse .Namespace ) -> list :
724+ with filename . open () as f :
725725 mandos_test = json .loads (f .read ())
726726 if 'name' in mandos_test :
727727 if args .verbose :
@@ -743,7 +743,7 @@ def get_steps_as_kseq(filename: str, output_dir: str, args: argparse.Namespace)
743743 elif step ['step' ] == 'checkState' :
744744 k_steps .append ((step ['step' ], get_steps_check_state (step , filename )))
745745 elif step ['step' ] == 'externalSteps' :
746- steps_file = get_external_file_path (filename , step ['path' ])
746+ steps_file = get_external_file_path (filename , Path ( step ['path' ]) )
747747 print ('Load external: %s' % steps_file )
748748 k_steps = k_steps + get_steps_as_kseq (steps_file , output_dir , args )
749749 elif step ['step' ] == 'transfer' :
@@ -758,11 +758,11 @@ def get_steps_as_kseq(filename: str, output_dir: str, args: argparse.Namespace)
758758def run_test_file (
759759 krun : KRun ,
760760 template_wasm_config : KInner ,
761- test_file_path : str ,
762- output_dir : str ,
761+ test_file_path : Path ,
762+ output_dir : Path ,
763763 cmd_args : argparse .Namespace ,
764764) -> KInner :
765- test_name = os . path . basename ( test_file_path )
765+ test_name = test_file_path . stem
766766 k_steps = get_steps_as_kseq (test_file_path , output_dir , cmd_args )
767767 final_config = template_wasm_config
768768
@@ -805,17 +805,17 @@ def run_test_file(
805805# ... Setup Elrond Wasm
806806
807807
808- def log_intermediate_state (krun : KRun , name : str , config : KInner , output_dir : str ) -> None :
809- with open ( f' { output_dir } / { name } ' , 'w' ) as f :
810- f . write (kast_to_json_str (config ))
811- with open ( f' { output_dir } / { name } .pretty.k' , 'w' ) as f :
812- pretty = krun . pretty_print ( config )
813- f . write ( pretty )
808+ def log_intermediate_state (krun : KRun , name : str , config : KInner , output_dir : Path ) -> None :
809+ json_path = output_dir / name
810+ json_path . write_text (kast_to_json_str (config ))
811+
812+ kore_path = output_dir / ( name + '.pretty.k' )
813+ kore_path . write_text ( krun . pretty_print ( config ) )
814814
815815
816816def run_tests () -> None :
817817 test_args = argparse .ArgumentParser (description = '' )
818- test_args .add_argument ('files' , metavar = 'N' , type = str , nargs = '+' , help = '' )
818+ test_args .add_argument ('files' , metavar = 'N' , type = file_path , nargs = '+' , help = '' )
819819 test_args .add_argument ('--log-level' , choices = ['none' , 'per-file' , 'per-step' ], default = 'per-file' )
820820 test_args .add_argument ('--verbose' , action = 'store_true' , help = '' )
821821 test_args .add_argument (
@@ -838,14 +838,13 @@ def run_tests() -> None:
838838 for test in tests :
839839 if args .verbose :
840840 print ('Running test %s' % test )
841- tmpdir = tempfile .mkdtemp (prefix = 'mandos_' )
841+ tmpdir = Path ( tempfile .mkdtemp (prefix = 'mandos_' ) )
842842 if args .verbose :
843843 print ('Intermediate test outputs stored in:\n %s' % tmpdir )
844844
845- initial_name = '0000_initial_config'
846- with open (f'{ tmpdir } /{ initial_name } ' , 'w' ) as f :
847- f .write (kast_to_json_str (template_wasm_config ))
848-
845+ initial_path = tmpdir / '0000_initial_config'
846+ initial_path .write_text (kast_to_json_str (template_wasm_config ))
847+ assert isinstance (test , Path )
849848 run_test_file (krun , template_wasm_config , test , tmpdir , args )
850849
851850 if args .verbose :
0 commit comments