/
path_strings.py
289 lines (215 loc) · 8.55 KB
/
path_strings.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
from generallibrary import match, replace, deco_cache
from urllib.parse import quote
class _Path_Strings:
""" String operations for Path. """
def __getitem__(self, item):
""" Get character from path string.
:param generalfile.Path self: """
return self.Path(self.path.__getitem__(item))
@deco_cache()
def to_alternative(self):
""" Get path using alternative delimiter and alternative root for windows.
:param generalfile.Path self:
:rtype: generalfile.Path """
return self.Path(replace(string=self.path, **self._alternative_chars))
@deco_cache()
def from_alternative(self):
""" Get path from an alternative representation with or without leading lock dir.
:param generalfile.Path self:
:rtype: generalfile.Path """
path = str(self.remove_start(self.get_lock_dir()))
return self.Path(replace(string=path, reverse=True, **self._alternative_chars))
def absolute(self):
""" Get new Path as absolute.
:param generalfile.Path self:
:rtype: generalfile.Path """
if self.is_absolute():
return self
else:
return self.get_working_dir() / self
def relative(self, base=None):
""" Get new Path as relative, uses working dir if base is None.
Returns self if not inside base.
:param generalfile.Path self:
:param base: Defaults to working dir. """
if self.is_relative() and (base is None or not self.startswith(base)):
return self
else:
if base is None:
base = self.get_working_dir()
try:
return self.Path() if self == base else self.Path(self._path.relative_to(base))
except ValueError:
return None
@deco_cache()
def is_absolute(self):
""" Get whether this Path is absolute.
:param generalfile.Path self: """
return self._path.is_absolute()
@deco_cache()
def is_relative(self):
""" Get whether this Path is relative.
:param generalfile.Path self: """
return not self.is_absolute()
@deco_cache()
def mirror_path(self):
""" Return mirror Path which currently points to same destination based on working dir.
Absolute Path returns relative Path and vice versa.
:param generalfile.Path self:
:rtype: generalfile.Path """
if self.is_absolute():
return self.relative()
else:
return self.absolute()
@deco_cache()
def startswith(self, path):
""" Get whether this Path starts with given string.
:param generalfile.Path self:
:param str or Path path:"""
path = self.Path(path)
return self.path.startswith(str(path))
@deco_cache()
def endswith(self, path):
""" Get whether this Path ends with given string.
:param generalfile.Path self:
:param str or Path path:"""
path = self.Path(path)
return self.path.endswith(str(path))
@deco_cache()
def remove_start(self, path):
""" Remove a string from the start of this Path if it exists.
:param generalfile.Path self:
:param str or Path path:"""
path = self.Path(path)
str_path = str(path)
if not self.startswith(str_path):
return self
else:
new_path = self.Path(self.path[len(str_path):])
if str(new_path).startswith(path.path_delimiter):
return new_path[1:]
else:
return new_path
@deco_cache()
def remove_end(self, path):
""" Remove a string from the end of this Path if it exists.
:param generalfile.Path self:
:param str or Path path:"""
path = self.Path(path)
str_path = str(path)
if not self.endswith(str_path):
return self
else:
new_path = self.Path(self.path[:-len(str_path)])
if str(new_path).endswith(path.path_delimiter):
return new_path[:-1]
else:
return new_path
def same_destination(self, path):
""" See if two paths point to the same destination.
:param generalfile.Path self:
:param str or Path path:"""
path = self.Path(path)
return self.absolute() == path.absolute()
@deco_cache()
def parts(self):
""" Split path using it's delimiter.
With an absolute path the first index is an empty string on a posix system. <- Not sure about that anymore, might be /
:param generalfile.Path self: """
return self.path.split(self.path_delimiter)
@deco_cache()
def name(self):
""" Get string name of Path which is stem + suffix, or entire path if root.
:param generalfile.Path self: """
return self.path if self.is_root() else self._path.name
@deco_cache()
def with_name(self, name):
""" Get a new Path with new name which is stem + suffix.
:param name: Name.
:param generalfile.Path self:
:rtype: generalfile.Path """
return self.Path(self._path.with_name(str(name)))
@deco_cache()
def stem(self):
""" Get stem which is name without last suffix.
:param generalfile.Path self: """
return self._path.stem
@deco_cache()
def with_stem(self, stem):
""" Get a new Path with new stem which is name without last suffix.
:param stem: New stem.
:param generalfile.Path self:
:rtype: generalfile.Path """
return self.Path(self.with_name(f"{stem}{self.suffix()}"))
@deco_cache()
def true_stem(self):
""" Get true stem which is name without any suffixes.
:param generalfile.Path self: """
return self._path.stem.split(".")[0]
@deco_cache()
def with_true_stem(self, true_stem):
""" Get a new Path with new stem which is name without any suffixes.
:param true_stem: New true stem.
:param generalfile.Path self:
:rtype: generalfile.Path """
return self.Path(self.with_name(f"{true_stem}{''.join(self.suffixes())}"))
@deco_cache()
def suffix(self):
""" Get suffix which is name without stem (e.g. .txt or .json).
Empty string if missing.
:param generalfile.Path self: """
return self._path.suffix
@deco_cache()
def with_suffix(self, suffix, index=-1):
""" Get a new Path with a new suffix at any index.
Index is automatically clamped if it's outside index range.
Set suffix to `None` to remove a suffix.
:param generalfile.Path self:
:param suffix: New suffix, can be `None`.
:param index: Suffix index to alter.
:rtype: generalfile.Path """
suffixes = self.suffixes().copy()
try:
suffixes[index]
except IndexError:
if index >= len(suffixes):
if not suffix:
if suffixes:
del suffixes[-1]
else:
suffixes.append(suffix)
else:
if not suffix:
if suffixes:
del suffixes[0]
else:
suffixes.insert(0, suffix)
else:
if not suffix:
del suffixes[index]
else:
suffixes[index] = suffix
return self.with_name(f"{self.true_stem()}{''.join(suffixes)}")
@deco_cache()
def suffixes(self):
""" Get every suffix as a list.
:param generalfile.Path self: """
return self._path.suffixes
@deco_cache()
def with_suffixes(self, *suffixes):
""" Get a new Path with a new list of suffixes.
:param str suffixes: New suffixes
:param generalfile.Path self:
:rtype: generalfile.Path """
return self.Path(self.with_name(f"{self.true_stem()}{''.join(suffixes)}"))
@deco_cache()
def match(self, *patterns):
""" Get whether this Path matches any given filter line.
:param generalfile.Path self: """
return match(self.path, *map(self._replace_delimiters, patterns))
@deco_cache()
def encode(self):
""" Return a URL encoded string from this Path.
:param generalfile.Path self: """
url = self.path.replace("\\", "/")
return quote(url)