Repository: pyinstaller/pyinstaller

Issue:
FileNotFoundError running PyInstaller from flatpak-builder
<!--
Welcome to the PyInstaller issue tracker! Before creating an issue, please heed the following:

1. This tracker should only be used to report bugs and request features / enhancements to PyInstaller
    - For questions and general support, use the mailing list, see
	  <http://www.pyinstaller.org/support.html#mailing-list>
2. Use the search function before creating a new issue. Duplicates will be closed and directed to
   the original discussion.
3. When making a bug report, make sure you provide all required information. The easier it is for
   maintainers to reproduce, the faster it'll be fixed.
-->

<!-- +++ ONLY TEXT +++ DO NOT POST IMAGES +++ -->

## Description of the issue
I tried to find a good example of someone running PyInstaller from flatpak-builder but wasn't able to find one. If this is answered somewhere else, or should be asked of the Flatpak devs, my apologies.
When running PyInstaller from flatpak-builder I get the error: 
FileNotFoundError: [Errno 2] No such file or directory: '/app/lib/python3.9/site-packages/PyInstaller/loader/pyimod01_os_path.pyc'

### Context information (for bug reports)

* Output of `pyinstaller --version`: ```4.9```
* Version of Python: 3.9 in Flatpak 3.10 on Fedora 35
* Platform: Fedora 35 KDE Spin, flatpak-builder 1.2.2, org.kde.Platform 5.15-21.08
* How you installed Python: within flatpak-builder
* Did you also try this on another platform? Does it work there?
Works fine when built with just PyInstaller outside of flatpak-builder
On Ubuntu 21.04 within flatpak-builder error is:
FileNotFoundError: [Errno 2] No such file or directory: '/usr/lib/python3.9/struct.pyo'

### A minimal example program which shows the error
```
test.py:
import sys
import os

if __name__ == "__main__":
        print('hello')

test.spec:
# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(['test.py'],
             pathex=[],
             binaries=[],
             hiddenimports=[],
             hookspath=[],
             hooksconfig={},
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)

exe = EXE(pyz,
          a.scripts, 
          [],
          exclude_binaries=True,
          name='test',
          debug=False,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          console=False,
          disable_windowed_traceback=False,
          target_arch=None,
          codesign_identity=None,
          entitlements_file=None )
coll = COLLECT(exe,
               a.binaries,
               a.zipfiles,
               a.datas, 
               strip=False,
               upx=True,
               upx_exclude=[],
               name='test')

com.shernet.Test.yml:
app-id: com.shernet.Test
runtime: org.kde.Platform
runtime-version: '5.15-21.08'
sdk: org.kde.Sdk
command: test
modules:
  - python3-pyinstaller.json
  - name: test
    buildsystem: simple
    build-commands:
      - pyinstaller test.spec -y --distpath /app
    sources:
      - type: dir
        path: .

python3-pyinstaller.json:
{
    "name": "python3-pyinstaller",
    "buildsystem": "simple",
    "build-commands": [
        "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pyinstaller\" --no-build-isolation"
    ],
    "sources": [
        {
            "type": "file",
            "url": "https://files.pythonhosted.org/packages/84/3f/1a5c9bef54cac9bf41edd6f4aaf61cd52ed578e10ccc607e0278012cb4a5/altgraph-0.17.2-py2.py3-none-any.whl",
            "sha256": "743628f2ac6a7c26f5d9223c91ed8ecbba535f506f4b6f558885a8a56a105857"
        },
        {
            "type": "file",
            "url": "https://files.pythonhosted.org/packages/5e/25/cdd74d0e15b43e9ba6d6f5770474d8617514227ada1132ffb2f0f6bb1a63/pyinstaller_hooks_contrib-2022.2-py2.py3-none-any.whl",
            "sha256": "7605e440ccb55904cb2a87d72e83642ef176fb7030c77e52ac4d9679bb3d1537"
        },
        {
            "type": "file",
            "url": "https://files.pythonhosted.org/packages/47/88/cbc8ee5a300988e67f54f0366fd4d74a01f24caff75b5dd5139c0c6223f3/pyinstaller-4.9.tar.gz",
            "sha256": "75a180a658871bc41f9cf94b6f90ffa54e98f5d6a7cdb02d7530f0360afe24f9"
        }
    ]
}

Run:
flatpak-builder build-dir com.shernet.Test.yml --force-clean
```

### Stacktrace / full error message


```
Downloading sources
Starting build of com.shernet.WindsofParadise
Cache hit for python3-pyinstaller, skipping build
Cache hit for python3-requests, skipping build
Cache miss, checking out last cache hit
========================================================================
Building module windslauncher in /home/adam/Projects/windslauncher-python/.flatpak-builder/build/windslauncher-36
========================================================================
Running: pyinstaller windslauncher.spec -y --distpath /app
271 INFO: PyInstaller: 4.9
271 INFO: Python: 3.9.9
276 INFO: Platform: Linux-5.16.9-200.fc35.x86_64-x86_64-with-glibc2.33
279 INFO: UPX is not available.
280 INFO: Extending PYTHONPATH with paths
['/run/build/windslauncher']
548 INFO: checking Analysis
603 INFO: Building because pathex changed
603 INFO: Initializing module dependency graph...
605 INFO: Caching module graph hooks...
622 INFO: Analyzing base_library.zip ...
3005 INFO: Processing pre-find module path hook distutils from '/app/lib/python3.9/site-packages/PyInstaller/hooks/pre_find_module_path/hook-distutils.py'.
3005 INFO: distutils: retargeting to non-venv dir '/usr/lib/python3.9'
5298 INFO: Caching module dependency graph...
5414 INFO: running Analysis Analysis-00.toc
5434 INFO: Analyzing windslauncher.py
5493 INFO: Processing pre-safe import module hook urllib3.packages.six.moves from '/app/lib/python3.9/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-urllib3.packages.six.moves.py'.
6419 INFO: Processing module hooks...
6420 INFO: Loading module hook 'hook-certifi.py' from '/app/lib/python3.9/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks'...
6427 INFO: Loading module hook 'hook-encodings.py' from '/app/lib/python3.9/site-packages/PyInstaller/hooks'...
6475 INFO: Loading module hook 'hook-heapq.py' from '/app/lib/python3.9/site-packages/PyInstaller/hooks'...
6477 INFO: Loading module hook 'hook-sysconfig.py' from '/app/lib/python3.9/site-packages/PyInstaller/hooks'...
6504 INFO: Loading module hook 'hook-multiprocessing.util.py' from '/app/lib/python3.9/site-packages/PyInstaller/hooks'...
6505 INFO: Loading module hook 'hook-difflib.py' from '/app/lib/python3.9/site-packages/PyInstaller/hooks'...
6507 INFO: Loading module hook 'hook-distutils.py' from '/app/lib/python3.9/site-packages/PyInstaller/hooks'...
6507 INFO: Loading module hook 'hook-pickle.py' from '/app/lib/python3.9/site-packages/PyInstaller/hooks'...
6509 INFO: Loading module hook 'hook-xml.py' from '/app/lib/python3.9/site-packages/PyInstaller/hooks'...
6561 INFO: Looking for ctypes DLLs
6565 INFO: Analyzing run-time hooks ...
6568 INFO: Including run-time hook '/app/lib/python3.9/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py'
6571 INFO: Including run-time hook '/app/lib/python3.9/site-packages/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py'
6573 INFO: Including run-time hook '/app/lib/python3.9/site-packages/PyInstaller/hooks/rthooks/pyi_rth_inspect.py'
6574 INFO: Including run-time hook '/app/lib/python3.9/site-packages/PyInstaller/hooks/rthooks/pyi_rth_subprocess.py'
6581 INFO: Looking for dynamic libraries
7024 INFO: Looking for eggs
7024 INFO: Using Python library /usr/lib/x86_64-linux-gnu/libpython3.9.so.1.0
7028 INFO: Warnings written to /run/build/windslauncher/build/windslauncher/warn-windslauncher.txt
7062 INFO: Graph cross-reference written to /run/build/windslauncher/build/windslauncher/xref-windslauncher.html
7068 INFO: Appending 'datas' from .spec
Traceback (most recent call last):
  File "/app/bin/pyinstaller", line 8, in <module>
    sys.exit(run())
  File "/app/lib/python3.9/site-packages/PyInstaller/__main__.py", line 124, in run
    run_build(pyi_config, spec_file, **vars(args))
  File "/app/lib/python3.9/site-packages/PyInstaller/__main__.py", line 58, in run_build
    PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs)
  File "/app/lib/python3.9/site-packages/PyInstaller/building/build_main.py", line 793, in main
    build(specfile, kw.get('distpath'), kw.get('workpath'), kw.get('clean_build'))
  File "/app/lib/python3.9/site-packages/PyInstaller/building/build_main.py", line 725, in build
    exec(code, spec_namespace)
  File "windslauncher.spec", line 20, in <module>
    pyz = PYZ(a.pure, a.zipped_data,
  File "/app/lib/python3.9/site-packages/PyInstaller/building/api.py", line 94, in __init__
    self.dependencies = misc.compile_py_files(self.dependencies, CONF['workpath'])
  File "/app/lib/python3.9/site-packages/PyInstaller/utils/misc.py", line 157, in compile_py_files
    with open(obj_fnm, 'rb') as fh:
FileNotFoundError: [Errno 2] No such file or directory: '/app/lib/python3.9/site-packages/PyInstaller/loader/pyimod02_archive.pyc'
Error: module windslauncher: Child process exited with code 1


```



Discussion:
Ah yes, we're trying to open a non-existent file due to a faulty `needs_compile` check here:
https://github.com/pyinstaller/pyinstaller/blob/dc9daf8c519dde83917f4e0e53fc43535d290027/PyInstaller/utils/misc.py#L155

For some reason, the `st_mtime` of the `src_fnm` in the build environment is zero, and `obj_fnm` does not exist, so our `mtime()` wrapper also returns zero:

```
Running: python -c "import os; fnm='/app/lib/python3.9/site-packages/PyInstaller/loader/pyimod01_os_path.py'; print(os.stat(fnm))"
os.stat_result(st_mode=33188, st_ino=13, st_dev=56, st_nlink=2, st_uid=1000, st_gid=1000, st_size=3042, st_atime=1645736494, st_mtime=0, st_ctime=1645738146)
```

So to prevent issues like this, we ought to explicitly check if `obj_fnm` exists. And perhaps replace that `mtime` helper with `os.path.getmtime()`...

Resolving patch:
diff --git a/PyInstaller/utils/misc.py b/PyInstaller/utils/misc.py
--- a/PyInstaller/utils/misc.py
+++ b/PyInstaller/utils/misc.py
@@ -151,7 +151,7 @@ def compile_py_files(toc, workpath):
 
         # We need to perform a build ourselves if obj_fnm does not exist, or if src_fnm is newer than obj_fnm, or if
         # obj_fnm was created by a different Python version.
-        needs_compile = mtime(src_fnm) > mtime(obj_fnm)
+        needs_compile = not os.path.exists(obj_fnm) or mtime(src_fnm) > mtime(obj_fnm)
         if not needs_compile:
             with open(obj_fnm, 'rb') as fh:
                 needs_compile = fh.read(4) != BYTECODE_MAGIC
@@ -185,7 +185,7 @@ def compile_py_files(toc, workpath):
                     os.makedirs(leading)
 
                 obj_fnm = os.path.join(leading, mod_name + ext)
-                needs_compile = mtime(src_fnm) > mtime(obj_fnm)
+                needs_compile = not os.path.exists(obj_fnm) or mtime(src_fnm) > mtime(obj_fnm)
                 if not needs_compile:
                     with open(obj_fnm, 'rb') as fh:
                         needs_compile = fh.read(4) != BYTECODE_MAGIC


Test patch: