5

Note: this question is about the newly supported win32 long paths (available since Windows 10 Version 1607, Build 14352) and not about extended UNC paths starting with \\?\.


I enabled long path support via a group policy and rebooted my PC. I checked in the registry that both HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\FileSystem\LongPathsEnabled and HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem\LongPathsEnabled are set to 1.

Then I opened a Python REPL and tried to create a directory that will exceed the 260-char limit, but failed:

>>> import os

>>> longdirname = 'a' * 300

>>> longdirname
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'

>>> os.makedirs(longdirname)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "c:\python27\lib\os.py", line 157, in makedirs
    mkdir(name, mode)
WindowsError: [Error 3] The system cannot find the path specified: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
[Error 3] The system cannot find the path specified: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'

I'm assuming that the long path support somehow didn't take effect here. Why is this and how can I properly enable it so that it works from Python scripts?


Update: I also tried directly calling a Win32 API function via pywin32 that claims in its documentation that it should support long paths, but failed again:

>>> import win32file

>>> longname = 'a' * 300

>>> win32file.CreateDirectoryW(longname, None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
error: (3, 'CreateDirectoryW', 'The system cannot find the path specified.')
(3, 'CreateDirectoryW', 'The system cannot find the path specified.')

Update 2: Also tried creating via individual components:

>>> for i in range(1, 300):
...     win32file.CreateDirectoryW('a', None)
...     os.chdir('a')
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
error: (206, 'CreateDirectoryW', 'The filename or extension is too long.')
(206, 'CreateDirectoryW', 'The filename or extension is too long.')

(os.makedirs also won't work in this case)


Update 3: The following batch script will not fail:

@echo off

setlocal enableextensions enabledelayedexpansion

pushd

set /a count = 1
for /L %%i in (1,1,300) do (
  mkdir a
  cd a
  echo %%i
)
endlocal

popd

So I'm assuming that this is somehow related to Python then.

Tamás Szelei
  • 23,169
  • 18
  • 105
  • 180

1 Answers1

3

The solution is both simple and somewhat disappointing: Python versions prior to 3.6 are not able to take advantage of long paths. 3.6 changelist.

Windows historically has limited path lengths to 260 characters. This meant that paths longer than this would not resolve and errors would result.

In the latest versions of Windows, this limitation can be expanded to approximately 32,000 characters. Your administrator will need to activate the “Enable Win32 long paths” group policy, or set the registry value HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem@LongPathsEnabled to 1.

This allows the open() function, the os module and most other path functionality to accept and return paths longer than 260 characters when using strings. (Use of bytes as paths is deprecated on Windows, and this feature is not available when using bytes.)

After changing the above option, no further configuration is required.

Changed in version 3.6: Support for long paths was enabled in Python.

To prove that it works, I did the following:

Python 3.6.2 (v3.6.2:5fd33b5, Jul  8 2017, 04:14:34) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> longdir = 'a' * 300
>>> os.makedirs(longdir)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\tamas\AppData\Local\Programs\Python\Python36-32\lib\os.py", line 220, in makedirs
    mkdir(name, mode)
OSError: [WinError 123] The filename, directory name, or volume label syntax is incorrect: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
>>> for i in range(1, 300):
...     os.mkdir('a')
...     os.chdir('a')
...
>>> len(os.getcwd())
631
>>>

The first makedirs call fails because individual components are still limited to 255 characters.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
Tamás Szelei
  • 23,169
  • 18
  • 105
  • 180
  • Apparently the docs need to be updated in this section. Bytes paths are no longer deprecated on Windows. 3.6 hard codes the Windows file-system encoding as UTF-8, and internally bytes paths are transcoded to UTF-16LE wide-character strings. – Eryk Sun Sep 29 '17 at 15:11
  • This was enabled in 3.6 by adding the `longPathAware` entry to the manifest. MSDN is not very clear that this feature has to be enabled both in the registry and the application manifest. – Eryk Sun Sep 29 '17 at 15:15
  • @eryksun, at one point I read that Windows didn't actually check the registry setting, only the manifest. Do you happen to know for sure whether or not the registry setting really is necessary? – Harry Johnston Sep 30 '17 at 00:19
  • @HarryJohnston, yes, both are required. The initialization of kernelbase.dll first calls `kernelbase!BasepIsProcessLongPathAwareByPolicy`, which checks the "LongPathsEnabled" registry setting. If it's enabled by policy, next it calls `kernelbase!BasepIsProcessLongPathAwareByManifest`, which checks the application manifest for the "longPathAware" setting. If the application is long-path aware, it enables the `IsLongPathAwareProcess` field in the PEB. – Eryk Sun Sep 30 '17 at 00:58
  • @eryksun, thanks. Hopefully the registry setting will be on by default in some future version of Windows 10. – Harry Johnston Sep 30 '17 at 02:05
  • Interesting, I got the impression from the docs that the manifest can be used to enable the feature per-app, and the registry key can be used to enable it globally. Quite fuzzy wording then if that's not the case. Thankfully this solved my problem and might be a helpful resource for future people who arrive here via Google. – Tamás Szelei Sep 30 '17 at 10:00