Coverage for glotter/project.py: 100%

73 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-09-13 19:09 +0000

1from enum import Enum, auto 

2from typing import ClassVar, Dict, Optional 

3 

4from pydantic import BaseModel, conlist, constr, validator 

5 

6from glotter.auto_gen_test import AutoGenTest, AutoGenUseTests 

7 

8 

9class NamingScheme(Enum): 

10 hyphen = auto() 

11 underscore = auto() 

12 camel = auto() 

13 pascal = auto() 

14 lower = auto() 

15 

16 

17class AcronymScheme(Enum): 

18 lower = "lower" 

19 upper = "upper" 

20 two_letter_limit = "two_letter_limit" 

21 

22 

23class Project(BaseModel): 

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

25 

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

27 requires_parameters: bool = False 

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

29 acronym_scheme: AcronymScheme = AcronymScheme.two_letter_limit 

30 use_tests: Optional[AutoGenUseTests] = None 

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

32 

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

34 def get_acronym(cls, value): 

35 if not isinstance(value, str): 

36 return value 

37 

38 return value.upper() 

39 

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

41 def get_tests(cls, value, values): 

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

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

44 ): 

45 return value 

46 

47 if values.get("use_tests"): 

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

49 

50 return { 

51 test_name: { 

52 **test, 

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

54 "name": test_name, 

55 } 

56 for test_name, test in value.items() 

57 } 

58 

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

60 """ 

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

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

63 

64 :params tests: Project with tests to use 

65 """ 

66 

67 if self.use_tests: 

68 self.tests = {} 

69 for test_name_, test in project.tests.items(): 

70 test_name = test_name_.replace(self.use_tests.search, self.use_tests.replace) 

71 self.tests[test_name] = AutoGenTest(**test.dict(exclude={"name"}), name=test_name) 

72 

73 self.requires_parameters = project.requires_parameters 

74 self.use_tests = None 

75 

76 @property 

77 def display_name(self): 

78 return self._as_display() 

79 

80 def get_project_name_by_scheme(self, naming): 

81 """ 

82 gets a project name for a specific naming scheme 

83 

84 :param naming: the naming scheme 

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

86 """ 

87 try: 

88 return { 

89 NamingScheme.hyphen: self._as_hyphen(), 

90 NamingScheme.underscore: self._as_underscore(), 

91 NamingScheme.camel: self._as_camel(), 

92 NamingScheme.pascal: self._as_pascal(), 

93 NamingScheme.lower: self._as_lower(), 

94 }[naming] 

95 except KeyError as e: 

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

97 

98 def _as_hyphen(self): 

99 return "-".join(self._try_as_acronym(word, NamingScheme.hyphen) for word in self.words) 

100 

101 def _as_underscore(self): 

102 return "_".join(self._try_as_acronym(word, NamingScheme.underscore) for word in self.words) 

103 

104 def _as_camel(self): 

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

106 self._try_as_acronym(word.title(), NamingScheme.camel) for word in self.words[1:] 

107 ) 

108 

109 def _as_pascal(self): 

110 return "".join( 

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

112 ) 

113 

114 def _as_lower(self): 

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

116 

117 def _as_display(self): 

118 return " ".join( 

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

120 ) 

121 

122 def _is_acronym(self, word): 

123 return word.upper() in self.acronyms 

124 

125 def _try_as_acronym(self, word, naming_scheme): 

126 if self._is_acronym(word): 

127 if self.acronym_scheme == AcronymScheme.upper: 

128 return word.upper() 

129 elif self.acronym_scheme == AcronymScheme.lower: 

130 return word.lower() 

131 elif len(word) <= 2 and naming_scheme in [ 

132 NamingScheme.camel, 

133 NamingScheme.pascal, 

134 ]: 

135 return word.upper() 

136 

137 return word