Coverage for /Users/Newville/Codes/xraylarch/larch/io/fileutils.py: 17%

112 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-11-09 10:08 -0600

1#!/usr/bin/env python 

2""" 

3general purpose file utilities 

4""" 

5import time 

6import os 

7import sys 

8 

9from random import seed, randrange 

10from string import printable 

11from ..utils.strutils import fix_filename, fix_varname, strip_quotes 

12 

13def asciikeys(adict): 

14 """ensure a dictionary has ASCII keys (and so can be an **kwargs)""" 

15 return dict((k.encode('ascii'), v) for k, v in adict.items()) 

16 

17def get_timestamp(with_t=False): 

18 """return ISO format of current timestamp: 

19 argument 

20 -------- 

21 with_t boolean (False) 

22 

23 when with_t is True, the returned string 

24 will match 'YYYY-mm-ddTHH:MM:SS' 

25 otherwise 'YYYY-mm-dd HH:MM:SS' 

26 """ 

27 if with_t: 

28 time.strftime('%Y-%m-%dT%H:%M:%S') 

29 return time.strftime('%Y-%m-%d %H:%M:%S') 

30 

31def random_string(n): 

32 """ random_string(n) 

33 generates a random string of length n, that will match: 

34 [a-z][a-z0-9](n-1) 

35 """ 

36 seed(time.time()) 

37 s = [printable[randrange(0,36)] for i in range(n-1)] 

38 s.insert(0, printable[randrange(10,36)]) 

39 return ''.join(s) 

40 

41def pathOf(dir, base, ext, delim='.'): 

42 """return the normalized path name of file created with 

43 a directory, base, extension, and delimiter""" 

44 p = os.path 

45 return p.normpath(p.join(dir,"%s%s%s" % (base, delim, ext))) 

46 

47def unixpath(d): 

48 "ensure path uses unix delimiters" 

49 d = d.replace('\\','/') 

50 if not d.endswith('/'): d = '%s/' % d 

51 return d 

52 

53def winpath(d): 

54 "ensure path uses windows delimiters" 

55 if d.startswith('//'): d = d[1:] 

56 d = d.replace('/','\\') 

57 if not d.endswith('\\'): d = '%s\\' % d 

58 return d 

59 

60def nativepath(d): 

61 "ensure path uses delimiters for current OS" 

62 if os.name == 'nt': 

63 return winpath(d) 

64 return unixpath(d) 

65 

66def get_homedir(): 

67 """return home directory, or best approximation 

68 On Windows, this returns the Roaming Profile APPDATA 

69 (use CSIDL_LOCAL_APPDATA for Local Profile) 

70 """ 

71 homedir = '.' 

72 if os.name == 'nt': 

73 # For Windows, ask for parent of Roaming 'Application Data' directory 

74 try: 

75 from win32com.shell import shellcon, shell 

76 homedir = shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0) 

77 except ImportError: # if win32com is not found 

78 homedir = os.get_environ('HOME', '.') 

79 else: 

80 try: 

81 os.path.expanduser("~") 

82 except: 

83 pass 

84 return homedir 

85 

86 

87def increment_filename(inpfile, ndigits=3, delim='.'): 

88 """ 

89 increment a data filename, returning a new (non-existing) filename 

90 

91 first see if a number is before '.'. if so, increment it. 

92 second look for number in the prefix. if so, increment it. 

93 lastly, insert a '_001' before the '.', preserving suffix. 

94 

95 the numerical part of the file name will contain at least three digits. 

96 

97 >>> increment_filename('a.002') 

98 'a.003' 

99 >>> increment_filename('a.999') 

100 'a.1000' 

101 >>> increment_filename('b_017.xrf') 

102 'b_018.xrf' 

103 >>> increment_filename('x_10300243.dat') 

104 'x_10300244.dat' 

105 

106 >>> increment_filename('x.dat') 

107 'x_001.dat' 

108 

109 >>> increment_filename('C:/program files/oo/data/x.002') 

110 'C:/program files/ifeffit/data/x.003' 

111 

112 >>> increment_filename('a_001.dat') 

113 'a_002.dat' 

114 

115 >>> increment_filename('a.001.dat') 

116 'a.002.dat' 

117 

118 >>> increment_filename('a_6.dat') 

119 'a_007.dat' 

120 

121 >>> increment_filename('a_001.002') 

122 'a_001.003' 

123 

124 >>> increment_filename("path/a.003") 

125 'path/a.004' 

126""" 

127 

128 dirname, filename = os.path.split(inpfile) 

129 base, ext = os.path.splitext(filename) 

130 if ext == '': 

131 ext = '.000' 

132 

133 if ext.startswith('.'): 

134 ext = ext[1:] 

135 if ndigits < 3: 

136 ndigits = 3 

137 form = "%%.%ii" % (ndigits) 

138 

139 def _incr(base, ext): 

140 if ext.isdigit(): 

141 ext = form % (int(ext)+1) 

142 else: 

143 found = False 

144 if '_' in base: 

145 parts = base.split('_') 

146 for iw, word in enumerate(parts[::-1]): 

147 if word.isdigit(): 

148 parts[len(parts)-iw-1] = form % (int(word)+1) 

149 found = True 

150 break 

151 base = '_'.join(parts) 

152 if not found and '.' in base: 

153 parts = base.split('.') 

154 for iw, word in enumerate(parts[::-1]): 

155 if word.isdigit(): 

156 parts[len(parts)-iw-1] = form % (int(word)+1) 

157 found = True 

158 break 

159 base = '.'.join(parts) 

160 if not found: 

161 base = "%s_001" % base 

162 return (base, ext) 

163 

164 # increment once 

165 base, ext = _incr(base, ext) 

166 fout = pathOf(dirname, base, ext, delim=delim) 

167 

168 # then gaurantee that file does not exist, 

169 # continuing to increment if necessary 

170 while (os.path.exists(fout)): 

171 base, ext = _incr(base, ext) 

172 fout = pathOf(dirname, base, ext, delim=delim) 

173 return fout 

174 

175def new_filename(fname=None, ndigits=3): 

176 """ generate a new file name, either based on 

177 filename or generating a random one 

178 

179 >>> new_filename(fname='x.001') 

180 'x.002' 

181 # if 'x.001' exists 

182 """ 

183 if fname is None: 

184 ext = ("%%.%ii" % ndigits) % 1 

185 fname = "%s.%s" % (random_string(6), ext) 

186 

187 if os.path.exists(fname): 

188 fname = increment_filename(fname, ndigits=ndigits) 

189 

190 return fname 

191 

192def new_dirname(dirname=None, ndigits=3): 

193 """ generate a new subdirectory name (no '.' in name), either 

194 based on dirname or generating a random one 

195 

196 >>> new_dirname('x.001') 

197 'x_002' 

198 # if 'x_001' exists 

199 """ 

200 if dirname is None: 

201 ext = ("%%_%ii" % ndigits) % 1 

202 dirname = "%s_%s" % (random_string(6), ext) 

203 

204 dirname = dirname.replace('.', '_') 

205 if os.path.exists(dirname): 

206 dirname = increment_filename(dirname, ndigits=ndigits, delim='_') 

207 return dirname 

208 

209def test_incrementfilename(): 

210 tests = (('a.002', 'a.003'), 

211 ('a.999', 'a.1000'), 

212 ('b_017.xrf', 'b_018.xrf'), 

213 ('x_10300243.dat', 'x_10300244.dat'), 

214 ('x.dat' , 'x_001.dat'), 

215 ('C:/program files/data/x.002', 

216 'C:/program files/data/x.003'), 

217 ('a_001.dat', 'a_002.dat'), 

218 ('a_6.dat', 'a_007.dat'), 

219 ('a_001.002', 'a_001.003'), 

220 ('path/a.003', 'path/a.004')) 

221 npass = nfail = 0 

222 for inp,out in tests: 

223 tval = increment_filename(inp) 

224 if tval != out: 

225 print( "Error converting " , inp) 

226 print( "Got '%s' expected '%s'" % (tval, out)) 

227 nfail = nfail + 1 

228 else: 

229 npass = npass + 1 

230 print('Passed %i of %i tests' % (npass, npass+nfail))