diff --git a/sm2gen.py b/sm2gen.py index 82349cc..8b47b7c 100644 --- a/sm2gen.py +++ b/sm2gen.py @@ -13,6 +13,7 @@ import traceback import os from datetime import datetime, timedelta from spellchecker import SpellChecker +import logging # # To Do @@ -27,8 +28,14 @@ json5_html_list: list = [] ini_file_path = os.path.expanduser("~/.smegit/conf") OPENAI_API_KEY = "" +# Configure the basic logging system +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +# Create a logger +logger = logging.getLogger(__name__) + def example_function(**kwargs): - print(kwargs) + logger.info(kwargs) def spell_check_and_correct(text): try: @@ -59,12 +66,12 @@ def spell_check_and_correct(text): # Join the corrected words back into a single string corrected_text = ' '.join(corrected_words) except: - print(f"Spelling checker exception ({text})") + logger.warning(f"Spelling checker exception ({text})") return text return corrected_text def python_to_perl_structure(data): - #print(data) + #logger.info(data) if data: if isinstance(data, list): # Convert each dictionary in the list to Perl format: ['text' => 'value'] @@ -126,7 +133,7 @@ def json5_to_list(filename): def json5_to_pandas(filename): with open(filename, "r") as file: data = json5.load(file) - print(data) + logger.debug(data) return data.json_normalize(data) @@ -147,7 +154,7 @@ def rec_print(data, prefix=""): rec_print(val, f"{prefix}[{idx}]") # If neither, it's a basic type. else: - print(f"{prefix}: {data}") + logger.info(f"{prefix}: {data}") def find_item(nested_dict, target_key): @@ -195,10 +202,10 @@ def lint_json5(filename): with open(filename, "r") as file: data = file.read() json5.loads(data) - print(f"{filename} as JSON5 data is valid") + logger.info(f"{filename} as JSON5 data is valid") except Exception as e: - print(f"{filename} as JSON5 data is invalid") - print("Error:", str(e)) + logger.warning(f"{filename} as JSON5 data is invalid") + logger.warning("Error:", str(e)) sys.exit() @@ -221,7 +228,7 @@ def hl(keyname): if keyname in json5_dict: return json5_dict[keyname] else: - print(f"{keyname} not found in JSON5 - top level") + logger.warning(f"{keyname} not found in JSON5 - top level") return "None" @@ -242,7 +249,7 @@ def has_file_been_modified(file_path): # Get the file's creation time and last modification time in Unix timestamp creation_time = os.path.getctime(file_path) last_modification_time = os.path.getmtime(file_path) - print(f"{creation_time}*{last_modification_time}") + logger.debug(f"{creation_time}*{last_modification_time}") quit() # Compare the creation time and last modification time @@ -298,25 +305,21 @@ def format_text(text): # Split the text into sentences sentences = text.split(".") words = sentences[0].split(" ") - # print(len(sentences)) # Deal with one capitalised word if sentences[0].isupper() and len(sentences) == 1 and len(words) == 1: return sentences[0].capitalize() else: for sentence in sentences: - # print(sentence) # and splt into sub phrases, based on comma formatted_phrases = [] phrases = sentence.split(",") for phrase in phrases: - # print(phrase) phrase = phrase.lstrip() formatted_words = [] words = phrase.split(" ") for i, word in enumerate(words): - # print(i,word) # Check if the word is fully uppercase or not the first word = word.lstrip() if word.isupper() or i != 0: @@ -364,7 +367,7 @@ def get_translation(message="Hello", language="french"): translated_message = get_completion(prompt) # Look for over long messages if len(message) / len(translated_message) < 0.2: - print(f"{message} translated to {translated_message}") + logger.error(f"{message} translated to {translated_message}") quit() return translated_message @@ -388,12 +391,11 @@ def check_file_version(filename,force_Files=False): for line in header_lines: if ' at ' in line: # Split at 'at', expect the timestamp to be in the third part - #print(line) timestamp_str = line.split('at')[2].strip() break if timestamp_str is None: - print("Warning: No timestamp found. Returning original filename.") + logger.warning("Warning: No timestamp found. Returning original filename.") return filename # Return the original filename if no timestamp is found # Convert the string timestamp to a datetime object @@ -405,8 +407,6 @@ def check_file_version(filename,force_Files=False): # Get the last modified time of the file, ignoring milliseconds file_modified_time = datetime.fromtimestamp(os.path.getmtime(filename)).replace(microsecond=0) - #print(file_modified_time,file_timestamp) - # Compare the timestamps if file_modified_time > file_timestamp: return f"{filename}.new" @@ -414,10 +414,10 @@ def check_file_version(filename,force_Files=False): return filename except FileNotFoundError: - #print(f"Error: The file '{filename}' does not exist.") + logger.warning(f"Error: The file '{filename}' does not exist.") return filename except Exception as e: - print(f"An error occurred: {traceback.format_exc()}") + logger.warning(f"An error occurred: {traceback.format_exc()}") return filename @@ -456,7 +456,7 @@ def extract_input_fields(json_data, value_type): if value.get('Type').lower() in ['readonlytext', 'text', 'select','checkbox','textarea','email']: # input_value = value.get('Value', '') input_name = value.get('Name', '') - print(input_name) + logger.debug(input_name) # # Match and extract the value without the value_type and parentheses # match = pattern.search(input_value) # if match: @@ -476,7 +476,7 @@ if __name__ == "__main__": json5_dict: dict = {} json5_html_list: list = [] - print(f"SM2 code from JSON5 - {strVersion}") + logger.info(f"SM2 code from JSON5 - {strVersion}") home_dir = "/home/brianr/clients/SM2/SM2Gen/" json_filename = f"{home_dir}/json5/nfsshare.json5" # CreateStarterWebsite.json5" @@ -491,12 +491,12 @@ if __name__ == "__main__": # Read the value of "OPENAI_API_KEY" if "OPENAI_API_KEY" in config["smegit"]: OPENAI_API_KEY = config["smegit"]["OPENAI_API_KEY"] - # print("API Key:", OPENAI_API_KEY) + # logger.info("API Key:", OPENAI_API_KEY) client = OpenAI(api_key=OPENAI_API_KEY) else: - print("OPENAI_API_KEY not found in the configuration file.") + logger.info("OPENAI_API_KEY not found in the configuration file.") else: - print("Configuration file not found at:", file_path) + logger.info("Configuration file not found at:", file_path) # Command line parameters - not in use parser = argparse.ArgumentParser(description="SM2Gen") @@ -534,14 +534,14 @@ if __name__ == "__main__": ) args = parser.parse_args() json_filename = args.filename - print( + logger.info( f"JSON5 from {json_filename} with noController={args.noController}, noHtml={args.noHtml} and noLang={args.noLang}" ) # Not yet activated # check if json5 file exists json_file_path = Path(json_filename) if not json_file_path.exists(): - print(f"json5 file: {json_filename} not found") + logger.info(f"json5 file: {json_filename} not found") quit(1) # check syntax of JSON5 @@ -551,15 +551,15 @@ if __name__ == "__main__": try: json5_dict = json5_to_dict(json_filename) except Exception as e: - print(f"json5 file {json_filename} failed lint test (e)") + logger.info(f"json5 file {json_filename} failed lint test (e)") quit(1) # Get dict of just the html bit json5_html_list = json5_dict["html"] # Identify message - print(f"\nGenerating mojo panels for {hl('PackageName')}") - print("-----------------------------------") + logger.info(f"\nGenerating mojo panels for {hl('PackageName')}") + logger.info("-----------------------------------") # Routes for each panel routes = get_all_routes() @@ -578,7 +578,7 @@ if __name__ == "__main__": controller_file = check_file_version(target_directory_path + hl("PackageName") + ".pm",force_Files) custom_controller_file = check_file_version(target_directory_path + hl("PackageName") + "-Custom.pm",force_Files) - #print(custom_controller_file) + #logger.info(custom_controller_file) layout_file = check_file_version(target_directory_path + hl("PackageName").lower() + ".html.ep",force_Files) css_file = check_file_version(target_directory_path + hl("PackageName").lower() + ".css",force_Files) partial_files = list() @@ -586,14 +586,14 @@ if __name__ == "__main__": partial_files.append(check_file_version( target_directory_path + '_' + hl("prefix") + "_" + panel + ".html.ep",force_Files) ) - print(f"Partial files to be created:{partial_files}") + logger.info(f"Partial files to be created:{partial_files}") lex_file = check_file_version(target_directory_path + hl("PackageName").lower() + "_en.lex",force_Files) - print(lex_file) + logger.info(lex_file) tablecontrols = ( get_table_control_data() ) # arrays of hashes used to drive rows in tables - # print(strVersion,tablecontrols,routes) + # logger.info(strVersion,tablecontrols,routes) # Generate controller file dbfields = [] #extract_input_fields(json5_dict, 'db') # Params which correspond to Db fields - TBD @@ -612,18 +612,18 @@ if __name__ == "__main__": ) with open(controller_file, "w") as file: file.write(controller_perl) - print(f"{controller_file} controller generated ok") + logger.info(f"{controller_file} controller generated ok") except Exception as e: - print(f"A Chameleon controller render error occurred: {e} {traceback.format_exc()}") + logger.info(f"A Chameleon controller render error occurred: {e} {traceback.format_exc()}") except Exception as e: - print(f"A Chameleon controller template error occurred: {e} {traceback.format_exc()}") + logger.info(f"A Chameleon controller template error occurred: {e} {traceback.format_exc()}") # Generate Custom controller file try: custom_controller_template = PageTemplateFile("Templates/custom.pm.tem") fields = extract_input_fields(json5_dict, 'stash') # Params which correspond to singleton values #flatfields = flatten_hash_of_lists(fields) - #print(fields) + #logger.info(fields) #quit(0) try: custom_controller_perl = custom_controller_template.render( @@ -632,11 +632,11 @@ if __name__ == "__main__": # We must be careful to not overwrite the custom file if the developer has already written to it - TBD with open(custom_controller_file, "w") as file: file.write(custom_controller_perl) - print(f"{custom_controller_file} custom controller generated ok") + logger.info(f"{custom_controller_file} custom controller generated ok") except Exception as e: - print(f"A Chameleon custom controller render error occurred: {e} {traceback.format_exc()}") + logger.info(f"A Chameleon custom controller render error occurred: {e} {traceback.format_exc()}") except Exception as e: - print(f"A Chameleon custom controller template error occurred: {e} {traceback.format_exc()}") + logger.info(f"A Chameleon custom controller template error occurred: {e} {traceback.format_exc()}") # generate Layout file layout_template = PageTemplateFile("Templates/layout.html.ep.tem") @@ -648,11 +648,11 @@ if __name__ == "__main__": ) with open(layout_file, "w") as file: file.write(layout_mojo) - print(f"{layout_file} mojo template layout file generated ok") + logger.info(f"{layout_file} mojo template layout file generated ok") except Exception as e: - print(f"A Chameleon render on layout file error occurred: {e}") + logger.info(f"A Chameleon render on layout file error occurred: {e}") except Exception as e: - print(f"A Chameleon template layout file error occurred: {e}") + logger.info(f"A Chameleon template layout file error occurred: {e}") # Generate a partial file for each of the entries in the html list @@ -675,13 +675,13 @@ if __name__ == "__main__": ) with open(partial_files[i], "w") as file: file.write(partial_mojo_template) - print(f"{partial_files[i]} mojo template generated ok - phase 1") + logger.info(f"{partial_files[i]} mojo template generated ok - phase 1") except Exception as e: - print( + logger.info( f"A Chameleon render error on partial file {html['route']} occurred: {e}" ) except Exception as e: - print(f"A Chameleon html {html['route']} error occurred: {e}") + logger.info(f"A Chameleon html {html['route']} error occurred: {e}") # Now generate the controls from the rest of the entries in the dict. all_controls_html = "" @@ -712,11 +712,11 @@ if __name__ == "__main__": ) all_controls_html = all_controls_html + control_html except Exception as e: - print( + logger.info( f"A Chameleon render on partial file control {html_control} error occurred: {e}" ) except Exception as e: - print( + logger.info( f"A Chameleon render on partial file control {html_control} error occurred: {e}" ) else: @@ -736,11 +736,11 @@ if __name__ == "__main__": ) all_controls_html = all_controls_html + simple_control_html except Exception as e: - print( + logger.warning( f"A Chameleon render on partial file control {html_control} error occurred: {e}" ) except Exception as e: - print( + logger.warning( f"A Chameleon template partial file control {html_control} error occurred: {e}" ) @@ -759,7 +759,7 @@ if __name__ == "__main__": # Write the modified content back to the file with open(partial_files[i], "w") as file: file.writelines(lines) - print(f"Content modified and saved to {partial_files[i]}") + logger.info(f"Content modified and saved to {partial_files[i]}") i += 1 # Create the css file (the header, followed by a dumy entry for each class created/used above) @@ -801,7 +801,6 @@ if __name__ == "__main__": left_str = hl("prefix") + "_" + lex_message right_str = lex_message right_str = right_str.replace("_", " ") - # print(f"Right:{right_str}") right_str = format_text(right_str) left_str = left_str.replace(" ", "_") words = left_str.split("_")[:6] @@ -813,12 +812,12 @@ if __name__ == "__main__": lex_all = "" for lex_str in string_lib: lex_all += f"'{lex_str['left']}' => '{lex_str['right']}',\n" - print(f"Writing {lex_file}") + logger.info(f"Writing {lex_file}") with open(lex_file, "w") as file: file.write(f"#\n# Generated by SM2Gen version: {strVersion}\n#\n") file.write(lex_all) # and then play the strings back into the partials and the layout file - print("..and feed the lex string names back into other files") + logger.debug("..and feed the lex string names back into other files") for filename in all_files: with open(filename, "r") as file: file_content = file.read() @@ -834,7 +833,7 @@ if __name__ == "__main__": # and write it back with open(filename, "w") as file: file.write(file_content) - print(f"Write out modified:{filename}") + logger.info(f"Write out modified:{filename}") # Now generate all the translated lex files from a list of the languages and codes # if specifically requested @@ -847,7 +846,7 @@ if __name__ == "__main__": lex_str = file.read() eng_lex_dict = convert_lex_to_dict(lex_str) for lang_item in lang_dict: - print(f"Translating from english lex file to {lang_item['language']}") + logger.info(f"Translating from english lex file to {lang_item['language']}") code = lang_item["code"] translated_lex_file = check_file_version( f"{target_directory_path}{hl('PackageName').lower()}_{code}.lex" @@ -863,7 +862,7 @@ if __name__ == "__main__": translated_dict.append( {"id": lex_item["id"], "text": translated_text} ) - print(f"Writing out lex file for {lang_item['code']}") + logger.info(f"Writing out lex file for {lang_item['code']}") with open(translated_lex_file, "w") as file: file.write(f"#\n# Generated by SM2Gen version: {strVersion}\n#\n") for item in translated_dict: @@ -878,9 +877,9 @@ if __name__ == "__main__": "'" + item["id"] + "' => " + '"' + translated_text + '",\n' ) file.write(line) - # print(f"{item['id']} => {item['text']}\n") + # logger.info(f"{item['id']} => {item['text']}\n") #else: - # print( + # logger.info( # f"Skipping the creation of {translated_lex_file} as it exists already" # ) quit() # end of the program \ No newline at end of file