Repository: pyinstaller/pyinstaller

Issue:
[Win/Store] Python library not found
## Description of the issue

The python is from MS Store. The point is that I have already used venv, by `python -m venv .venv`.

## Context information (for bug reports)

* Output of `pyinstaller --version`: ```4.3```
* Version of Python: 3.9
* Platform: Windows 10 x64
* Did you also try this on another platform? No

### A minimal example program which shows the error

```
print("hello world")
```

### Stacktrace / full error message

```
(.venv) PS C:\py\pyinstaller-test> pyinstaller test.py
112 INFO: PyInstaller: 4.3
118 INFO: Python: 3.9.5
159 INFO: Platform: Windows-10-10.0.19043-SP0
160 INFO: wrote C:\py\pyinstaller-test\test.spec
239 INFO: UPX is available.
243 INFO: Extending PYTHONPATH with paths
['C:\\py\\pyinstaller-test', 'C:\\py\\pyinstaller-test']
254 INFO: checking Analysis
255 INFO: Building Analysis because Analysis-00.toc is non existent
255 INFO: Initializing module dependency graph...
259 INFO: Caching module graph hooks...
273 WARNING: Several hooks defined for module 'win32ctypes.core'. Please take care they do not conflict.
280 INFO: Analyzing base_library.zip ...
2898 INFO: Processing pre-find module path hook distutils from 'c:\\py\\pyinstaller-test\\.venv\\lib\\site-packages\\PyInstaller\\hooks\\pre_find_module_path\\hook-distutils.py'.
2900 INFO: distutils: retargeting to non-venv dir 'C:\\Program Files\\WindowsApps\\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\\lib'
5094 INFO: Caching module dependency graph...
5280 INFO: running Analysis Analysis-00.toc
5297 INFO: Adding Microsoft.Windows.Common-Controls to dependent assemblies of final executable
  required by c:\py\pyinstaller-test\.venv\scripts\python.exe
5302 INFO: Analyzing C:\py\pyinstaller-test\test.py
5314 INFO: Processing module hooks...
5314 INFO: Loading module hook 'hook-difflib.py' from 'c:\\py\\pyinstaller-test\\.venv\\lib\\site-packages\\PyInstaller\\hooks'...
5316 INFO: Loading module hook 'hook-distutils.py' from 'c:\\py\\pyinstaller-test\\.venv\\lib\\site-packages\\PyInstaller\\hooks'...
5317 INFO: Loading module hook 'hook-encodings.py' from 'c:\\py\\pyinstaller-test\\.venv\\lib\\site-packages\\PyInstaller\\hooks'...
5529 INFO: Loading module hook 'hook-heapq.py' from 'c:\\py\\pyinstaller-test\\.venv\\lib\\site-packages\\PyInstaller\\hooks'...
5531 INFO: Loading module hook 'hook-multiprocessing.util.py' from 'c:\\py\\pyinstaller-test\\.venv\\lib\\site-packages\\PyInstaller\\hooks'...
5532 INFO: Loading module hook 'hook-pickle.py' from 'c:\\py\\pyinstaller-test\\.venv\\lib\\site-packages\\PyInstaller\\hooks'...
5533 INFO: Loading module hook 'hook-sysconfig.py' from 'c:\\py\\pyinstaller-test\\.venv\\lib\\site-packages\\PyInstaller\\hooks'...
5534 INFO: Loading module hook 'hook-xml.py' from 'c:\\py\\pyinstaller-test\\.venv\\lib\\site-packages\\PyInstaller\\hooks'...
5728 INFO: Looking for ctypes DLLs
5745 INFO: Analyzing run-time hooks ...
5747 INFO: Including run-time hook 'c:\\py\\pyinstaller-test\\.venv\\lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py'   
5750 INFO: Looking for dynamic libraries
5758 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\_multiprocessing.pyd
5765 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\unicodedata.pyd
5780 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\select.pyd
5795 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\_socket.pyd
5843 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\_decimal.pyd
5867 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\_overlapped.pyd
5873 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\_ssl.pyd
5904 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\_queue.pyd
5912 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\pyexpat.pyd
5940 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\_asyncio.pyd
5950 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\_hashlib.pyd
5958 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\_lzma.pyd
5972 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\_bz2.pyd
5988 WARNING: lib not found: python39.dll dependency of C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\DLLs\_ctypes.pyd
6298 INFO: Looking for eggs
6298 INFO: Python library not in binary dependencies. Doing additional searching...
6298 WARNING: Can not get binary dependencies for file: C:\Users\xxx\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0\python.exe
6298 WARNING:   Reason: 'The file is empty'
Traceback (most recent call last):
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1520.0_x64__qbz5n2kfra8p0\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\py\pyinstaller-test\.venv\Scripts\pyinstaller.exe\__main__.py", line 7, in <module>
  File "c:\py\pyinstaller-test\.venv\lib\site-packages\PyInstaller\__main__.py", line 114, in run
    run_build(pyi_config, spec_file, **vars(args))
  File "c:\py\pyinstaller-test\.venv\lib\site-packages\PyInstaller\__main__.py", line 65, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
  File "c:\py\pyinstaller-test\.venv\lib\site-packages\PyInstaller\building\build_main.py", line 737, in main
    build(specfile, kw.get('distpath'), kw.get('workpath'), kw.get('clean_build'))
  File "c:\py\pyinstaller-test\.venv\lib\site-packages\PyInstaller\building\build_main.py", line 684, in build
    exec(code, spec_namespace)
  File "C:\py\pyinstaller-test\test.spec", line 7, in <module>
    a = Analysis(['test.py'],
  File "c:\py\pyinstaller-test\.venv\lib\site-packages\PyInstaller\building\build_main.py", line 242, in __init__
    self.__postinit__()
  File "c:\py\pyinstaller-test\.venv\lib\site-packages\PyInstaller\building\datastruct.py", line 160, in __postinit__
    self.assemble()
  File "c:\py\pyinstaller-test\.venv\lib\site-packages\PyInstaller\building\build_main.py", line 476, in assemble
    self._check_python_library(self.binaries)
  File "c:\py\pyinstaller-test\.venv\lib\site-packages\PyInstaller\building\build_main.py", line 581, in _check_python_library
    python_lib = bindepend.get_python_library_path()
  File "c:\py\pyinstaller-test\.venv\lib\site-packages\PyInstaller\depend\bindepend.py", line 956, in get_python_library_path
    raise IOError(msg)
OSError: Python library not found: python39.dll, libpython3.9m.dll, libpython39m.dll, libpython3.9.dll, libpython39.dll
    This would mean your Python installation doesn't come with proper library files.
    This usually happens by missing development package, or unsuitable build parameters of Python installation.

    * On Debian/Ubuntu, you would need to install Python development packages
      * apt-get install python3-dev
      * apt-get install python-dev
    * If you're building Python by yourself, please rebuild your Python with `--enable-shared` (or, `--enable-framework` on Darwin)
```




Discussion:
Is there a `Python39.dll` in the Windows store Python? If not then there is nothing PyInstaller (venv or no venv) can do to support it.
There is, but the problem is that `sys._base_executable` for some reason points to the empty shims in `%LOCALAPPDATA%\Microsoft\WindowsApps\PythonSoftware[...]` (hence the `6298 WARNING:   Reason: 'The file is empty'`) instead of actual executable in `%PROGRAMFILES%\WindowsApps\PythonSoftware[...]`.

But I think we can work around that...

Resolving patch:
diff --git a/PyInstaller/building/build_main.py b/PyInstaller/building/build_main.py
--- a/PyInstaller/building/build_main.py
+++ b/PyInstaller/building/build_main.py
@@ -360,7 +360,7 @@ def assemble(self):
 
         logger.info("running Analysis %s", self.tocbasename)
         # Get paths to Python and, in Windows, the manifest.
-        python = sys.executable
+        python = compat.python_executable
         if not is_win:
             # Linux/MacOS: get a real, non-link path to the running Python executable.
             while os.path.islink(python):
diff --git a/PyInstaller/compat.py b/PyInstaller/compat.py
--- a/PyInstaller/compat.py
+++ b/PyInstaller/compat.py
@@ -165,6 +165,21 @@
 # that the default non-conda behaviour is generally desired from PyInstaller.
 is_pure_conda = os.path.isdir(os.path.join(sys.prefix, 'conda-meta'))
 
+# Full path to python interpreter.
+python_executable = getattr(sys, '_base_executable', sys.executable)
+
+# Is this Python from Microsoft App Store (Windows only)?
+# Python from Microsoft App Store has executable pointing at empty shims.
+is_ms_app_store = is_win and os.path.getsize(python_executable) == 0
+
+if is_ms_app_store:
+    # Locate the actual executable inside base_prefix.
+    python_executable = os.path.join(
+        base_prefix, os.path.basename(python_executable))
+    if not os.path.exists(python_executable):
+        raise SystemExit('PyInstaller cannot locate real python executable '
+                         'belonging to Python from Microsoft App Store!')
+
 # In Python 3.4 module 'imp' is deprecated and there is another way how
 # to obtain magic value.
 import importlib.util
diff --git a/PyInstaller/depend/bindepend.py b/PyInstaller/depend/bindepend.py
--- a/PyInstaller/depend/bindepend.py
+++ b/PyInstaller/depend/bindepend.py
@@ -181,8 +181,8 @@ def matchDLLArch(filename):
     global _exe_machine_type
     try:
         if _exe_machine_type is None:
-            pefilename = sys.executable  # for exception handling
-            exe_pe = pefile.PE(sys.executable, fast_load=True)
+            pefilename = compat.python_executable  # for exception handling
+            exe_pe = pefile.PE(pefilename, fast_load=True)
             _exe_machine_type = exe_pe.FILE_HEADER.Machine
             exe_pe.close()
 
@@ -890,10 +890,18 @@ def _find_lib_in_libdirs(*libdirs):
                     return full_path
         return None
 
+    # If this is Microsoft App Store Python, check the compat.base_path first.
+    # While compat.python_executable resolves to actual python.exe file, the
+    # latter contains relative library reference that does not get properly
+    # resolved by getfullnameof().
+    if compat.is_ms_app_store:
+        python_libname = _find_lib_in_libdirs(compat.base_prefix)
+        if python_libname:
+            return python_libname
+
     # Try to get Python library name from the Python executable. It assumes that Python
     # library is not statically linked.
-    executable = getattr(sys, '_base_executable', sys.executable)
-    dlls = getImports(executable)
+    dlls = getImports(compat.python_executable)
     for filename in dlls:
         for name in PYDYLIB_NAMES:
             if os.path.basename(filename) == name:


Test patch: