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
« 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
9from random import seed, randrange
10from string import printable
11from ..utils.strutils import fix_filename, fix_varname, strip_quotes
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())
17def get_timestamp(with_t=False):
18 """return ISO format of current timestamp:
19 argument
20 --------
21 with_t boolean (False)
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')
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)
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)))
47def unixpath(d):
48 "ensure path uses unix delimiters"
49 d = d.replace('\\','/')
50 if not d.endswith('/'): d = '%s/' % d
51 return d
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
60def nativepath(d):
61 "ensure path uses delimiters for current OS"
62 if os.name == 'nt':
63 return winpath(d)
64 return unixpath(d)
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
87def increment_filename(inpfile, ndigits=3, delim='.'):
88 """
89 increment a data filename, returning a new (non-existing) filename
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.
95 the numerical part of the file name will contain at least three digits.
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'
106 >>> increment_filename('x.dat')
107 'x_001.dat'
109 >>> increment_filename('C:/program files/oo/data/x.002')
110 'C:/program files/ifeffit/data/x.003'
112 >>> increment_filename('a_001.dat')
113 'a_002.dat'
115 >>> increment_filename('a.001.dat')
116 'a.002.dat'
118 >>> increment_filename('a_6.dat')
119 'a_007.dat'
121 >>> increment_filename('a_001.002')
122 'a_001.003'
124 >>> increment_filename("path/a.003")
125 'path/a.004'
126"""
128 dirname, filename = os.path.split(inpfile)
129 base, ext = os.path.splitext(filename)
130 if ext == '':
131 ext = '.000'
133 if ext.startswith('.'):
134 ext = ext[1:]
135 if ndigits < 3:
136 ndigits = 3
137 form = "%%.%ii" % (ndigits)
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)
164 # increment once
165 base, ext = _incr(base, ext)
166 fout = pathOf(dirname, base, ext, delim=delim)
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
175def new_filename(fname=None, ndigits=3):
176 """ generate a new file name, either based on
177 filename or generating a random one
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)
187 if os.path.exists(fname):
188 fname = increment_filename(fname, ndigits=ndigits)
190 return fname
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
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)
204 dirname = dirname.replace('.', '_')
205 if os.path.exists(dirname):
206 dirname = increment_filename(dirname, ndigits=ndigits, delim='_')
207 return dirname
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))