Skip to content

Commit c5c0a76

Browse files
committed
Improve validation/sanitization precision for WIndows platform
1 parent db3e58f commit c5c0a76

File tree

3 files changed

+56
-20
lines changed

3 files changed

+56
-20
lines changed

pathvalidate/_common.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import re
1010
import string
1111
import sys
12-
from os.path import normpath
1312

1413
from ._six import text_type
1514
from .error import NullNameError
@@ -53,7 +52,7 @@ def preprocess(name):
5352
if is_pathlike_obj(name):
5453
name = text_type(name)
5554

56-
return normpath(name)
55+
return name
5756

5857

5958
def is_null_string(value):

pathvalidate/_file.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import enum
1010
import itertools
11+
import ntpath
1112
import os.path
1213
import platform
1314
import re
@@ -295,20 +296,23 @@ def sanitize(self, value, replacement_text=""):
295296
except AttributeError as e:
296297
raise ValueError(e)
297298

299+
drive, unicode_file_path = ntpath.splitdrive(unicode_file_path)
298300
sanitized_path = self._sanitize_regexp.sub(replacement_text, unicode_file_path)
299-
300-
if len(sanitized_path.split("/")) > len(sanitized_path.split("\\")):
301-
path_separator = "/"
302-
else:
301+
if self._is_windows():
303302
path_separator = "\\"
303+
else:
304+
path_separator = "/"
304305

305306
sanitized_entries = []
307+
if drive:
308+
sanitized_entries.append(drive)
306309
for entry in sanitized_path.replace("\\", "/").split("/"):
307310
try:
308311
sanitized_entries.append(self.__fname_sanitizer.sanitize(entry))
309312
except ValidationError as e:
310313
if e.reason == ErrorReason.NULL_NAME:
311-
sanitized_entries.append("")
314+
if not sanitized_entries:
315+
sanitized_entries.append("")
312316
else:
313317
raise
314318
sanitized_path = path_separator.join(sanitized_entries)
@@ -326,7 +330,7 @@ def sanitize(self, value, replacement_text=""):
326330
def validate(self, value):
327331
self._validate_null_string(value)
328332

329-
value = os.path.splitdrive(value)[1]
333+
value = ntpath.splitdrive(value)[1]
330334
if not value:
331335
return
332336

test/test_filepath.py

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,7 @@ def test_exception_invalid_win_char(self, value, platform):
278278
for reserved_keyword, platform in product(
279279
WIN_RESERVED_FILE_NAMES, ["windows", "universal"]
280280
)
281+
if reserved_keyword not in [".", ".."]
281282
]
282283
+ [
283284
["/foo/abc/{}.txt".format(reserved_keyword), platform, ReservedNameError]
@@ -336,23 +337,23 @@ class Test_sanitize_filepath(object):
336337
@pytest.mark.parametrize(
337338
["platform", "value", "replace_text", "expected"],
338339
[
339-
["universal", "A" + c + "B", rep, "A" + rep + "B"]
340+
["universal", "AA" + c + "B", rep, "AA" + rep + "B"]
340341
for c, rep in product(SANITIZE_CHARS, REPLACE_TEXT_LIST)
341342
]
342343
+ [
343-
["universal", "A" + c + "B", rep, "A" + c + "B"]
344+
["universal", "AA" + c + "B", rep, "AA" + c + "B"]
344345
for c, rep in product(NOT_SANITIZE_CHARS, REPLACE_TEXT_LIST)
345346
]
346347
+ [
347348
["universal", "あ" + c + "い", rep, "あ" + c + "い"]
348349
for c, rep in product(NOT_SANITIZE_CHARS, REPLACE_TEXT_LIST)
349350
]
350351
+ [
351-
["linux", "A" + c + "B", rep, "A" + rep + "B"]
352+
["linux", "AA" + c + "B", rep, "AA" + rep + "B"]
352353
for c, rep in product(INVALID_PATH_CHARS + unprintable_ascii_chars, REPLACE_TEXT_LIST)
353354
]
354355
+ [
355-
["linux", "A" + c + "B", rep, "A" + c + "B"]
356+
["linux", "AA" + c + "B", rep, "AA" + c + "B"]
356357
for c, rep in product([":", "*", "?", '"', "<", ">", "|"], REPLACE_TEXT_LIST)
357358
],
358359
)
@@ -371,9 +372,16 @@ def test_normal_str(self, platform, value, replace_text, expected):
371372
platform,
372373
"/abc/{}_/xyz".format(reserved_keyword),
373374
]
374-
for reserved_keyword, platform in product(
375-
WIN_RESERVED_FILE_NAMES, ["windows", "universal"]
376-
)
375+
for reserved_keyword, platform in product(WIN_RESERVED_FILE_NAMES, ["universal"])
376+
if reserved_keyword not in [".", ".."]
377+
]
378+
+ [
379+
[
380+
"/abc/{}/xyz".format(reserved_keyword),
381+
platform,
382+
"/abc/{}/xyz".format(reserved_keyword),
383+
]
384+
for reserved_keyword, platform in product(WIN_RESERVED_FILE_NAMES, ["linux"])
377385
if reserved_keyword not in [".", ".."]
378386
]
379387
+ [
@@ -382,9 +390,34 @@ def test_normal_str(self, platform, value, replace_text, expected):
382390
platform,
383391
"/abc/{}_.txt".format(reserved_keyword),
384392
]
385-
for reserved_keyword, platform in product(
386-
WIN_RESERVED_FILE_NAMES, ["windows", "universal"]
387-
)
393+
for reserved_keyword, platform in product(WIN_RESERVED_FILE_NAMES, ["universal"])
394+
if reserved_keyword not in [".", ".."]
395+
]
396+
+ [
397+
[
398+
"/abc/{}.txt".format(reserved_keyword),
399+
platform,
400+
"/abc/{}.txt".format(reserved_keyword),
401+
]
402+
for reserved_keyword, platform in product(WIN_RESERVED_FILE_NAMES, ["linux"])
403+
if reserved_keyword not in [".", ".."]
404+
]
405+
+ [
406+
[
407+
"C:\\abc\\{}.txt".format(reserved_keyword),
408+
platform,
409+
"C:/abc/{}_.txt".format(reserved_keyword),
410+
]
411+
for reserved_keyword, platform in product(WIN_RESERVED_FILE_NAMES, ["universal"])
412+
if reserved_keyword not in [".", ".."]
413+
]
414+
+ [
415+
[
416+
"C:\\abc\\{}.txt".format(reserved_keyword),
417+
platform,
418+
"C:\\abc\\{}_.txt".format(reserved_keyword),
419+
]
420+
for reserved_keyword, platform in product(WIN_RESERVED_FILE_NAMES, ["windows"])
388421
if reserved_keyword not in [".", ".."]
389422
],
390423
)
@@ -397,11 +430,11 @@ def test_normal_reserved_name(self, value, test_platform, expected):
397430
@pytest.mark.parametrize(
398431
["value", "replace_text", "expected"],
399432
[
400-
[Path("A" + c + "B"), rep, Path("A" + rep + "B")]
433+
[Path("AA" + c + "B"), rep, Path("AA" + rep + "B")]
401434
for c, rep in product(SANITIZE_CHARS, REPLACE_TEXT_LIST)
402435
]
403436
+ [
404-
[Path("A" + c + "B"), rep, Path("A" + c + "B")]
437+
[Path("AA" + c + "B"), rep, Path("AA" + c + "B")]
405438
for c, rep in product(NOT_SANITIZE_CHARS, REPLACE_TEXT_LIST)
406439
]
407440
+ [

0 commit comments

Comments
 (0)