Coverage for glotter/project.py: 100%

73 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-04-12 02:25 +0000

1# pylint hates pydantic 

2# pylint: disable=E0213,E0611 

3from typing import Dict, Optional, ClassVar 

4from enum import Enum, auto 

5 

6from pydantic import BaseModel, validator, conlist, constr 

7 

8from glotter.auto_gen_test import AutoGenTest, AutoGenUseTests 

9 

10 

11class NamingScheme(Enum): 

12 hyphen = auto() 

13 underscore = auto() 

14 camel = auto() 

15 pascal = auto() 

16 lower = auto() 

17 

18 

19class AcronymScheme(Enum): 

20 lower = "lower" 

21 upper = "upper" 

22 two_letter_limit = "two_letter_limit" 

23 

24 

25class Project(BaseModel): 

26 VALID_REGEX: ClassVar[str] = "^[0-9a-zA-Z]+$" 

27 

28 words: conlist(constr(min_length=1, regex=VALID_REGEX, strict=True), min_items=1) 

29 requires_parameters: bool = False 

30 acronyms: conlist(constr(min_length=1, regex=VALID_REGEX, strict=True)) = [] 

31 acronym_scheme: AcronymScheme = AcronymScheme.two_letter_limit 

32 use_tests: Optional[AutoGenUseTests] = None 

33 tests: Dict[str, AutoGenTest] = {} 

34 

35 @validator("acronyms", pre=True, each_item=True) 

36 def get_acronym(cls, value): 

37 if not isinstance(value, str): 

38 return value 

39 

40 return value.upper() 

41 

42 @validator("tests", pre=True) 

43 def get_tests(cls, value, values): 

44 if not isinstance(value, dict) or not all( 

45 isinstance(test, dict) for test in value.values() 

46 ): 

47 return value 

48 

49 if values.get("use_tests"): 

50 raise ValueError('"tests" and "use_tests" items are mutually exclusive') 

51 

52 return { 

53 test_name: { 

54 **test, 

55 "requires_parameters": values.get("requires_parameters") or False, 

56 "name": test_name, 

57 } 

58 for test_name, test in value.items() 

59 } 

60 

61 def set_tests(self, project: "Project"): 

62 """ 

63 If there is a "use_tests" item, then set the specified tests, renaming them 

64 according to the "use_tests" item. The "use_tests" item is then removed 

65 

66 :params tests: Project with tests to use 

67 """ 

68 

69 if self.use_tests: 

70 self.tests = {} 

71 for test_name, test in project.tests.items(): 

72 test_name = test_name.replace( 

73 self.use_tests.search, self.use_tests.replace 

74 ) 

75 self.tests[test_name] = AutoGenTest( 

76 **test.dict(exclude={"name"}), name=test_name 

77 ) 

78 

79 self.requires_parameters = project.requires_parameters 

80 self.use_tests = None 

81 

82 @property 

83 def display_name(self): 

84 return self._as_display() 

85 

86 def get_project_name_by_scheme(self, naming): 

87 """ 

88 gets a project name for a specific naming scheme 

89 

90 :param naming: the naming scheme 

91 :return: the project type formatted by the directory's naming scheme 

92 """ 

93 try: 

94 return { 

95 NamingScheme.hyphen: self._as_hyphen(), 

96 NamingScheme.underscore: self._as_underscore(), 

97 NamingScheme.camel: self._as_camel(), 

98 NamingScheme.pascal: self._as_pascal(), 

99 NamingScheme.lower: self._as_lower(), 

100 }[naming] 

101 except KeyError as e: 

102 raise KeyError(f'Unknown naming scheme "{naming}"') from e 

103 

104 def _as_hyphen(self): 

105 return "-".join( 

106 self._try_as_acronym(word, NamingScheme.hyphen) for word in self.words 

107 ) 

108 

109 def _as_underscore(self): 

110 return "_".join( 

111 self._try_as_acronym(word, NamingScheme.underscore) for word in self.words 

112 ) 

113 

114 def _as_camel(self): 

115 return self.words[0].lower() + "".join( 

116 self._try_as_acronym(word.title(), NamingScheme.camel) 

117 for word in self.words[1:] 

118 ) 

119 

120 def _as_pascal(self): 

121 return "".join( 

122 self._try_as_acronym(word.title(), NamingScheme.pascal) 

123 for word in self.words 

124 ) 

125 

126 def _as_lower(self): 

127 return "".join(word.lower() for word in self.words) 

128 

129 def _as_display(self): 

130 return " ".join( 

131 self._try_as_acronym(word.title(), NamingScheme.underscore) 

132 for word in self.words 

133 ) 

134 

135 def _is_acronym(self, word): 

136 return word.upper() in self.acronyms 

137 

138 def _try_as_acronym(self, word, naming_scheme): 

139 if self._is_acronym(word): 

140 if self.acronym_scheme == AcronymScheme.upper: 

141 return word.upper() 

142 elif self.acronym_scheme == AcronymScheme.lower: 

143 return word.lower() 

144 else: 

145 if len(word) <= 2 and naming_scheme in [ 

146 NamingScheme.camel, 

147 NamingScheme.pascal, 

148 ]: 

149 return word.upper() 

150 

151 return word