Skip to content

Commit 3040cd1

Browse files
committed
Improve path splits (follow up from #413)
Signed-off-by: Philippe Ombredanne <[email protected]>
1 parent 6458999 commit 3040cd1

File tree

1 file changed

+47
-22
lines changed

1 file changed

+47
-22
lines changed

src/commoncode/fileutils.py

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ def is_posixpath(location):
180180
if drive:
181181
return False
182182

183-
184183
# a path is always POSIX unless it contains ONLY backslahes
185184
# which is a rough approximation (it could still be posix)
186185
is_posix = True
@@ -208,78 +207,104 @@ def as_winpath(location):
208207

209208
def split_parent_resource(path, force_posix=False):
210209
"""
211-
Return a (tuple of parent directory path, resource name).
210+
Return a tuple of (parent directory path, resource name).
212211
"""
213-
splitter = is_posixpath(path) and posixpath or ntpath
212+
use_posix = force_posix or is_posixpath(path)
213+
splitter = use_posix and posixpath or ntpath
214214
path = path.rstrip('/\\')
215215
return splitter.split(path)
216216

217217

218-
def resource_name(path):
218+
def resource_name(path, force_posix=False):
219219
"""
220220
Return the resource name (file name or directory name) from `path` which
221221
is the last path segment.
222222
"""
223-
_left, right = split_parent_resource(path)
223+
_left, right = split_parent_resource(path,force_posix)
224224
return right or ''
225225

226226

227-
def file_name(path):
227+
def file_name(path, force_posix=False):
228228
"""
229229
Return the file name (or directory name) of a path.
230230
"""
231-
return resource_name(path)
231+
return resource_name(path, force_posix)
232232

233233

234-
def parent_directory(path):
234+
def parent_directory(path, force_posix=False):
235235
"""
236236
Return the parent directory path of a file or directory `path`.
237237
"""
238-
left, _right = split_parent_resource(path)
239-
sep = is_posixpath(path) and '/' or '\\'
238+
left, _right = split_parent_resource(path, force_posix)
239+
use_posix = force_posix or is_posixpath(path)
240+
sep = use_posix and '/' or '\\'
240241
trail = sep if left != sep else ''
241242
return left + trail
242243

243244

244-
def file_base_name(path):
245+
def file_base_name(path, force_posix=False):
245246
"""
246247
Return the file base name for a path. The base name is the base name of
247248
the file minus the extension. For a directory return an empty string.
248249
"""
249-
return splitext(path)[0]
250+
return splitext(path, force_posix)[0]
250251

251252

252-
def file_extension(path):
253+
def file_extension(path, force_posix=False):
253254
"""
254255
Return the file extension for a path.
255256
"""
256-
return splitext(path)[1]
257+
return splitext(path, force_posix)[1]
257258

258259

259-
def splitext(path):
260+
def splitext(path, force_posix=False):
260261
"""
261262
Return a tuple of strings (basename, extension) for a path. The basename is
262263
the file name minus its extension. Return an empty extension string for a
263264
directory. A directory is identified by ending with a path separator. Not
264265
the same as os.path.splitext.
266+
267+
For example:
268+
>>> splitext('C:\\dir\path.ext')
269+
('path', '.ext')
270+
271+
Directories even with dotted names have no extension:
272+
>>> import ntpath
273+
>>> splitext('C:\\dir\\path.ext' + ntpath.sep)
274+
('path.ext', '')
275+
276+
>>> splitext('/dir/path.ext/')
277+
('path.ext', '')
278+
279+
>>> splitext('/some/file.txt')
280+
('file', '.txt')
281+
282+
Composite extensions for tarballs are properly handled:
283+
>>> splitext('archive.tar.gz')
284+
('archive', '.tar.gz')
265285
"""
266286
base_name = ''
267287
extension = ''
268288
if not path:
269289
return base_name, extension
270290

271-
path = as_posixpath(path)
272-
name = resource_name(path)
273-
if path.endswith('/'):
274-
# directories have no extension
291+
ppath= as_posixpath(path)
292+
name = resource_name(path, force_posix)
293+
name = name.strip('\\/')
294+
if ppath.endswith('/'):
295+
# directories never have an extension
275296
base_name = name
276297
extension = ''
277298
elif name.startswith('.') and '.' not in name[1:]:
278-
base_name = ''
279-
extension = name
299+
base_name = name
300+
extension = ''
280301
else:
281302
base_name, extension = posixpath.splitext(name)
282-
return base_name or '', extension or ''
303+
# handle composed extensions of tar.gz, bz, zx,etc
304+
if base_name.endswith('.tar'):
305+
base_name, extension2 = posixpath.splitext(base_name)
306+
extension = extension2 + extension
307+
return base_name, extension
283308

284309
#
285310
# DIRECTORY AND FILES WALKING/ITERATION

0 commit comments

Comments
 (0)