FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[Original HTTPS Page]
cpython/Lib/posixpath.py at 3.5 · python/cpython · GitHub
python
cpython
Repository navigation
Code
Issues
5k+
(5k+)
Pull requests
2.7k
(2.7k)
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
cpython
/
Lib
/
posixpath.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
503 lines (429 loc) · 14.6 KB
Breadcrumbs
cpython
/
Lib
/
posixpath.py
Copy path
File metadata and controls
503 lines (429 loc) · 14.6 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
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
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
"""Common operations on Posix pathnames.
Instead of importing this module directly, import os and refer to
this module as os.path. The "os.path" name is an alias for this
module on Posix systems; on other systems (e.g. Mac, Windows),
os.path provides the same operations in a manner specific to that
platform, and is an alias to another module (e.g. macpath, ntpath).
Some of this can actually be useful on non-Posix systems too, e.g.
for manipulation of the pathname component of URLs.
"""
import
os
import
sys
import
stat
import
genericpath
from
genericpath
import
*
__all__
=
[
"normcase"
,
"isabs"
,
"join"
,
"splitdrive"
,
"split"
,
"splitext"
,
"basename"
,
"dirname"
,
"commonprefix"
,
"getsize"
,
"getmtime"
,
"getatime"
,
"getctime"
,
"islink"
,
"exists"
,
"lexists"
,
"isdir"
,
"isfile"
,
"ismount"
,
"expanduser"
,
"expandvars"
,
"normpath"
,
"abspath"
,
"samefile"
,
"sameopenfile"
,
"samestat"
,
"curdir"
,
"pardir"
,
"sep"
,
"pathsep"
,
"defpath"
,
"altsep"
,
"extsep"
,
"devnull"
,
"realpath"
,
"supports_unicode_filenames"
,
"relpath"
,
"commonpath"
]
# Strings representing various path-related bits and pieces.
# These are primarily for export; internally, they are hardcoded.
curdir
=
'.'
pardir
=
'..'
extsep
=
'.'
sep
=
'/'
pathsep
=
':'
defpath
=
':/bin:/usr/bin'
altsep
=
None
devnull
=
'/dev/null'
def
_get_sep
(
path
):
if
isinstance
(
path
,
bytes
):
return
b'/'
else
:
return
'/'
# Normalize the case of a pathname. Trivial in Posix, string.lower on Mac.
# On MS-DOS this may also turn slashes into backslashes; however, other
# normalizations (such as optimizing '../' away) are not allowed
# (another function should be defined to do that).
def
normcase
(
s
):
"""Normalize case of pathname. Has no effect under Posix"""
if
not
isinstance
(
s
, (
bytes
,
str
)):
raise
TypeError
(
"normcase() argument must be str or bytes, "
"not '{}'"
.
format
(
s
.
__class__
.
__name__
))
return
s
# Return whether a path is absolute.
# Trivial in Posix, harder on the Mac or MS-DOS.
def
isabs
(
s
):
"""Test whether a path is absolute"""
sep
=
_get_sep
(
s
)
return
s
.
startswith
(
sep
)
# Join pathnames.
# Ignore the previous parts if a part is absolute.
# Insert a '/' unless the first part is empty or already ends in '/'.
def
join
(
a
,
*
p
):
"""Join two or more pathname components, inserting '/' as needed.
If any component is an absolute path, all previous path components
will be discarded. An empty last part will result in a path that
ends with a separator."""
sep
=
_get_sep
(
a
)
path
=
a
try
:
if
not
p
:
path
[:
0
]
+
sep
#23780: Ensure compatible data type even if p is null.
for
b
in
p
:
if
b
.
startswith
(
sep
):
path
=
b
elif
not
path
or
path
.
endswith
(
sep
):
path
+=
b
else
:
path
+=
sep
+
b
except
(
TypeError
,
AttributeError
,
BytesWarning
):
genericpath
.
_check_arg_types
(
'join'
,
a
,
*
p
)
raise
return
path
# Split a path in head (everything up to the last '/') and tail (the
# rest). If the path ends in '/', tail will be empty. If there is no
# '/' in the path, head will be empty.
# Trailing '/'es are stripped from head unless it is the root.
def
split
(
p
):
"""Split a pathname. Returns tuple "(head, tail)" where "tail" is
everything after the final slash. Either part may be empty."""
sep
=
_get_sep
(
p
)
i
=
p
.
rfind
(
sep
)
+
1
head
,
tail
=
p
[:
i
],
p
[
i
:]
if
head
and
head
!=
sep
*
len
(
head
):
head
=
head
.
rstrip
(
sep
)
return
head
,
tail
# Split a path in root and extension.
# The extension is everything starting at the last dot in the last
# pathname component; the root is everything before that.
# It is always true that root + ext == p.
def
splitext
(
p
):
if
isinstance
(
p
,
bytes
):
sep
=
b'/'
extsep
=
b'.'
else
:
sep
=
'/'
extsep
=
'.'
return
genericpath
.
_splitext
(
p
,
sep
,
None
,
extsep
)
splitext
.
__doc__
=
genericpath
.
_splitext
.
__doc__
# Split a pathname into a drive specification and the rest of the
# path. Useful on DOS/Windows/NT; on Unix, the drive is always empty.
def
splitdrive
(
p
):
"""Split a pathname into drive and path. On Posix, drive is always
empty."""
return
p
[:
0
],
p
# Return the tail (basename) part of a path, same as split(path)[1].
def
basename
(
p
):
"""Returns the final component of a pathname"""
sep
=
_get_sep
(
p
)
i
=
p
.
rfind
(
sep
)
+
1
return
p
[
i
:]
# Return the head (dirname) part of a path, same as split(path)[0].
def
dirname
(
p
):
"""Returns the directory component of a pathname"""
sep
=
_get_sep
(
p
)
i
=
p
.
rfind
(
sep
)
+
1
head
=
p
[:
i
]
if
head
and
head
!=
sep
*
len
(
head
):
head
=
head
.
rstrip
(
sep
)
return
head
# Is a path a symbolic link?
# This will always return false on systems where os.lstat doesn't exist.
def
islink
(
path
):
"""Test whether a path is a symbolic link"""
try
:
st
=
os
.
lstat
(
path
)
except
(
OSError
,
AttributeError
):
return
False
return
stat
.
S_ISLNK
(
st
.
st_mode
)
# Being true for dangling symbolic links is also useful.
def
lexists
(
path
):
"""Test whether a path exists. Returns True for broken symbolic links"""
try
:
os
.
lstat
(
path
)
except
OSError
:
return
False
return
True
# Is a path a mount point?
# (Does this work for all UNIXes? Is it even guaranteed to work by Posix?)
def
ismount
(
path
):
"""Test whether a path is a mount point"""
try
:
s1
=
os
.
lstat
(
path
)
except
OSError
:
# It doesn't exist -- so not a mount point. :-)
return
False
else
:
# A symlink can never be a mount point
if
stat
.
S_ISLNK
(
s1
.
st_mode
):
return
False
if
isinstance
(
path
,
bytes
):
parent
=
join
(
path
,
b'..'
)
else
:
parent
=
join
(
path
,
'..'
)
parent
=
realpath
(
parent
)
try
:
s2
=
os
.
lstat
(
parent
)
except
OSError
:
return
False
dev1
=
s1
.
st_dev
dev2
=
s2
.
st_dev
if
dev1
!=
dev2
:
return
True
# path/.. on a different device as path
ino1
=
s1
.
st_ino
ino2
=
s2
.
st_ino
if
ino1
==
ino2
:
return
True
# path/.. is the same i-node as path
return
False
# Expand paths beginning with '~' or '~user'.
# '~' means $HOME; '~user' means that user's home directory.
# If the path doesn't begin with '~', or if the user or $HOME is unknown,
# the path is returned unchanged (leaving error reporting to whatever
# function is called with the expanded path as argument).
# See also module 'glob' for expansion of *, ? and [...] in pathnames.
# (A function should also be defined to do full *sh-style environment
# variable expansion.)
def
expanduser
(
path
):
"""Expand ~ and ~user constructions. If user or $HOME is unknown,
do nothing."""
if
isinstance
(
path
,
bytes
):
tilde
=
b'~'
else
:
tilde
=
'~'
if
not
path
.
startswith
(
tilde
):
return
path
sep
=
_get_sep
(
path
)
i
=
path
.
find
(
sep
,
1
)
if
i
<
0
:
i
=
len
(
path
)
if
i
==
1
:
if
'HOME'
not
in
os
.
environ
:
import
pwd
userhome
=
pwd
.
getpwuid
(
os
.
getuid
()).
pw_dir
else
:
userhome
=
os
.
environ
[
'HOME'
]
else
:
import
pwd
name
=
path
[
1
:
i
]
if
isinstance
(
name
,
bytes
):
name
=
str
(
name
,
'ASCII'
)
try
:
pwent
=
pwd
.
getpwnam
(
name
)
except
KeyError
:
return
path
userhome
=
pwent
.
pw_dir
if
isinstance
(
path
,
bytes
):
userhome
=
os
.
fsencode
(
userhome
)
root
=
b'/'
else
:
root
=
'/'
userhome
=
userhome
.
rstrip
(
root
)
return
(
userhome
+
path
[
i
:])
or
root
# Expand paths containing shell variable substitutions.
# This expands the forms $variable and ${variable} only.
# Non-existent variables are left unchanged.
_varprog
=
None
_varprogb
=
None
def
expandvars
(
path
):
"""Expand shell variables of form $var and ${var}. Unknown variables
are left unchanged."""
global
_varprog
,
_varprogb
if
isinstance
(
path
,
bytes
):
if
b'$'
not
in
path
:
return
path
if
not
_varprogb
:
import
re
_varprogb
=
re
.
compile
(
br'\$(\w+|\{[^}]*\})'
,
re
.
ASCII
)
search
=
_varprogb
.
search
start
=
b'{'
end
=
b'}'
environ
=
getattr
(
os
,
'environb'
,
None
)
else
:
if
'$'
not
in
path
:
return
path
if
not
_varprog
:
import
re
_varprog
=
re
.
compile
(
r'\$(\w+|\{[^}]*\})'
,
re
.
ASCII
)
search
=
_varprog
.
search
start
=
'{'
end
=
'}'
environ
=
os
.
environ
i
=
0
while
True
:
m
=
search
(
path
,
i
)
if
not
m
:
break
i
,
j
=
m
.
span
(
0
)
name
=
m
.
group
(
1
)
if
name
.
startswith
(
start
)
and
name
.
endswith
(
end
):
name
=
name
[
1
:
-
1
]
try
:
if
environ
is
None
:
value
=
os
.
fsencode
(
os
.
environ
[
os
.
fsdecode
(
name
)])
else
:
value
=
environ
[
name
]
except
KeyError
:
i
=
j
else
:
tail
=
path
[
j
:]
path
=
path
[:
i
]
+
value
i
=
len
(
path
)
path
+=
tail
return
path
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
# It should be understood that this may change the meaning of the path
# if it contains symbolic links!
def
normpath
(
path
):
"""Normalize path, eliminating double slashes, etc."""
if
isinstance
(
path
,
bytes
):
sep
=
b'/'
empty
=
b''
dot
=
b'.'
dotdot
=
b'..'
else
:
sep
=
'/'
empty
=
''
dot
=
'.'
dotdot
=
'..'
if
path
==
empty
:
return
dot
initial_slashes
=
path
.
startswith
(
sep
)
# POSIX allows one or two initial slashes, but treats three or more
# as single slash.
if
(
initial_slashes
and
path
.
startswith
(
sep
*
2
)
and
not
path
.
startswith
(
sep
*
3
)):
initial_slashes
=
2
comps
=
path
.
split
(
sep
)
new_comps
=
[]
for
comp
in
comps
:
if
comp
in
(
empty
,
dot
):
continue
if
(
comp
!=
dotdot
or
(
not
initial_slashes
and
not
new_comps
)
or
(
new_comps
and
new_comps
[
-
1
]
==
dotdot
)):
new_comps
.
append
(
comp
)
elif
new_comps
:
new_comps
.
pop
()
comps
=
new_comps
path
=
sep
.
join
(
comps
)
if
initial_slashes
:
path
=
sep
*
initial_slashes
+
path
return
path
or
dot
def
abspath
(
path
):
"""Return an absolute path."""
if
not
isabs
(
path
):
if
isinstance
(
path
,
bytes
):
cwd
=
os
.
getcwdb
()
else
:
cwd
=
os
.
getcwd
()
path
=
join
(
cwd
,
path
)
return
normpath
(
path
)
# Return a canonical path (i.e. the absolute location of a file on the
# filesystem).
def
realpath
(
filename
):
"""Return the canonical path of the specified filename, eliminating any
symbolic links encountered in the path."""
path
,
ok
=
_joinrealpath
(
filename
[:
0
],
filename
, {})
return
abspath
(
path
)
# Join two paths, normalizing and eliminating any symbolic links
# encountered in the second path.
def
_joinrealpath
(
path
,
rest
,
seen
):
if
isinstance
(
path
,
bytes
):
sep
=
b'/'
curdir
=
b'.'
pardir
=
b'..'
else
:
sep
=
'/'
curdir
=
'.'
pardir
=
'..'
if
isabs
(
rest
):
rest
=
rest
[
1
:]
path
=
sep
while
rest
:
name
,
_
,
rest
=
rest
.
partition
(
sep
)
if
not
name
or
name
==
curdir
:
# current dir
continue
if
name
==
pardir
:
# parent dir
if
path
:
path
,
name
=
split
(
path
)
if
name
==
pardir
:
path
=
join
(
path
,
pardir
,
pardir
)
else
:
path
=
pardir
continue
newpath
=
join
(
path
,
name
)
if
not
islink
(
newpath
):
path
=
newpath
continue
# Resolve the symbolic link
if
newpath
in
seen
:
# Already seen this path
path
=
seen
[
newpath
]
if
path
is
not
None
:
# use cached value
continue
# The symlink is not resolved, so we must have a symlink loop.
# Return already resolved part + rest of the path unchanged.
return
join
(
newpath
,
rest
),
False
seen
[
newpath
]
=
None
# not resolved symlink
path
,
ok
=
_joinrealpath
(
path
,
os
.
readlink
(
newpath
),
seen
)
if
not
ok
:
return
join
(
path
,
rest
),
False
seen
[
newpath
]
=
path
# resolved symlink
return
path
,
True
supports_unicode_filenames
=
(
sys
.
platform
==
'darwin'
)
def
relpath
(
path
,
start
=
None
):
"""Return a relative version of a path"""
if
not
path
:
raise
ValueError
(
"no path specified"
)
if
isinstance
(
path
,
bytes
):
curdir
=
b'.'
sep
=
b'/'
pardir
=
b'..'
else
:
curdir
=
'.'
sep
=
'/'
pardir
=
'..'
if
start
is
None
:
start
=
curdir
try
:
start_list
=
[
x
for
x
in
abspath
(
start
).
split
(
sep
)
if
x
]
path_list
=
[
x
for
x
in
abspath
(
path
).
split
(
sep
)
if
x
]
# Work out how much of the filepath is shared by start and path.
i
=
len
(
commonprefix
([
start_list
,
path_list
]))
rel_list
=
[
pardir
]
*
(
len
(
start_list
)
-
i
)
+
path_list
[
i
:]
if
not
rel_list
:
return
curdir
return
join
(
*
rel_list
)
except
(
TypeError
,
AttributeError
,
BytesWarning
,
DeprecationWarning
):
genericpath
.
_check_arg_types
(
'relpath'
,
path
,
start
)
raise
# Return the longest common sub-path of the sequence of paths given as input.
# The paths are not normalized before comparing them (this is the
# responsibility of the caller). Any trailing separator is stripped from the
# returned path.
def
commonpath
(
paths
):
"""Given a sequence of path names, returns the longest common sub-path."""
if
not
paths
:
raise
ValueError
(
'commonpath() arg is an empty sequence'
)
if
isinstance
(
paths
[
0
],
bytes
):
sep
=
b'/'
curdir
=
b'.'
else
:
sep
=
'/'
curdir
=
'.'
try
:
split_paths
=
[
path
.
split
(
sep
)
for
path
in
paths
]
try
:
isabs
,
=
set
(
p
[:
1
]
==
sep
for
p
in
paths
)
except
ValueError
:
raise
ValueError
(
"Can't mix absolute and relative paths"
)
from
None
split_paths
=
[[
c
for
c
in
s
if
c
and
c
!=
curdir
]
for
s
in
split_paths
]
s1
=
min
(
split_paths
)
s2
=
max
(
split_paths
)
common
=
s1
for
i
,
c
in
enumerate
(
s1
):
if
c
!=
s2
[
i
]:
common
=
s1
[:
i
]
break
prefix
=
sep
if
isabs
else
sep
[:
0
]
return
prefix
+
sep
.
join
(
common
)
except
(
TypeError
,
AttributeError
):
genericpath
.
_check_arg_types
(
'commonpath'
,
*
paths
)
raise
Back
|
FazBrowse Home
|
New Git URL