Coverage for pystratum_common/DocBlockReflection.py: 90%

78 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2024-05-13 08:46 +0200

1import os 

2import re 

3from typing import List, Tuple 

4 

5 

6class DocBlockReflection: 

7 """ 

8 A simple DocBlock reflection. 

9 """ 

10 

11 # ------------------------------------------------------------------------------------------------------------------ 

12 def __init__(self, comment: List[str]): 

13 """ 

14 Object constructor. 

15 

16 :param comment: The comment as a list of strings. 

17 """ 

18 self._comment: List[str] = comment 

19 """ 

20 The DocBlock as a list of strings. 

21 """ 

22 

23 self._description: str = '' 

24 """ 

25 The description. 

26 """ 

27 

28 self._tags: List[Tuple[str, str]] = list() 

29 """ 

30 The tags in the DocBlock 

31 """ 

32 

33 self.__reflect() 

34 

35 # ------------------------------------------------------------------------------------------------------------------ 

36 def get_description(self) -> str: 

37 """ 

38 Returns the description. 

39 """ 

40 return self._description 

41 

42 # ------------------------------------------------------------------------------------------------------------------ 

43 def get_tag(self, name: str) -> str: 

44 """ 

45 Returns a tag. 

46 

47 @param str name: The name of the tag. 

48 """ 

49 for tag in self._tags: 

50 if tag[0] == name: 

51 return tag[1] 

52 

53 return '' 

54 

55 # ------------------------------------------------------------------------------------------------------------------ 

56 def get_tags(self, name: str) -> List[str]: 

57 """ 

58 Returns a list of tags. 

59 

60 @param str name: The name of the tag. 

61 """ 

62 tags = list() 

63 for tag in self._tags: 

64 if tag[0] == name: 64 ↛ 63line 64 didn't jump to line 63, because the condition on line 64 was always true

65 tags.append(tag[1]) 

66 

67 return tags 

68 

69 # ------------------------------------------------------------------------------------------------------------------ 

70 def __reflect(self) -> None: 

71 """ 

72 Parses the DocBlock. 

73 """ 

74 self.__clean_doc_block() 

75 self.__extract_description() 

76 self.__extract_tags() 

77 

78 # ------------------------------------------------------------------------------------------------------------------ 

79 @staticmethod 

80 def __remove_leading_empty_lines(lines: List[str]) -> List[str]: 

81 """ 

82 Removes leading empty lines from a list of lines. 

83 

84 :param lines: The lines. 

85 """ 

86 tmp = list() 

87 empty = True 

88 for i in range(0, len(lines)): 

89 empty = empty and lines[i] == '' 

90 if not empty: 

91 tmp.append(lines[i]) 

92 

93 return tmp 

94 

95 # ------------------------------------------------------------------------------------------------------------------ 

96 @staticmethod 

97 def __remove_trailing_empty_lines(lines: List[str]) -> List[str]: 

98 """ 

99 Removes leading empty lines from a list of lines. 

100 

101 :param lines: The lines. 

102 """ 

103 lines.reverse() 

104 tmp = DocBlockReflection.__remove_leading_empty_lines(lines) 

105 lines.reverse() 

106 tmp.reverse() 

107 

108 return tmp 

109 

110 # ------------------------------------------------------------------------------------------------------------------ 

111 def __clean_doc_block(self) -> None: 

112 """ 

113 Cleans the DocBlock from leading and trailing white space and comment tokens. 

114 """ 

115 # Return immediately if the DockBlock is empty. 

116 if not self._comment: 

117 return 

118 

119 for i in range(1, len(self._comment) - 1): 

120 self._comment[i] = re.sub(r'^\s*\*', '', self._comment[i]) 

121 

122 self._comment[0] = re.sub(r'^\s*/\*\*', '', self._comment[0]) 

123 

124 self._comment[-1] = re.sub(r'\*/\s*$', '', self._comment[-1]) 

125 

126 for i, line in enumerate(self._comment): 

127 self._comment[i] = line.strip() 

128 

129 self._comment = self.__remove_leading_empty_lines(self._comment) 

130 self._comment = self.__remove_trailing_empty_lines(self._comment) 

131 

132 # ------------------------------------------------------------------------------------------------------------------ 

133 def __extract_description(self) -> None: 

134 """ 

135 Extracts the description from the DocBlock. The description start at the first line and stops at the first tag 

136 or the end of the DocBlock. 

137 """ 

138 tmp = list() 

139 for line in self._comment: 

140 if len(line) >= 1 and line[0] == '@': 

141 break 

142 

143 tmp.append(line) 

144 

145 tmp = self.__remove_trailing_empty_lines(tmp) 

146 

147 self._description = os.linesep.join(tmp) 

148 

149 # ------------------------------------------------------------------------------------------------------------------ 

150 def __extract_tags(self) -> None: 

151 """ 

152 Extract tags from the DocBlock. 

153 """ 

154 tags = list() 

155 current = None 

156 for line in self._comment: 

157 parts = re.match(r'^@(\w+)', line) 

158 if parts: 

159 current = (parts.group(1), list()) 

160 tags.append(current) 

161 

162 if current: 

163 if line == '': 163 ↛ 164line 163 didn't jump to line 164, because the condition on line 163 was never true

164 current = None 

165 else: 

166 current[1].append(line) 

167 

168 for tag in tags: 

169 self._tags.append((tag[0], os.linesep.join(tag[1]))) 

170 

171# ----------------------------------------------------------------------------------------------------------------------