Coverage for klayout_pex/klayout/repair_rdb.py: 16%

79 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-17 17:24 +0000

1# 

2# -------------------------------------------------------------------------------- 

3# SPDX-FileCopyrightText: 2024 Martin Jan Köhler and Harald Pretl 

4# Johannes Kepler University, Institute for Integrated Circuits. 

5# 

6# This file is part of KPEX  

7# (see https://github.com/martinjankoehler/klayout-pex). 

8# 

9# This program is free software: you can redistribute it and/or modify 

10# it under the terms of the GNU General Public License as published by 

11# the Free Software Foundation, either version 3 of the License, or 

12# (at your option) any later version. 

13# 

14# This program is distributed in the hope that it will be useful, 

15# but WITHOUT ANY WARRANTY; without even the implied warranty of 

16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

17# GNU General Public License for more details. 

18# 

19# You should have received a copy of the GNU General Public License 

20# along with this program. If not, see <http://www.gnu.org/licenses/>. 

21# SPDX-License-Identifier: GPL-3.0-or-later 

22# -------------------------------------------------------------------------------- 

23# 

24import gzip 

25import io 

26import os.path 

27import shutil 

28import sys 

29from typing import * 

30import xml.etree.ElementTree as ET 

31 

32import klayout.rdb as rdb 

33from ..log import ( 

34 LogLevel, 

35 set_log_level, 

36 register_additional_handler, 

37 deregister_additional_handler, 

38 # console, 

39 # debug, 

40 info, 

41 warning, 

42 subproc, 

43 error, 

44 rule 

45) 

46 

47 

48def parse_category_path(category_path: str) -> List[str]: 

49 within_escaped = False 

50 within_backslash = False 

51 current_word = '' 

52 path_list = [] 

53 for c in category_path: 

54 match c: 

55 case '.': 

56 if within_backslash: 

57 current_word += c 

58 within_backslash = False 

59 elif within_escaped: 

60 current_word += c 

61 else: 

62 path_list.append(current_word) 

63 current_word = '' 

64 case '\\': 

65 if within_backslash: 

66 current_word += c 

67 within_backslash = False 

68 else: 

69 within_backslash = True 

70 case '\'': 

71 if within_backslash: 

72 current_word += c 

73 within_backslash = False 

74 else: 

75 within_escaped = not within_escaped 

76 case _: 

77 current_word += c 

78 if len(current_word) >= 1: 

79 path_list.append(current_word) 

80 return path_list 

81 

82def repair_rdb_xml(xml_file: io.IOBase, new_xml_path: str): 

83 et = ET.parse(xml_file) 

84 root = et.getroot() 

85 

86 categories: Set[str] = set( 

87 [e.text for e in root.findall('./items/item/category')] 

88 ) 

89 category_paths = [parse_category_path(c) for c in categories] 

90 category_paths.sort() 

91 # print(category_paths) 

92 for p in category_paths: 

93 elem = root 

94 for c in p: 

95 elemcats = elem.find("./categories") 

96 subelem = elemcats.find("./category/name[.='{0}']/..".format(c)) 

97 if subelem is None: 

98 warning(f"In category path {p}, can't find element for component {c}") 

99 new_category = ET.SubElement(elemcats, "category") 

100 new_cname = ET.SubElement(new_category, "name") 

101 new_cname.text = c 

102 ET.SubElement(new_category, 'description') 

103 ET.SubElement(new_category, 'categories') 

104 elem = new_category 

105 else: 

106 elem = subelem 

107 

108 et.write(new_xml_path) 

109 

110 

111def repair_rdb(rdb_path: str): 

112 rdb_file: io.IOBase 

113 suffix = os.path.splitext(rdb_path)[-1] 

114 new_xml_path = rdb_path + '.repair.xml' 

115 

116 if suffix == '.gz': 

117 with gzip.open(rdb_path, 'r') as f: 

118 repair_rdb_xml(f, new_xml_path) 

119 else: 

120 with open(rdb_path, 'r') as f: 

121 repair_rdb_xml(f, new_xml_path) 

122 

123 report = rdb.ReportDatabase('') 

124 try: 

125 report.load(new_xml_path) 

126 info(f"Succeeded in repairing broken marker database {rdb_path} under {new_xml_path}") 

127 

128 except Exception as e: 

129 error(f"Failed to repair broken marker database {rdb_path} due to exception: {e}") 

130 

131 

132if __name__ == "__main__": 

133 if len(sys.argv) < 2: 

134 print(f"Usage: {sys.argv[0]} file.rdb.gz") 

135 sys.exit(1) 

136 

137 repair_rdb(sys.argv[1])