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
10ecbadb
Commit
10ecbadb
authored
Oct 21, 2019
by
Serhiy Storchaka
Committed by
GitHub
Oct 21, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bpo-31202: Preserve case of literal parts in Path.glob() on Windows. (GH-16860)
parent
1e739454
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
26 additions
and
18 deletions
+26
-18
Lib/pathlib.py
Lib/pathlib.py
+20
-18
Lib/test/test_pathlib.py
Lib/test/test_pathlib.py
+4
-0
Misc/NEWS.d/next/Library/2019-10-20-12-04-48.bpo-31202.NfdIus.rst
...S.d/next/Library/2019-10-20-12-04-48.bpo-31202.NfdIus.rst
+2
-0
No files found.
Lib/pathlib.py
View file @
10ecbadb
...
@@ -187,6 +187,9 @@ class _WindowsFlavour(_Flavour):
...
@@ -187,6 +187,9 @@ class _WindowsFlavour(_Flavour):
def
casefold_parts
(
self
,
parts
):
def
casefold_parts
(
self
,
parts
):
return
[
p
.
lower
()
for
p
in
parts
]
return
[
p
.
lower
()
for
p
in
parts
]
def
compile_pattern
(
self
,
pattern
):
return
re
.
compile
(
fnmatch
.
translate
(
pattern
),
re
.
IGNORECASE
).
fullmatch
def
resolve
(
self
,
path
,
strict
=
False
):
def
resolve
(
self
,
path
,
strict
=
False
):
s
=
str
(
path
)
s
=
str
(
path
)
if
not
s
:
if
not
s
:
...
@@ -309,6 +312,9 @@ class _PosixFlavour(_Flavour):
...
@@ -309,6 +312,9 @@ class _PosixFlavour(_Flavour):
def
casefold_parts
(
self
,
parts
):
def
casefold_parts
(
self
,
parts
):
return
parts
return
parts
def
compile_pattern
(
self
,
pattern
):
return
re
.
compile
(
fnmatch
.
translate
(
pattern
)).
fullmatch
def
resolve
(
self
,
path
,
strict
=
False
):
def
resolve
(
self
,
path
,
strict
=
False
):
sep
=
self
.
sep
sep
=
self
.
sep
accessor
=
path
.
_accessor
accessor
=
path
.
_accessor
...
@@ -446,7 +452,7 @@ _normal_accessor = _NormalAccessor()
...
@@ -446,7 +452,7 @@ _normal_accessor = _NormalAccessor()
# Globbing helpers
# Globbing helpers
#
#
def
_make_selector
(
pattern_parts
):
def
_make_selector
(
pattern_parts
,
flavour
):
pat
=
pattern_parts
[
0
]
pat
=
pattern_parts
[
0
]
child_parts
=
pattern_parts
[
1
:]
child_parts
=
pattern_parts
[
1
:]
if
pat
==
'**'
:
if
pat
==
'**'
:
...
@@ -457,7 +463,7 @@ def _make_selector(pattern_parts):
...
@@ -457,7 +463,7 @@ def _make_selector(pattern_parts):
cls
=
_WildcardSelector
cls
=
_WildcardSelector
else
:
else
:
cls
=
_PreciseSelector
cls
=
_PreciseSelector
return
cls
(
pat
,
child_parts
)
return
cls
(
pat
,
child_parts
,
flavour
)
if
hasattr
(
functools
,
"lru_cache"
):
if
hasattr
(
functools
,
"lru_cache"
):
_make_selector
=
functools
.
lru_cache
()(
_make_selector
)
_make_selector
=
functools
.
lru_cache
()(
_make_selector
)
...
@@ -467,10 +473,10 @@ class _Selector:
...
@@ -467,10 +473,10 @@ class _Selector:
"""A selector matches a specific glob pattern part against the children
"""A selector matches a specific glob pattern part against the children
of a given path."""
of a given path."""
def
__init__
(
self
,
child_parts
):
def
__init__
(
self
,
child_parts
,
flavour
):
self
.
child_parts
=
child_parts
self
.
child_parts
=
child_parts
if
child_parts
:
if
child_parts
:
self
.
successor
=
_make_selector
(
child_parts
)
self
.
successor
=
_make_selector
(
child_parts
,
flavour
)
self
.
dironly
=
True
self
.
dironly
=
True
else
:
else
:
self
.
successor
=
_TerminatingSelector
()
self
.
successor
=
_TerminatingSelector
()
...
@@ -496,9 +502,9 @@ class _TerminatingSelector:
...
@@ -496,9 +502,9 @@ class _TerminatingSelector:
class
_PreciseSelector
(
_Selector
):
class
_PreciseSelector
(
_Selector
):
def
__init__
(
self
,
name
,
child_parts
):
def
__init__
(
self
,
name
,
child_parts
,
flavour
):
self
.
name
=
name
self
.
name
=
name
_Selector
.
__init__
(
self
,
child_parts
)
_Selector
.
__init__
(
self
,
child_parts
,
flavour
)
def
_select_from
(
self
,
parent_path
,
is_dir
,
exists
,
scandir
):
def
_select_from
(
self
,
parent_path
,
is_dir
,
exists
,
scandir
):
try
:
try
:
...
@@ -512,13 +518,12 @@ class _PreciseSelector(_Selector):
...
@@ -512,13 +518,12 @@ class _PreciseSelector(_Selector):
class
_WildcardSelector
(
_Selector
):
class
_WildcardSelector
(
_Selector
):
def
__init__
(
self
,
pat
,
child_parts
):
def
__init__
(
self
,
pat
,
child_parts
,
flavour
):
self
.
pat
=
re
.
compile
(
fnmatch
.
translate
(
pat
)
)
self
.
match
=
flavour
.
compile_pattern
(
pat
)
_Selector
.
__init__
(
self
,
child_parts
)
_Selector
.
__init__
(
self
,
child_parts
,
flavour
)
def
_select_from
(
self
,
parent_path
,
is_dir
,
exists
,
scandir
):
def
_select_from
(
self
,
parent_path
,
is_dir
,
exists
,
scandir
):
try
:
try
:
cf
=
parent_path
.
_flavour
.
casefold
entries
=
list
(
scandir
(
parent_path
))
entries
=
list
(
scandir
(
parent_path
))
for
entry
in
entries
:
for
entry
in
entries
:
entry_is_dir
=
False
entry_is_dir
=
False
...
@@ -529,8 +534,7 @@ class _WildcardSelector(_Selector):
...
@@ -529,8 +534,7 @@ class _WildcardSelector(_Selector):
raise
raise
if
not
self
.
dironly
or
entry_is_dir
:
if
not
self
.
dironly
or
entry_is_dir
:
name
=
entry
.
name
name
=
entry
.
name
casefolded
=
cf
(
name
)
if
self
.
match
(
name
):
if
self
.
pat
.
match
(
casefolded
):
path
=
parent_path
.
_make_child_relpath
(
name
)
path
=
parent_path
.
_make_child_relpath
(
name
)
for
p
in
self
.
successor
.
_select_from
(
path
,
is_dir
,
exists
,
scandir
):
for
p
in
self
.
successor
.
_select_from
(
path
,
is_dir
,
exists
,
scandir
):
yield
p
yield
p
...
@@ -541,8 +545,8 @@ class _WildcardSelector(_Selector):
...
@@ -541,8 +545,8 @@ class _WildcardSelector(_Selector):
class
_RecursiveWildcardSelector
(
_Selector
):
class
_RecursiveWildcardSelector
(
_Selector
):
def
__init__
(
self
,
pat
,
child_parts
):
def
__init__
(
self
,
pat
,
child_parts
,
flavour
):
_Selector
.
__init__
(
self
,
child_parts
)
_Selector
.
__init__
(
self
,
child_parts
,
flavour
)
def
_iterate_directories
(
self
,
parent_path
,
is_dir
,
scandir
):
def
_iterate_directories
(
self
,
parent_path
,
is_dir
,
scandir
):
yield
parent_path
yield
parent_path
...
@@ -1118,11 +1122,10 @@ class Path(PurePath):
...
@@ -1118,11 +1122,10 @@ class Path(PurePath):
"""
"""
if
not
pattern
:
if
not
pattern
:
raise
ValueError
(
"Unacceptable pattern: {!r}"
.
format
(
pattern
))
raise
ValueError
(
"Unacceptable pattern: {!r}"
.
format
(
pattern
))
pattern
=
self
.
_flavour
.
casefold
(
pattern
)
drv
,
root
,
pattern_parts
=
self
.
_flavour
.
parse_parts
((
pattern
,))
drv
,
root
,
pattern_parts
=
self
.
_flavour
.
parse_parts
((
pattern
,))
if
drv
or
root
:
if
drv
or
root
:
raise
NotImplementedError
(
"Non-relative patterns are unsupported"
)
raise
NotImplementedError
(
"Non-relative patterns are unsupported"
)
selector
=
_make_selector
(
tuple
(
pattern_parts
))
selector
=
_make_selector
(
tuple
(
pattern_parts
)
,
self
.
_flavour
)
for
p
in
selector
.
select_from
(
self
):
for
p
in
selector
.
select_from
(
self
):
yield
p
yield
p
...
@@ -1131,11 +1134,10 @@ class Path(PurePath):
...
@@ -1131,11 +1134,10 @@ class Path(PurePath):
directories) matching the given relative pattern, anywhere in
directories) matching the given relative pattern, anywhere in
this subtree.
this subtree.
"""
"""
pattern
=
self
.
_flavour
.
casefold
(
pattern
)
drv
,
root
,
pattern_parts
=
self
.
_flavour
.
parse_parts
((
pattern
,))
drv
,
root
,
pattern_parts
=
self
.
_flavour
.
parse_parts
((
pattern
,))
if
drv
or
root
:
if
drv
or
root
:
raise
NotImplementedError
(
"Non-relative patterns are unsupported"
)
raise
NotImplementedError
(
"Non-relative patterns are unsupported"
)
selector
=
_make_selector
((
"**"
,)
+
tuple
(
pattern_parts
))
selector
=
_make_selector
((
"**"
,)
+
tuple
(
pattern_parts
)
,
self
.
_flavour
)
for
p
in
selector
.
select_from
(
self
):
for
p
in
selector
.
select_from
(
self
):
yield
p
yield
p
...
...
Lib/test/test_pathlib.py
View file @
10ecbadb
...
@@ -2378,11 +2378,15 @@ class WindowsPathTest(_BasePathTest, unittest.TestCase):
...
@@ -2378,11 +2378,15 @@ class WindowsPathTest(_BasePathTest, unittest.TestCase):
P
=
self
.
cls
P
=
self
.
cls
p
=
P
(
BASE
)
p
=
P
(
BASE
)
self
.
assertEqual
(
set
(
p
.
glob
(
"FILEa"
)),
{
P
(
BASE
,
"fileA"
)
})
self
.
assertEqual
(
set
(
p
.
glob
(
"FILEa"
)),
{
P
(
BASE
,
"fileA"
)
})
self
.
assertEqual
(
set
(
p
.
glob
(
"F*a"
)),
{
P
(
BASE
,
"fileA"
)
})
self
.
assertEqual
(
set
(
map
(
str
,
p
.
glob
(
"FILEa"
))),
{
f"
{
p
}\
\
FILEa"
})
self
.
assertEqual
(
set
(
map
(
str
,
p
.
glob
(
"F*a"
))),
{
f"
{
p
}\
\
fileA"
})
def
test_rglob
(
self
):
def
test_rglob
(
self
):
P
=
self
.
cls
P
=
self
.
cls
p
=
P
(
BASE
,
"dirC"
)
p
=
P
(
BASE
,
"dirC"
)
self
.
assertEqual
(
set
(
p
.
rglob
(
"FILEd"
)),
{
P
(
BASE
,
"dirC/dirD/fileD"
)
})
self
.
assertEqual
(
set
(
p
.
rglob
(
"FILEd"
)),
{
P
(
BASE
,
"dirC/dirD/fileD"
)
})
self
.
assertEqual
(
set
(
map
(
str
,
p
.
rglob
(
"FILEd"
))),
{
f"
{
p
}\
\
dirD
\
\
FILEd"
})
def
test_expanduser
(
self
):
def
test_expanduser
(
self
):
P
=
self
.
cls
P
=
self
.
cls
...
...
Misc/NEWS.d/next/Library/2019-10-20-12-04-48.bpo-31202.NfdIus.rst
0 → 100644
View file @
10ecbadb
The case the result of :func:`pathlib.WindowsPath.glob` matches now the case
of the pattern for literal parts.
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