Coverage for pesummary/_version_helper.py: 65.1%

109 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-12-09 22:34 +0000

1# Licensed under an MIT style license -- see LICENSE.md 

2 

3import json 

4import os 

5import shutil 

6import subprocess 

7import sys 

8from pathlib import Path 

9 

10__author__ = ["Charlie Hoy <charlie.hoy@ligo.org>"] 

11 

12 

13class GitDummy(object): 

14 def __getattr__(self, attr): 

15 return "" 

16 

17 

18class GitInformation(object): 

19 """Helper class to handle the git information 

20 """ 

21 def __init__(self, directory=None): 

22 if directory is None and not os.path.isdir(".git"): 

23 raise TypeError( 

24 "Not a git repository. Unable to get git information" 

25 ) 

26 elif directory is None: 

27 directory = "." 

28 cwd = os.getcwd() 

29 os.chdir(directory) 

30 self.last_commit_info = self.get_last_commit_info() 

31 self.last_version = self.get_last_version() 

32 self.hash = self.last_commit_info[0] 

33 self.author = self.last_commit_info[1] 

34 self.status = self.get_status() 

35 self.builder = self.get_build_name() 

36 self.build_date = self.get_build_date() 

37 os.chdir(cwd) 

38 

39 def call(self, arguments): 

40 """Launch a subprocess to run the bash command 

41 

42 Parameters 

43 ---------- 

44 arguments: list 

45 list of bash commands 

46 """ 

47 return subprocess.check_output(arguments) 

48 

49 def get_build_name(self): 

50 """Return the username and email of the current builder 

51 """ 

52 try: 

53 name = self.call(["git", "config", "user.name"]) 

54 email = self.call(["git", "config", "user.email"]) 

55 name = name.strip() 

56 email = email.strip() 

57 return "%s <%s>" % (name.decode("utf-8"), email.decode("utf-8")) 

58 except Exception: 

59 return "" 

60 

61 def get_build_date(self): 

62 """Return the current datetime 

63 """ 

64 import time 

65 return time.strftime('%Y-%m-%d %H:%M:%S +0000', time.gmtime()) 

66 

67 def get_last_commit_info(self): 

68 """Return the details of the last git commit 

69 """ 

70 try: 

71 string = self.call( 

72 ["git", "log", "-1", "--pretty=format:%h,%an,%ae"]) 

73 string = string.decode("utf-8").split(",") 

74 hash, username, email = string 

75 author = "%s <%s>" % (username, email) 

76 return hash, author 

77 except Exception: 

78 return "" 

79 

80 def get_status(self): 

81 """Return the state of the git repository 

82 """ 

83 git_diff = self.call(["git", "diff", "."]).decode("utf-8") 

84 if git_diff: 

85 return "UNCLEAN: Modified working tree" 

86 return "CLEAN: All modifications committed" 

87 

88 def get_last_version(self): 

89 """Return the last stable version 

90 """ 

91 try: 

92 tag = self.call(["git", "describe", "--tags", "--abbrev=0"]).decode( 

93 "utf-8" 

94 ).strip("\n") 

95 if tag[0] != "v": 

96 return tag 

97 return tag[1:] 

98 except Exception: 

99 return "Not found" 

100 

101 

102class PackageInformation(GitInformation): 

103 """Helper class to handle package versions 

104 """ 

105 def __init__(self): 

106 self.package_info = self.get_package_info() 

107 self.package_dir = self.get_package_dir() 

108 

109 @staticmethod 

110 def _find_conda(): 

111 """Return the path of the ``conda`` executable, or `None`. 

112 """ 

113 return os.getenv("CONDA_EXE", shutil.which("conda")) 

114 

115 def get_package_info(self): 

116 """Return the package information 

117 """ 

118 if (conda := self._find_conda()) and (Path(sys.prefix) / "conda-meta").is_dir(): 

119 self.package_manager = "conda" 

120 raw = self.call([ 

121 conda, 

122 "list", 

123 "--json", 

124 "--prefix", sys.prefix, 

125 ]) 

126 else: 

127 self.package_manager = "pypi" 

128 raw = self.call([ 

129 sys.executable, 

130 "-m", "pip", 

131 "list", "installed", 

132 "--format", "json", 

133 ]) 

134 return json.loads(raw.decode('utf-8')) 

135 

136 def get_package_dir(self): 

137 """Return the package directory 

138 """ 

139 return sys.prefix 

140 

141 

142def make_version_file( 

143 version_file=None, return_string=False, version=None, add_install_path=False 

144): 

145 """Write a version file 

146 

147 Parameters 

148 ---------- 

149 version_file: str 

150 the path to the version file you wish to write 

151 return_sting: Bool, optional 

152 if True, return the version file as a string. Default False 

153 """ 

154 from pesummary import __version_string__ 

155 

156 string = __version_string__ 

157 if add_install_path: 

158 string += install_path(return_string=True) 

159 if not return_string and version_file is None: 

160 raise ValueError("Please provide a version file") 

161 elif not return_string: 

162 with open(version_file, "w") as f: 

163 f.write(string) 

164 return version_file 

165 return string 

166 

167 

168def install_path(return_string=False): 

169 """Return the install path of a package 

170 """ 

171 packages = PackageInformation() 

172 install_path = packages.package_dir 

173 string = "# Install information\n\ninstall_path = %s\n" % ( 

174 install_path 

175 ) 

176 if return_string: 

177 return string 

178 return packages.package_dir 

179 

180 

181def get_version_information(short=False): 

182 """Grab the version from the .version file 

183 

184 Parameters 

185 ---------- 

186 short: Bool 

187 If True, only return the version. If False, return git hash 

188 """ 

189 try: 

190 from ._version import version 

191 except ModuleNotFoundError: 

192 try: 

193 # in build 

194 import setuptools_scm 

195 version = setuptools_scm.get_version() 

196 except ImportError: 

197 version = "" 

198 

199 if short: 

200 return version.split("+")[0] 

201 return version