Skip to content

Commit b11ac13

Browse files
authored
Merge pull request #228 from Erotemic/dev/add_pathutils
Port util_path from ubelt
2 parents 5dab3c1 + ad298b5 commit b11ac13

File tree

2 files changed

+170
-0
lines changed

2 files changed

+170
-0
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@ boltons Changelog
44
Since February 20, 2013 there have been 40 releases and 1386 commits for
55
an average of one 35-commit release about every 10 weeks.
66

7+
8+
19.4.0
9+
------
10+
*(Unreleased)*
11+
12+
New module [pathutils][pathutils]:
13+
14+
* [pathutils.augpath][pathutils.augpath] augments a path by modifying its components
15+
* [pathutils.shrinkuser][pathutils.shrinkuser] inverts :func:`os.path.expanduser`.
16+
* [pathutils.expandpath][pathutils.expandpath] shell-like environ and tilde expansion
17+
18+
[pathutils.augpath]: https://boltons.readthedocs.io/en/latest/funcutils.html#boltons.pathutils.augpath
19+
[pathutils.shrinkuser]: https://boltons.readthedocs.io/en/latest/funcutils.html#boltons.pathutils.shrinkuser
20+
[pathutils.expandpath]: https://boltons.readthedocs.io/en/latest/funcutils.html#boltons.pathutils.expandpath
21+
22+
723
19.3.0
824
------
925
*(October 28, 2019)*

boltons/pathutils.py

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
"""
2+
Functions for working with filesystem paths.
3+
4+
The :func:`expandpath` function expands the tilde to $HOME and environment
5+
variables to their values.
6+
7+
The :func:`augpath` function creates variants of an existing path without
8+
having to spend multiple lines of code splitting it up and stitching it back
9+
together.
10+
11+
The :func:`shrinkuser` function replaces your home directory with a tilde.
12+
"""
13+
from __future__ import print_function
14+
15+
from os.path import (expanduser, expandvars, join, normpath, split, splitext)
16+
import os
17+
18+
19+
__all__ = [
20+
'augpath', 'shrinkuser', 'expandpath',
21+
]
22+
23+
24+
def augpath(path, suffix='', prefix='', ext=None, base=None, dpath=None,
25+
multidot=False):
26+
"""
27+
Augment a path by modifying its components.
28+
29+
Creates a new path with a different extension, basename, directory, prefix,
30+
and/or suffix.
31+
32+
A prefix is inserted before the basename. A suffix is inserted
33+
between the basename and the extension. The basename and extension can be
34+
replaced with a new one. Essentially a path is broken down into components
35+
(dpath, base, ext), and then recombined as (dpath, prefix, base, suffix,
36+
ext) after replacing any specified component.
37+
38+
Args:
39+
path (str | PathLike): a path to augment
40+
suffix (str, default=''): placed between the basename and extension
41+
prefix (str, default=''): placed in front of the basename
42+
ext (str, default=None): if specified, replaces the extension
43+
base (str, default=None): if specified, replaces the basename without
44+
extension
45+
dpath (str | PathLike, default=None): if specified, replaces the
46+
directory
47+
multidot (bool, default=False): Allows extensions to contain multiple
48+
dots. Specifically, if False, everything after the last dot in the
49+
basename is the extension. If True, everything after the first dot
50+
in the basename is the extension.
51+
52+
Returns:
53+
str: augmented path
54+
55+
Example:
56+
>>> path = 'foo.bar'
57+
>>> suffix = '_suff'
58+
>>> prefix = 'pref_'
59+
>>> ext = '.baz'
60+
>>> newpath = augpath(path, suffix, prefix, ext=ext, base='bar')
61+
>>> print('newpath = %s' % (newpath,))
62+
newpath = pref_bar_suff.baz
63+
64+
Example:
65+
>>> augpath('foo.bar')
66+
'foo.bar'
67+
>>> augpath('foo.bar', ext='.BAZ')
68+
'foo.BAZ'
69+
>>> augpath('foo.bar', suffix='_')
70+
'foo_.bar'
71+
>>> augpath('foo.bar', prefix='_')
72+
'_foo.bar'
73+
>>> augpath('foo.bar', base='baz')
74+
'baz.bar'
75+
>>> augpath('foo.tar.gz', ext='.zip', multidot=True)
76+
'foo.zip'
77+
>>> augpath('foo.tar.gz', ext='.zip', multidot=False)
78+
'foo.tar.zip'
79+
>>> augpath('foo.tar.gz', suffix='_new', multidot=True)
80+
'foo_new.tar.gz'
81+
"""
82+
# Breakup path
83+
orig_dpath, fname = split(path)
84+
if multidot:
85+
# The first dot defines the extension
86+
parts = fname.split('.', 1)
87+
orig_base = parts[0]
88+
orig_ext = '' if len(parts) == 1 else '.' + parts[1]
89+
else:
90+
# The last dot defines the extension
91+
orig_base, orig_ext = splitext(fname)
92+
# Replace parts with specified augmentations
93+
if dpath is None:
94+
dpath = orig_dpath
95+
if ext is None:
96+
ext = orig_ext
97+
if base is None:
98+
base = orig_base
99+
# Recombine into new path
100+
new_fname = ''.join((prefix, base, suffix, ext))
101+
newpath = join(dpath, new_fname)
102+
return newpath
103+
104+
105+
def shrinkuser(path, home='~'):
106+
"""
107+
Inverse of :func:`os.path.expanduser`.
108+
109+
Args:
110+
path (str | PathLike): path in system file structure
111+
home (str, default='~'): symbol used to replace the home path.
112+
Defaults to '~', but you might want to use '$HOME' or
113+
'%USERPROFILE%' instead.
114+
115+
Returns:
116+
str: path: shortened path replacing the home directory with a tilde
117+
118+
Example:
119+
>>> path = expanduser('~')
120+
>>> assert path != '~'
121+
>>> assert shrinkuser(path) == '~'
122+
>>> assert shrinkuser(path + '1') == path + '1'
123+
>>> assert shrinkuser(path + '/1') == join('~', '1')
124+
>>> assert shrinkuser(path + '/1', '$HOME') == join('$HOME', '1')
125+
"""
126+
path = normpath(path)
127+
userhome_dpath = expanduser('~')
128+
if path.startswith(userhome_dpath):
129+
if len(path) == len(userhome_dpath):
130+
path = home
131+
elif path[len(userhome_dpath)] == os.path.sep:
132+
path = home + path[len(userhome_dpath):]
133+
return path
134+
135+
136+
def expandpath(path):
137+
"""
138+
Shell-like expansion of environment variables and tilde home directory.
139+
140+
Args:
141+
path (str | PathLike): the path to expand
142+
143+
Returns:
144+
str : expanded path
145+
146+
Example:
147+
>>> import os
148+
>>> os.environ['SPAM'] = 'eggs'
149+
>>> assert expandpath('~/$SPAM') == expanduser('~/eggs')
150+
>>> assert expandpath('foo') == 'foo'
151+
"""
152+
path = expanduser(path)
153+
path = expandvars(path)
154+
return path

0 commit comments

Comments
 (0)