diff --git a/script/code_generator/test_transform_python_to_code_writer.py b/script/code_generator/test_transform_python_to_code_writer.py new file mode 100644 index 0000000..90e1be5 --- /dev/null +++ b/script/code_generator/test_transform_python_to_code_writer.py @@ -0,0 +1,114 @@ +#!./.venv/bin/python +import argparse +import os +import subprocess +import sys +import tempfile + + +def get_config(): + """Parse command line arguments, extracting the config file name, + returning the union of config file and command line arguments + + :return: dict of config file settings and command line arguments + """ + # TODO update description + parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""\ + Transform a python file in code writer format python file, will generate it in temp file and compare difference. +""", + epilog="""\ +""", + ) + parser.add_argument( + "--debug", action="store_true", help="Show debug information." + ) + parser.add_argument( + "--format", action="store_true", help="Format file before test." + ) + parser.add_argument( + "-f", + "--file", + dest="file", + required=True, + help="Path of file to transform to code_writer.", + ) + args = parser.parse_args() + return args + + +def main(): + config = get_config() + if config.format: + result = subprocess.run( + [ + "bash", + "./script/maintenance/format_python.sh", + config.file, + ], + capture_output=True, + text=True, + ) + with tempfile.NamedTemporaryFile() as temp_file: + # Generate the generator + file = temp_file.name + result = subprocess.run( + [ + "python", + "./script/code_generator/transform_python_to_code_writer.py", + "-f", + config.file, + "-o", + file, + ], + capture_output=True, + text=True, + ) + # if config.debug: + # print("-- show the generator --") + # print(result.stdout) + # print("-- end show the generator --") + # Execute the generator + result_generator = subprocess.run( + ["python", file], capture_output=True, text=True + ) + if result_generator.returncode != 0: + raise Exception(result_generator.stderr) + if config.debug: + print("-- show the generator result --") + print(result_generator.stdout) + print("-- end show the generator result --") + # Test the generator output + fd, temp_file_path = tempfile.mkstemp() + with os.fdopen(fd, "w+") as temp_file_test: + temp_file_test.write(result_generator.stdout) + temp_file_test.seek(0) + # Compare the output of the generator with original + result = subprocess.run( + ["diff", config.file, temp_file_path], + capture_output=True, + text=True, + ) + if config.debug or result.stdout: + print("-- show diff --") + print(result.stdout) + print("-- end show diff --") + if result.stdout: + print("FAIL") + result_wc = subprocess.run( + ["wc", "-m", config.file], capture_output=True, text=True + ) + if result_wc.returncode == 0: + line_count = int(result_wc.stdout.split()[0]) + print(f"{line_count} VS {len(result_generator.stdout)}") + else: + print(f"Error with command 'wc -m {config.file}'") + return -1 + else: + print("PASS") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/script/code_generator/transform_python_to_code_writer.py b/script/code_generator/transform_python_to_code_writer.py index 690f479..b2fadd2 100755 --- a/script/code_generator/transform_python_to_code_writer.py +++ b/script/code_generator/transform_python_to_code_writer.py @@ -1,7 +1,6 @@ #!./.venv/bin/python import argparse -import logging -import os +import uuid import subprocess import sys @@ -88,6 +87,7 @@ def main(): cw.emit("from code_writer import CodeWriter") cw.emit("cw = CodeWriter()") + unique_str = f"#{uuid.uuid4().hex}#" no_line = 1 with open(config.file, "r") as file: @@ -95,7 +95,13 @@ def main(): nb_tab, nb_space = count_space_tab(line) diff_tab = nb_tab - last_nb_tab new_line = line.strip() + + # Support \, because with cw.emit("\") this will break + new_line = new_line.replace("\\", "\\\\") + # Support " into string new_line = new_line.replace('"', '\\"') + # Fix """ + new_line = new_line.replace('\\"\\"\\"', unique_str) status_no_tab = add_line( cw, new_line, no_line, nb_tab, no_tab, no_tab, nb_space @@ -105,7 +111,16 @@ def main(): last_nb_tab = nb_tab no_line += 1 - cw.emit("print(cw.render())") + argument_print = "" + if line[-1] != "\n": + # Remove last endline if missing + argument_print = ", end=''" + # Ignore last character, it's an empty space + # TODO find another technique to support """, instead of using uuid + cw.emit( + f"print(cw.render()[:-1].replace('{unique_str}'," + f' \'"""\'){argument_print})' + ) output = cw.render() if config.output: @@ -116,7 +131,14 @@ def main(): def add_line( - cw, line, no_line, nb_indent, no_indent, init_no_intend, nb_space + cw, + line, + no_line, + nb_indent, + no_indent, + init_no_intend, + nb_space, + deindent=False, ): """ Recursive check indent and write line @@ -135,22 +157,27 @@ def add_line( sys.exit(-1) if nb_indent == -1: - cw.emit('cw.emit("")') - return 0 + if no_indent > 0: + cw.emit_raw(" " * no_indent * 4 + f"cw.emit()\n") + return no_indent + else: + cw.emit("cw.emit()") + return 0 elif nb_indent == no_indent: if nb_indent == 0: cw.emit(f'cw.emit("{line}")') return 0 elif nb_indent == 1: - if no_indent != init_no_intend: + if no_indent != init_no_intend and not deindent: cw.emit(f"with cw.indent({4 + nb_space if nb_space else ''}):") with cw.indent(): cw.emit(f'cw.emit("{line}")') elif nb_indent == 2: if nb_indent - 1 > init_no_intend: cw.emit(f"with cw.indent():") + # TODO support indent with cw.emit_raw with cw.indent(): - if no_indent != init_no_intend: + if no_indent != init_no_intend and not deindent: cw.emit( f"with cw.indent({4 + nb_space if nb_space else ''}):" ) @@ -163,7 +190,7 @@ def add_line( if nb_indent - 1 > init_no_intend: cw.emit(f"with cw.indent():") with cw.indent(): - if no_indent != init_no_intend: + if no_indent != init_no_intend and not deindent: cw.emit( "with" f" cw.indent({4 + nb_space if nb_space else ''}):" @@ -180,7 +207,7 @@ def add_line( if nb_indent - 1 > init_no_intend: cw.emit(f"with cw.indent():") with cw.indent(): - if no_indent != init_no_intend: + if no_indent != init_no_intend and not deindent: cw.emit( "with" f" cw.indent({4 + nb_space if nb_space else ''}):" @@ -200,7 +227,7 @@ def add_line( if nb_indent - 1 > init_no_intend: cw.emit(f"with cw.indent():") with cw.indent(): - if no_indent != init_no_intend: + if no_indent != init_no_intend and not deindent: cw.emit( "with" f" cw.indent({4 + nb_space if nb_space else ''}):" @@ -223,7 +250,10 @@ def add_line( if nb_indent - 1 > init_no_intend: cw.emit(f"with cw.indent():") with cw.indent(): - if no_indent != init_no_intend: + if ( + no_indent != init_no_intend + and not deindent + ): cw.emit( "with" f" cw.indent({4 + nb_space if nb_space else ''}):" @@ -249,7 +279,10 @@ def add_line( if nb_indent - 1 > init_no_intend: cw.emit(f"with cw.indent():") with cw.indent(): - if no_indent != init_no_intend: + if ( + no_indent != init_no_intend + and not deindent + ): cw.emit( "with" f" cw.indent({4 + nb_space if nb_space else ''}):" @@ -278,7 +311,10 @@ def add_line( if nb_indent - 1 > init_no_intend: cw.emit(f"with cw.indent():") with cw.indent(): - if no_indent != init_no_intend: + if ( + no_indent != init_no_intend + and not deindent + ): cw.emit( "with" f" cw.indent({4 + nb_space if nb_space else ''}):" @@ -310,7 +346,10 @@ def add_line( if nb_indent - 1 > init_no_intend: cw.emit(f"with cw.indent():") with cw.indent(): - if no_indent != init_no_intend: + if ( + no_indent != init_no_intend + and not deindent + ): cw.emit( "with" f" cw.indent({4 + nb_space if nb_space else ''}):" @@ -345,7 +384,10 @@ def add_line( if nb_indent - 1 > init_no_intend: cw.emit(f"with cw.indent():") with cw.indent(): - if no_indent != init_no_intend: + if ( + no_indent != init_no_intend + and not deindent + ): cw.emit( "with" f" cw.indent({4 + nb_space if nb_space else ''}):" @@ -1137,6 +1179,7 @@ def add_line( no_indent - 1, init_no_intend, nb_space, + deindent=True, ) else: # indent