pythonwindowspyinstallermanifestmax-path

Enabling Windows long file path support in PyInstaller application


I am running into an issue with a script I've built into an executable using PyInstaller. The script works fine when run as a Python script, but when run as a PyInstaller application, it fails when it encounters a file whose path is longer than 260 characters.

I understand this is due to a limitation of Windows and support for longer paths must be opted into both in the registry and using an application manifest which enables the longPathAware setting. Incidentally, the reason this works in Python itself is because at Python 3.6 the developers enabled this setting for python.exe and pythonw.exe.

So far I've done all of this, and indeed it works if I place the following manifest file alongside the built PyInstaller application (using --onefile mode):

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
    </windowsSettings>
  </application>
</assembly>

However, to keep the application self-contained and portable for end users, I am trying to avoid having to use an external manifest file and instead get PyInstaller to embed this custom manifest into the executable.

The --manifest option purportedly does this -- at least since PyInstaller 3.5, per the changelog and PR #3746:

  • (Windows) Fix UAC in one-file mode by embedding the manifest. (#1729, #3746)

But when specified, the custom manifest file seems to be ignored, as the application continues to fail on long paths without the external manifest file in place, and inspecting the bundled manifest file in --onedir mode, it just looks like it's ignored the custom one and created this one instead:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <dependency>
    <dependentAssembly>
      <assemblyIdentity language="*" name="Microsoft.Windows.Common-Controls" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" type="win32" version="6.0.0.0"/>
      <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"/>
    </dependentAssembly>
  </dependency>
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
    </application>
  </compatibility>
</assembly>

Am I doing or understanding something wrong? Does the --manifest option not do what I am thinking it should? Is this a bug?

This answer describes modifying the PyInstaller source code to override the embedded manifest creation. Is this still necessary?

I also came across a project on GitHub that seems to be having the same problem; the author of this PR states:

Note that PyInstaller does not understand the longPathAware setting yet and strips it out of the manifest.

I don't know if that is true, but I think it does lend some weight to this being a bug.

I am using PyInstaller 3.6, Python 3.7.2, and Windows 10 version 1809.


Solution

  • This is now implemented in PyInstaller 4.2: https://pyinstaller.readthedocs.io/en/v4.2/CHANGES.html

    (Windows) Enable longPathAware option in built application’s manifest in order to support long file paths on Windows 10 v.1607 and later. (#5424)