from clang.cindex import Index, CursorKind, Config from datetime import datetime from os import path from typing import List Config.set_library_file("/usr/lib/llvm-18/lib/libclang.so") class EnumUpdater: @staticmethod def execute() -> None: """ Read the enums from the C++ file and then update the Python Enum definitions """ files_to_check = [] files_to_check.append(path.abspath(f'{path.dirname(__file__)}/../../leahi-common/AlarmDefs.h')) files_to_check.append(path.abspath(f'{path.dirname(__file__)}/../../leahi-common/MsgDefs.h')) common_location = path.abspath(f'{path.dirname(__file__)}/../common') file_to_update = {'AlarmList': (f'{common_location}/alarm_defs.py', 'AlarmEnum', False), 'RequestRejectReasons': (f'{common_location}/msg_defs.py', 'DialinEnum', False), 'MsgIds': (f'{common_location}/msg_ids.py', 'DialinEnum', True), # 'TestConfig': (f'{common_location}/test_config_defs.py', 'DialinEnum', False) } for file in files_to_check: if path.exists(file): extracted_enums = _extract_enums(file) for enum_name in extracted_enums: if enum_name in file_to_update: _generate_enum_file(file_location = file_to_update[enum_name][0], enum_name = enum_name, enum_member_list = extracted_enums[enum_name], enum_type = file_to_update[enum_name][1], is_hex = file_to_update[enum_name][2]) print(f'Updated enum: {enum_name}') # ============================================================ Private Methods ============================================================ def _extract_enums(cpp_file): """ Extract the enums from the provided C++ file :param cpp_file: (String) The C++ file with full location :return: (Dictionary) The collected enums """ index = Index.create() tu = index.parse(cpp_file) enums = {} for cursor in tu.cursor.walk_preorder(): if cursor.kind == CursorKind.ENUM_DECL: # Update name to be CamelCase enum_name = "".join(part.capitalize() for part in cursor.spelling.split("_") if part) enums[enum_name] = [] for item in cursor.get_children(): if item.kind == CursorKind.ENUM_CONSTANT_DECL: if item.spelling in ['MSG_ID_FIRST_TD_TESTER_MESSAGE', 'MSG_ID_FIRST_DD_TESTER_MESSAGE', 'MSG_ID_FIRST_FP_TESTER_MESSAGE']: continue enums[enum_name].append({ "member": item.spelling, "value": item.enum_value, "comment": item.brief_comment, }) return enums def _generate_enum_file(file_location: str, enum_name: str, enum_member_list: List[dict], enum_type: str='Enum', is_hex: bool=False) -> None: """ Generate the enum file content :param file_location: (String) The enum file with full location :param enum_name: (String) The enum's name :param enum_member_list: (List of Dictionaries) The information of the enum members :param enum_type: (String) The enum type to be the parent :param is_hex: (Boolean) The member's values are hex or not :return: None """ now = datetime.now().strftime("%d-%b-%Y") file_name = file_location.split('/')[-1] lines = [] lines.append('###########################################################################') lines.append('#') lines.append('# Copyright (c) 2020-2024 Diality Inc. - All Rights Reserved.') lines.append('#') lines.append('# THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM IN PART OR IN') lines.append('# WHOLE WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER.') lines.append('#') lines.append(f'# @file {file_name}') lines.append('#') lines.append('# @author (last) Enum Updater Script') lines.append(f'# @date (last) {now}') lines.append('# @author (original) Zoltan Miskolci') lines.append('# @date (original) 31-Jul-2026') lines.append('#') lines.append('############################################################################') lines.append('from enum import unique') lines.append(f'from leahi_dialin.utils.enums import {enum_type}') lines.append('') lines.append('') lines.append('@unique') lines.append(f'class {enum_name}({enum_type}):') # Add the members for i in range(len(enum_member_list)): member = enum_member_list[i] if i != 0 and member['value'] != enum_member_list[i-1]['value'] + 1: lines.append('') value = member['value'] if is_hex: value = hex(member['value']).upper().replace('X','x') lines.append(f' {member["member"]:<75} = {value:<10} # {member["comment"]}') lines.append('') # Add cutom code for specific enum or enum types lines.extend(_custom_code_generator(enum_name, enum_type)) # Write into the file with open(file_location, "w") as f: f.write("\n".join(lines)) def _custom_code_generator(enum_name:str, enum_type:str) -> List[str]: """ Add cutom code for specific enum or enum types :param enum_name: (String) The enum's name :param enum_type: (String) The enum type to be the parent :return: (List[str]) The custom code lines """ lines = [] # Add the _str_list for python 3.6 compatibility if enum_type == 'DialinEnum': lines.append(f'{enum_name}._str_list = ' + '{ }') lines.append('') if enum_name == 'RequestRejectReasons': lines.append(f'ACK_NOT_REQUIRED = [ ]') lines.append('') return lines # ============================================================ Main ============================================================ if __name__ == '__main__': EnumUpdater.execute()