Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
f5d2f224
Commit
f5d2f224
authored
Jan 27, 2014
by
Serhiy Storchaka
Browse files
Options
Browse Files
Download
Plain Diff
Issue #19456: ntpath.join() now joins relative paths correctly when a drive
is present.
parents
2393dca4
c369c2c6
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
69 additions
and
109 deletions
+69
-109
Lib/ntpath.py
Lib/ntpath.py
+30
-76
Lib/test/test_ntpath.py
Lib/test/test_ntpath.py
+36
-33
Misc/NEWS
Misc/NEWS
+3
-0
No files found.
Lib/ntpath.py
View file @
f5d2f224
...
...
@@ -101,82 +101,36 @@ def isabs(s):
# Join two (or more) paths.
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."""
sep
=
_get_sep
(
a
)
seps
=
_get_bothseps
(
a
)
colon
=
_get_colon
(
a
)
path
=
a
for
b
in
p
:
b_wins
=
0
# set to 1 iff b makes path irrelevant
if
not
path
:
b_wins
=
1
elif
isabs
(
b
):
# This probably wipes out path so far. However, it's more
# complicated if path begins with a drive letter. You get a+b
# (minus redundant slashes) in these four cases:
# 1. join('c:', '/a') == 'c:/a'
# 2. join('//computer/share', '/a') == '//computer/share/a'
# 3. join('c:/', '/a') == 'c:/a'
# 4. join('//computer/share/', '/a') == '//computer/share/a'
# But b wins in all of these cases:
# 5. join('c:/a', '/b') == '/b'
# 6. join('//computer/share/a', '/b') == '/b'
# 7. join('c:', 'd:/') == 'd:/'
# 8. join('c:', '//computer/share/') == '//computer/share/'
# 9. join('//computer/share', 'd:/') == 'd:/'
# 10. join('//computer/share', '//computer/share/') == '//computer/share/'
# 11. join('c:/', 'd:/') == 'd:/'
# 12. join('c:/', '//computer/share/') == '//computer/share/'
# 13. join('//computer/share/', 'd:/') == 'd:/'
# 14. join('//computer/share/', '//computer/share/') == '//computer/share/'
b_prefix
,
b_rest
=
splitdrive
(
b
)
# if b has a prefix, it always wins.
if
b_prefix
:
b_wins
=
1
else
:
# b doesn't have a prefix.
# but isabs(b) returned true.
# and therefore b_rest[0] must be a slash.
# (but let's check that.)
assert
(
b_rest
and
b_rest
[
0
]
in
seps
)
# so, b still wins if path has a rest that's more than a sep.
# you get a+b if path_rest is empty or only has a sep.
# (see cases 1-4 for times when b loses.)
path_rest
=
splitdrive
(
path
)[
1
]
b_wins
=
path_rest
and
path_rest
not
in
seps
if
b_wins
:
path
=
b
else
:
# Join, and ensure there's a separator.
assert
len
(
path
)
>
0
if
path
[
-
1
:]
in
seps
:
if
b
and
b
[:
1
]
in
seps
:
path
+=
b
[
1
:]
else
:
path
+=
b
elif
path
[
-
1
:]
==
colon
:
path
+=
b
elif
b
:
if
b
[:
1
]
in
seps
:
path
+=
b
else
:
path
+=
sep
+
b
else
:
# path is not empty and does not end with a backslash,
# but b is empty; since, e.g., split('a/') produces
# ('a', ''), it's best if join() adds a backslash in
# this case.
path
+=
sep
return
path
def
join
(
path
,
*
paths
):
sep
=
_get_sep
(
path
)
seps
=
_get_bothseps
(
path
)
colon
=
_get_colon
(
path
)
result_drive
,
result_path
=
splitdrive
(
path
)
for
p
in
paths
:
p_drive
,
p_path
=
splitdrive
(
p
)
if
p_path
and
p_path
[
0
]
in
seps
:
# Second path is absolute
if
p_drive
or
not
result_drive
:
result_drive
=
p_drive
result_path
=
p_path
continue
elif
p_drive
and
p_drive
!=
result_drive
:
if
p_drive
.
lower
()
!=
result_drive
.
lower
():
# Different drives => ignore the first path entirely
result_drive
=
p_drive
result_path
=
p_path
continue
# Same drive in different case
result_drive
=
p_drive
# Second path is relative to the first
if
result_path
and
result_path
[
-
1
]
not
in
seps
:
result_path
=
result_path
+
sep
result_path
=
result_path
+
p_path
## add separator between UNC and non-absolute path
if
(
result_path
and
result_path
[
0
]
not
in
seps
and
result_drive
and
result_drive
[
-
1
:]
!=
colon
):
return
result_drive
+
sep
+
result_path
return
result_drive
+
result_path
# Split a path in a drive specification (a drive letter followed by a
...
...
Lib/test/test_ntpath.py
View file @
f5d2f224
...
...
@@ -126,10 +126,7 @@ class TestNtpath(unittest.TestCase):
tester
(
'ntpath.join("/a")'
,
'/a'
)
tester
(
'ntpath.join("
\
\
a")'
,
'
\
\
a'
)
tester
(
'ntpath.join("a:")'
,
'a:'
)
tester
(
'ntpath.join("a:", "b")'
,
'a:b'
)
tester
(
'ntpath.join("a:", "/b")'
,
'a:/b'
)
tester
(
'ntpath.join("a:", "
\
\
b")'
,
'a:
\
\
b'
)
tester
(
'ntpath.join("a", "/b")'
,
'/b'
)
tester
(
'ntpath.join("a", "
\
\
b")'
,
'
\
\
b'
)
tester
(
'ntpath.join("a", "b", "c")'
,
'a
\
\
b
\
\
c'
)
tester
(
'ntpath.join("a
\
\
", "b", "c")'
,
'a
\
\
b
\
\
c'
)
...
...
@@ -137,42 +134,48 @@ class TestNtpath(unittest.TestCase):
tester
(
'ntpath.join("a", "b", "
\
\
c")'
,
'
\
\
c'
)
tester
(
'ntpath.join("d:
\
\
", "
\
\
pleep")'
,
'd:
\
\
pleep'
)
tester
(
'ntpath.join("d:
\
\
", "a", "b")'
,
'd:
\
\
a
\
\
b'
)
tester
(
"ntpath.join('c:', '/a')"
,
'c:/a'
)
tester
(
"ntpath.join('c:/', '/a')"
,
'c:/a'
)
tester
(
"ntpath.join('c:/a', '/b')"
,
'/b'
)
tester
(
"ntpath.join('c:', 'd:/')"
,
'd:/'
)
tester
(
"ntpath.join('c:/', 'd:/')"
,
'd:/'
)
tester
(
"ntpath.join('c:/', 'd:/a/b')"
,
'd:/a/b'
)
tester
(
"ntpath.join('')"
,
''
)
tester
(
"ntpath.join('', '', '', '', '')"
,
''
)
tester
(
"ntpath.join('a')"
,
'a'
)
tester
(
"ntpath.join('', 'a')"
,
'a'
)
tester
(
"ntpath.join('', '', '', '', 'a')"
,
'a'
)
tester
(
"ntpath.join('a', '')"
,
'a
\
\
'
)
tester
(
"ntpath.join('a', '', '', '', '')"
,
'a
\
\
'
)
tester
(
"ntpath.join('a
\
\
', '')"
,
'a
\
\
'
)
tester
(
"ntpath.join('a
\
\
', '', '', '', '')"
,
'a
\
\
'
)
# from comment in ntpath.join
tester
(
"ntpath.join('c:', '/a')"
,
'c:/a'
)
tester
(
"ntpath.join('//computer/share', '/a')"
,
'//computer/share/a'
)
tester
(
"ntpath.join('c:/', '/a')"
,
'c:/a'
)
tester
(
"ntpath.join('//computer/share/', '/a')"
,
'//computer/share/a'
)
tester
(
"ntpath.join('c:/a', '/b')"
,
'/b'
)
tester
(
"ntpath.join('//computer/share/a', '/b')"
,
'/b'
)
tester
(
"ntpath.join('c:', 'd:/')"
,
'd:/'
)
tester
(
"ntpath.join('c:', '//computer/share/')"
,
'//computer/share/'
)
tester
(
"ntpath.join('//computer/share', 'd:/')"
,
'd:/'
)
tester
(
"ntpath.join('//computer/share', '//computer/share/')"
,
'//computer/share/'
)
tester
(
"ntpath.join('c:/', 'd:/')"
,
'd:/'
)
tester
(
"ntpath.join('c:/', '//computer/share/')"
,
'//computer/share/'
)
tester
(
"ntpath.join('//computer/share/', 'd:/')"
,
'd:/'
)
tester
(
"ntpath.join('//computer/share/', '//computer/share/')"
,
'//computer/share/'
)
tester
(
"ntpath.join('c:', '//computer/share/')"
,
'//computer/share/'
)
tester
(
"ntpath.join('c:/', '//computer/share/')"
,
'//computer/share/'
)
tester
(
"ntpath.join('c:/', '//computer/share/a/b')"
,
'//computer/share/a/b'
)
tester
(
"ntpath.join('a/', '')"
,
'a/'
)
tester
(
"ntpath.join('a/b', 'x/y')"
,
'a/b
\
\
x/y'
)
tester
(
"ntpath.join('/a/b', 'x/y')"
,
'/a/b
\
\
x/y'
)
tester
(
"ntpath.join('/a/b/', 'x/y')"
,
'/a/b/x/y'
)
tester
(
"ntpath.join('c:', 'x/y')"
,
'c:x/y'
)
tester
(
"ntpath.join('c:a/b', 'x/y')"
,
'c:a/b
\
\
x/y'
)
tester
(
"ntpath.join('c:a/b/', 'x/y')"
,
'c:a/b/x/y'
)
tester
(
"ntpath.join('c:/', 'x/y')"
,
'c:/x/y'
)
tester
(
"ntpath.join('c:/a/b', 'x/y')"
,
'c:/a/b
\
\
x/y'
)
tester
(
"ntpath.join('c:/a/b/', 'x/y')"
,
'c:/a/b/x/y'
)
tester
(
"ntpath.join('//computer/share', 'x/y')"
,
'//computer/share
\
\
x/y'
)
tester
(
"ntpath.join('//computer/share/', 'x/y')"
,
'//computer/share/x/y'
)
tester
(
"ntpath.join('//computer/share/a/b', 'x/y')"
,
'//computer/share/a/b
\
\
x/y'
)
tester
(
"ntpath.join('a/b', '/x/y')"
,
'/x/y'
)
tester
(
"ntpath.join('/a/b', '/x/y')"
,
'/x/y'
)
tester
(
"ntpath.join('c:', '/x/y')"
,
'c:/x/y'
)
tester
(
"ntpath.join('c:a/b', '/x/y')"
,
'c:/x/y'
)
tester
(
"ntpath.join('c:/', '/x/y')"
,
'c:/x/y'
)
tester
(
"ntpath.join('c:/a/b', '/x/y')"
,
'c:/x/y'
)
tester
(
"ntpath.join('//computer/share', '/x/y')"
,
'//computer/share/x/y'
)
tester
(
"ntpath.join('//computer/share/', '/x/y')"
,
'//computer/share/x/y'
)
tester
(
"ntpath.join('//computer/share/a', '/x/y')"
,
'//computer/share/x/y'
)
tester
(
"ntpath.join('c:', 'C:x/y')"
,
'C:x/y'
)
tester
(
"ntpath.join('c:a/b', 'C:x/y')"
,
'C:a/b
\
\
x/y'
)
tester
(
"ntpath.join('c:/', 'C:x/y')"
,
'C:/x/y'
)
tester
(
"ntpath.join('c:/a/b', 'C:x/y')"
,
'C:/a/b
\
\
x/y'
)
for
x
in
(
''
,
'a/b'
,
'/a/b'
,
'c:'
,
'c:a/b'
,
'c:/'
,
'c:/a/b'
,
'//computer/share'
,
'//computer/share/'
,
'//computer/share/a/b'
):
for
y
in
(
'd:'
,
'd:x/y'
,
'd:/'
,
'd:/x/y'
,
'//machine/common'
,
'//machine/common/'
,
'//machine/common/x/y'
):
tester
(
"ntpath.join(%r, %r)"
%
(
x
,
y
),
y
)
tester
(
"ntpath.join('
\
\
\
\
computer
\
\
share
\
\
', 'a', 'b')"
,
'
\
\
\
\
computer
\
\
share
\
\
a
\
\
b'
)
tester
(
"ntpath.join('
\
\
\
\
computer
\
\
share', 'a', 'b')"
,
'
\
\
\
\
computer
\
\
share
\
\
a
\
\
b'
)
...
...
Misc/NEWS
View file @
f5d2f224
...
...
@@ -48,6 +48,9 @@ Core and Builtins
Library
-------
-
Issue
#
19456
:
ntpath
.
join
()
now
joins
relative
paths
correctly
when
a
drive
is
present
.
-
Issue
#
19077
:
tempfile
.
TemporaryDirectory
cleanup
no
longer
fails
when
called
during
shutdown
.
Emitting
resource
warning
in
__del__
no
longer
fails
.
Original
patch
by
Antoine
Pitrou
.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment