Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/soupsieve/__meta__.py: 34%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

70 statements  

1"""Meta related things.""" 

2from __future__ import annotations 

3from collections import namedtuple 

4import re 

5 

6RE_VER = re.compile( 

7 r'''(?x) 

8 (?P<major>\d+)(?:\.(?P<minor>\d+))?(?:\.(?P<micro>\d+))? 

9 (?:(?P<type>a|b|rc)(?P<pre>\d+))? 

10 (?:\.post(?P<post>\d+))? 

11 (?:\.dev(?P<dev>\d+))? 

12 ''' 

13) 

14 

15REL_MAP = { 

16 ".dev": "", 

17 ".dev-alpha": "a", 

18 ".dev-beta": "b", 

19 ".dev-candidate": "rc", 

20 "alpha": "a", 

21 "beta": "b", 

22 "candidate": "rc", 

23 "final": "" 

24} 

25 

26DEV_STATUS = { 

27 ".dev": "2 - Pre-Alpha", 

28 ".dev-alpha": "2 - Pre-Alpha", 

29 ".dev-beta": "2 - Pre-Alpha", 

30 ".dev-candidate": "2 - Pre-Alpha", 

31 "alpha": "3 - Alpha", 

32 "beta": "4 - Beta", 

33 "candidate": "4 - Beta", 

34 "final": "5 - Production/Stable" 

35} 

36 

37PRE_REL_MAP = {"a": 'alpha', "b": 'beta', "rc": 'candidate'} 

38 

39 

40class Version(namedtuple("Version", ["major", "minor", "micro", "release", "pre", "post", "dev"])): 

41 """ 

42 Get the version (PEP 440). 

43 

44 A biased approach to the PEP 440 semantic version. 

45 

46 Provides a tuple structure which is sorted for comparisons `v1 > v2` etc. 

47 (major, minor, micro, release type, pre-release build, post-release build, development release build) 

48 Release types are named in is such a way they are comparable with ease. 

49 Accessors to check if a development, pre-release, or post-release build. Also provides accessor to get 

50 development status for setup files. 

51 

52 How it works (currently): 

53 

54 - You must specify a release type as either `final`, `alpha`, `beta`, or `candidate`. 

55 - To define a development release, you can use either `.dev`, `.dev-alpha`, `.dev-beta`, or `.dev-candidate`. 

56 The dot is used to ensure all development specifiers are sorted before `alpha`. 

57 You can specify a `dev` number for development builds, but do not have to as implicit development releases 

58 are allowed. 

59 - You must specify a `pre` value greater than zero if using a prerelease as this project (not PEP 440) does not 

60 allow implicit prereleases. 

61 - You can optionally set `post` to a value greater than zero to make the build a post release. While post releases 

62 are technically allowed in prereleases, it is strongly discouraged, so we are rejecting them. It should be 

63 noted that we do not allow `post0` even though PEP 440 does not restrict this. This project specifically 

64 does not allow implicit post releases. 

65 - It should be noted that we do not support epochs `1!` or local versions `+some-custom.version-1`. 

66 

67 Acceptable version releases: 

68 

69 ``` 

70 Version(1, 0, 0, "final") 1.0 

71 Version(1, 2, 0, "final") 1.2 

72 Version(1, 2, 3, "final") 1.2.3 

73 Version(1, 2, 0, ".dev-alpha", pre=4) 1.2a4 

74 Version(1, 2, 0, ".dev-beta", pre=4) 1.2b4 

75 Version(1, 2, 0, ".dev-candidate", pre=4) 1.2rc4 

76 Version(1, 2, 0, "final", post=1) 1.2.post1 

77 Version(1, 2, 3, ".dev") 1.2.3.dev0 

78 Version(1, 2, 3, ".dev", dev=1) 1.2.3.dev1 

79 ``` 

80 

81 """ 

82 

83 def __new__( 

84 cls, 

85 major: int, minor: int, micro: int, release: str = "final", 

86 pre: int = 0, post: int = 0, dev: int = 0 

87 ) -> Version: 

88 """Validate version info.""" 

89 

90 # Ensure all parts are positive integers. 

91 for value in (major, minor, micro, pre, post): 

92 if not (isinstance(value, int) and value >= 0): 

93 raise ValueError("All version parts except 'release' should be integers.") 

94 

95 if release not in REL_MAP: 

96 raise ValueError(f"'{release}' is not a valid release type.") 

97 

98 # Ensure valid pre-release (we do not allow implicit pre-releases). 

99 if ".dev-candidate" < release < "final": 

100 if pre == 0: 

101 raise ValueError("Implicit pre-releases not allowed.") 

102 elif dev: 

103 raise ValueError("Version is not a development release.") 

104 elif post: 

105 raise ValueError("Post-releases are not allowed with pre-releases.") 

106 

107 # Ensure valid development or development/pre release 

108 elif release < "alpha": 

109 if release > ".dev" and pre == 0: 

110 raise ValueError("Implicit pre-release not allowed.") 

111 elif post: 

112 raise ValueError("Post-releases are not allowed with pre-releases.") 

113 

114 # Ensure a valid normal release 

115 else: 

116 if pre: 

117 raise ValueError("Version is not a pre-release.") 

118 elif dev: 

119 raise ValueError("Version is not a development release.") 

120 

121 return super().__new__(cls, major, minor, micro, release, pre, post, dev) 

122 

123 def _is_pre(self) -> bool: 

124 """Is prerelease.""" 

125 

126 return bool(self.pre > 0) 

127 

128 def _is_dev(self) -> bool: 

129 """Is development.""" 

130 

131 return bool(self.release < "alpha") 

132 

133 def _is_post(self) -> bool: 

134 """Is post.""" 

135 

136 return bool(self.post > 0) 

137 

138 def _get_dev_status(self) -> str: # pragma: no cover 

139 """Get development status string.""" 

140 

141 return DEV_STATUS[self.release] 

142 

143 def _get_canonical(self) -> str: 

144 """Get the canonical output string.""" 

145 

146 # Assemble major, minor, micro version and append `pre`, `post`, or `dev` if needed.. 

147 if self.micro == 0: 

148 ver = f"{self.major}.{self.minor}" 

149 else: 

150 ver = f"{self.major}.{self.minor}.{self.micro}" 

151 if self._is_pre(): 

152 ver += f'{REL_MAP[self.release]}{self.pre}' 

153 if self._is_post(): 

154 ver += f".post{self.post}" 

155 if self._is_dev(): 

156 ver += f".dev{self.dev}" 

157 

158 return ver 

159 

160 

161def parse_version(ver: str) -> Version: 

162 """Parse version into a comparable Version tuple.""" 

163 

164 m = RE_VER.match(ver) 

165 

166 if m is None: 

167 raise ValueError(f"'{ver}' is not a valid version") 

168 

169 # Handle major, minor, micro 

170 major = int(m.group('major')) 

171 minor = int(m.group('minor')) if m.group('minor') else 0 

172 micro = int(m.group('micro')) if m.group('micro') else 0 

173 

174 # Handle pre releases 

175 if m.group('type'): 

176 release = PRE_REL_MAP[m.group('type')] 

177 pre = int(m.group('pre')) 

178 else: 

179 release = "final" 

180 pre = 0 

181 

182 # Handle development releases 

183 dev = m.group('dev') if m.group('dev') else 0 

184 if m.group('dev'): 

185 dev = int(m.group('dev')) 

186 release = '.dev-' + release if pre else '.dev' 

187 else: 

188 dev = 0 

189 

190 # Handle post 

191 post = int(m.group('post')) if m.group('post') else 0 

192 

193 return Version(major, minor, micro, release, pre, post, dev) 

194 

195 

196__version_info__ = Version(2, 7, 0, "final") 

197__version__ = __version_info__._get_canonical()