diff --git a/test/test_utils.py b/test/test_utils.py index b3de14198e..8f81d0b1b7 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -249,17 +249,36 @@ def _test_sanitize_path(self): self.assertEqual(sanitize_path('abc/def...'), 'abc\\def..#') self.assertEqual(sanitize_path('abc.../def'), 'abc..#\\def') self.assertEqual(sanitize_path('abc.../def...'), 'abc..#\\def..#') - - self.assertEqual(sanitize_path('../abc'), '..\\abc') - self.assertEqual(sanitize_path('../../abc'), '..\\..\\abc') - self.assertEqual(sanitize_path('./abc'), 'abc') - self.assertEqual(sanitize_path('./../abc'), '..\\abc') - - self.assertEqual(sanitize_path('\\abc'), '\\abc') - self.assertEqual(sanitize_path('C:abc'), 'C:abc') - self.assertEqual(sanitize_path('C:abc\\..\\'), 'C:..') self.assertEqual(sanitize_path('C:\\abc:%(title)s.%(ext)s'), 'C:\\abc#%(title)s.%(ext)s') + # Check with nt._path_normpath if available + try: + import nt + + nt_path_normpath = getattr(nt, '_path_normpath', None) + except Exception: + nt_path_normpath = None + + for test, expected in [ + ('C:\\', 'C:\\'), + ('../abc', '..\\abc'), + ('../../abc', '..\\..\\abc'), + ('./abc', 'abc'), + ('./../abc', '..\\abc'), + ('\\abc', '\\abc'), + ('C:abc', 'C:abc'), + ('C:abc\\..\\', 'C:'), + ('C:abc\\..\\def\\..\\..\\', 'C:..'), + ('C:\\abc\\xyz///..\\def\\', 'C:\\abc\\def'), + ('abc/../', '.'), + ('./abc/../', '.'), + ]: + result = sanitize_path(test) + assert result == expected, f'{test} was incorrectly resolved' + assert result == sanitize_path(result), f'{test} changed after sanitizing again' + if nt_path_normpath: + assert result == nt_path_normpath(test), f'{test} does not match nt._path_normpath' + def test_sanitize_url(self): self.assertEqual(sanitize_url('//foo.bar'), 'http://foo.bar') self.assertEqual(sanitize_url('httpss://foo.bar'), 'https://foo.bar') diff --git a/yt_dlp/utils/_utils.py b/yt_dlp/utils/_utils.py index 699bf1e7f6..17d8424c47 100644 --- a/yt_dlp/utils/_utils.py +++ b/yt_dlp/utils/_utils.py @@ -685,7 +685,8 @@ def _sanitize_path_parts(parts): elif part == '..': if sanitized_parts and sanitized_parts[-1] != '..': sanitized_parts.pop() - sanitized_parts.append('..') + else: + sanitized_parts.append('..') continue # Replace invalid segments with `#` # - trailing dots and spaces (`asdf...` => `asdf..#`) @@ -702,7 +703,8 @@ def sanitize_path(s, force=False): if not force: return s root = '/' if s.startswith('/') else '' - return root + '/'.join(_sanitize_path_parts(s.split('/'))) + path = '/'.join(_sanitize_path_parts(s.split('/'))) + return root + path if root or path else '.' normed = s.replace('/', '\\') @@ -721,7 +723,8 @@ def sanitize_path(s, force=False): root = '\\' if normed[:1] == '\\' else '' parts = normed.split('\\') - return root + '\\'.join(_sanitize_path_parts(parts)) + path = '\\'.join(_sanitize_path_parts(parts)) + return root + path if root or path else '.' def sanitize_url(url, *, scheme='http'):