1
|
|
|
# -*- coding: utf-8 -*- |
2
|
|
|
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- |
3
|
|
|
# vi: set ft=python sts=4 ts=4 sw=4 et: |
4
|
|
|
""" |
5
|
|
|
Crumb manipulation utilities |
6
|
|
|
""" |
7
|
|
|
import os |
8
|
|
|
import os.path as op |
9
|
|
|
|
10
|
|
|
from six import string_types |
11
|
|
|
|
12
|
|
|
|
13
|
|
|
def _get_path(crumb_path): |
14
|
|
|
""" Return the path string from `crumb_path`. |
15
|
|
|
Parameters |
16
|
|
|
---------- |
17
|
|
|
crumb_path: str or Crumb |
18
|
|
|
|
19
|
|
|
Returns |
20
|
|
|
------- |
21
|
|
|
path: str |
22
|
|
|
""" |
23
|
|
|
if hasattr(crumb_path, '_path'): |
24
|
|
|
crumb_path = crumb_path._path |
25
|
|
|
|
26
|
|
|
if not isinstance(crumb_path, string_types): |
27
|
|
|
raise TypeError("Expected `crumb_path` to be a {}, got {}.".format(string_types, type(crumb_path))) |
28
|
|
|
|
29
|
|
|
return crumb_path |
30
|
|
|
|
31
|
|
|
|
32
|
|
|
def _is_crumb_arg(crumb_arg, start_sym='{', end_sym='}'): |
33
|
|
|
""" Returns True if `crumb_arg` is a well formed crumb argument, i.e., |
34
|
|
|
is a string that starts with `start_sym` and ends with `end_sym`. False otherwise.""" |
35
|
|
|
if not isinstance(crumb_arg, string_types): |
36
|
|
|
return False |
37
|
|
|
|
38
|
|
|
return crumb_arg.startswith(start_sym) and crumb_arg.endswith(end_sym) |
39
|
|
|
|
40
|
|
|
|
41
|
|
|
def _arg_name(arg, start_sym='{', end_sym='}'): |
42
|
|
|
""" Return the name of the argument given its crumb representation. |
43
|
|
|
Parameters |
44
|
|
|
---------- |
45
|
|
|
arg_crumb: str |
46
|
|
|
|
47
|
|
|
Returns |
48
|
|
|
------- |
49
|
|
|
arg_name: str |
50
|
|
|
""" |
51
|
|
|
if not _is_crumb_arg(arg): |
52
|
|
|
raise ValueError("Expected an well formed crumb argument, " |
53
|
|
|
"got {}.".format(arg)) |
54
|
|
|
return arg[len(start_sym):-len(end_sym)] |
55
|
|
|
|
56
|
|
|
|
57
|
|
|
def _arg_format(arg_name, start_sym='{', end_sym='}'): |
58
|
|
|
""" Return the crumb argument for its string `format()` representation. |
59
|
|
|
Parameters |
60
|
|
|
---------- |
61
|
|
|
arg_name: str |
62
|
|
|
|
63
|
|
|
Returns |
64
|
|
|
------- |
65
|
|
|
arg_format: str |
66
|
|
|
""" |
67
|
|
|
return start_sym + arg_name + end_sym |
68
|
|
|
|
69
|
|
|
|
70
|
|
|
def is_valid(crumb_path, start_sym='{', end_sym='}'): |
71
|
|
|
""" Return True if `crumb_path` is a well formed path with crumb arguments, |
72
|
|
|
False otherwise. |
73
|
|
|
Parameters |
74
|
|
|
---------- |
75
|
|
|
crumb_path: str |
76
|
|
|
|
77
|
|
|
Returns |
78
|
|
|
------- |
79
|
|
|
is_valid: bool |
80
|
|
|
""" |
81
|
|
|
crumb_path = _get_path(crumb_path) |
82
|
|
|
|
83
|
|
|
splt = crumb_path.split(op.sep) |
84
|
|
|
for crumb in splt: |
85
|
|
|
if op.isdir(crumb): |
86
|
|
|
continue |
87
|
|
|
|
88
|
|
|
if _is_crumb_arg(crumb, start_sym=start_sym, end_sym=end_sym): |
89
|
|
|
crumb = _arg_name(crumb, start_sym=start_sym, end_sym=end_sym) |
90
|
|
|
|
91
|
|
|
if start_sym in crumb or end_sym in crumb: |
92
|
|
|
return False |
93
|
|
|
|
94
|
|
|
return True |
95
|
|
|
|
96
|
|
|
|
97
|
|
|
def has_crumbs(crumb_path, start_sym='{', end_sym='}'): |
98
|
|
|
""" Return True if the `crumb_path.split(op.sep)` has item which is a crumb argument |
99
|
|
|
that starts with '{' and ends with '}'.""" |
100
|
|
|
crumb_path = _get_path(crumb_path) |
101
|
|
|
|
102
|
|
|
splt = crumb_path.split(op.sep) |
103
|
|
|
for i in splt: |
104
|
|
|
if _is_crumb_arg(i, start_sym=start_sym, end_sym=end_sym): |
105
|
|
|
return True |
106
|
|
|
|
107
|
|
|
return False |
108
|
|
|
|
109
|
|
|
|
110
|
|
|
def _replace(crumb_path, start_sym='{', end_sym='}', **kwargs): |
111
|
|
|
""" Return `crumb_path` where every crumb argument found in `kwargs` has been |
112
|
|
|
replaced by the given value in `kwargs.""" |
113
|
|
|
if not kwargs: |
114
|
|
|
return crumb_path |
115
|
|
|
|
116
|
|
|
for k in kwargs: |
117
|
|
|
karg = _arg_format(k, start_sym=start_sym, end_sym=end_sym) |
118
|
|
|
if k not in crumb_path: |
119
|
|
|
raise KeyError("Could not find argument {} in" |
120
|
|
|
" `path` {}.".format(k, crumb_path)) |
121
|
|
|
|
122
|
|
|
crumb_path = crumb_path.replace(karg, kwargs[k]) |
123
|
|
|
|
124
|
|
|
return crumb_path |
125
|
|
|
|
126
|
|
|
|
127
|
|
|
def _split(crumb_path, start_sym='{', end_sym='}'): |
128
|
|
|
""" Return a list of sub-strings of `crumb_path` where the |
129
|
|
|
path parts are separated from the crumb arguments. |
130
|
|
|
""" |
131
|
|
|
crumb_path = _get_path(crumb_path) |
132
|
|
|
|
133
|
|
|
if not is_valid(crumb_path, start_sym, end_sym): |
134
|
|
|
raise ValueError('Crumb path {} is not valid.'.format(crumb_path)) |
135
|
|
|
|
136
|
|
|
splt = [] |
137
|
|
|
tmp = '/' if crumb_path.startswith(op.sep) else '' |
138
|
|
|
for i in crumb_path.split(op.sep): |
139
|
|
|
if i.startswith(start_sym): |
140
|
|
|
splt.append(tmp) |
141
|
|
|
tmp = '' |
142
|
|
|
splt.append(i) |
143
|
|
|
else: |
144
|
|
|
tmp = op.join(tmp, i) |
145
|
|
|
|
146
|
|
|
return splt |
147
|
|
|
|
148
|
|
|
|
149
|
|
|
def _touch(crumb_path, exist_ok=True, start_sym='{', end_sym='}'): |
150
|
|
|
""" Create a leaf directory and all intermediate ones |
151
|
|
|
using the non crumbed part of `crumb_path`. |
152
|
|
|
If the target directory already exists, raise an IOError |
153
|
|
|
if exist_ok is False. Otherwise no exception is raised. |
154
|
|
|
Parameters |
155
|
|
|
---------- |
156
|
|
|
crumb_path: str |
157
|
|
|
|
158
|
|
|
exist_ok: bool |
159
|
|
|
Default = True |
160
|
|
|
|
161
|
|
|
Returns |
162
|
|
|
------- |
163
|
|
|
nupath: str |
164
|
|
|
The new path created. |
165
|
|
|
""" |
166
|
|
|
if has_crumbs(crumb_path, start_sym=start_sym, end_sym=end_sym): |
167
|
|
|
nupath = _split(crumb_path, start_sym=start_sym, end_sym=end_sym)[0] |
168
|
|
|
else: |
169
|
|
|
nupath = crumb_path |
170
|
|
|
|
171
|
|
|
if op.exists(nupath) and not exist_ok: |
172
|
|
|
raise IOError("Folder {} already exists.".format(nupath)) |
173
|
|
|
|
174
|
|
|
try: |
175
|
|
|
os.makedirs(nupath, exist_ok=exist_ok) |
176
|
|
|
except: |
177
|
|
|
raise |
178
|
|
|
else: |
179
|
|
|
return nupath |
180
|
|
|
|
181
|
|
|
|
182
|
|
|
def _split_exists(crumb_path, start_sym='{', end_sym='}'): |
183
|
|
|
""" Return True if the part without crumb arguments of `crumb_path` |
184
|
|
|
is an existing path or a symlink, False otherwise. |
185
|
|
|
Returns |
186
|
|
|
------- |
187
|
|
|
exists: bool |
188
|
|
|
""" |
189
|
|
|
if has_crumbs(crumb_path): |
190
|
|
|
rpath = _split(crumb_path, start_sym=start_sym, end_sym=end_sym)[0] |
191
|
|
|
else: |
192
|
|
|
rpath = str(crumb_path) |
193
|
|
|
|
194
|
|
|
return op.exists(rpath) or op.islink(rpath) |
195
|
|
|
|