File: frigcal-products/unzipped/

  setup path/cwd context for all frozen scripts (part of the frigcal system)

For frozen apps/exes, fix module+resource visibility.  This configures
sys.path and the CWD as needed for the freeze tool used, to grant importers
access to these items.  This module is imported by most scripts frozen in
the frigcal package; it updates the global sys.path and CWD in-place.

In the frozen package, all command-line scripts are frozen executables without 
a ".py" extension, but otherwise work the same, and require no separate Python
install.  In the Mac app, running the app itself launches the frigcal GUI; 
on Windows an Linux, the launcher-GUI executable must be started directly.

The logic here was originally hashed out in PyEdit's file of the same name;
see that system's more-complex version for additional background details.

FORMER CAVEAT: an os.chdir(exedir) for PyInstaller apps was used to make the
empty __file__ dir portably map to the install dir in sys.argv[0] (instead of the
_MEIPASS temp unzip folder), but precluded using any relative paths in command
lines.  This isn't an issue in PyEdit or PyMailGUI (they have no or rare args),
but utilities in both frigcal and mergeall process file paths.  Omitting the
chdir almost works, but the launcher then couldn't find its icons, help, and
script if run from elsewhere via a command line (instead of clicked directly).

   FIXED: the chdir is no longer run; instead, clients call fetchMyInstallDir()
   to select the install path explicitly per deployment mode -- from __file __
   for source and Mac apps, and sys.argv[0] for PyInstaller exes.  The cwd is
   unchanged, so relative paths work in all frozen executables' command lines.

   Exception: both frigcal-launcher.pyw and manually os.chdir() to
   the install dir returned from fetchMyInstallDir() early, so they can access 
   their data relative to "." easily; neither has any command-line arguments.
   Ditto for and both chdir to the install
   dir to make relative calendar paths map to it, and have no pathname args. 

import sys, os
RunningOnMac     = sys.platform.startswith('darwin')
RunningOnWindows = sys.platform.startswith('win')
RunningOnLinux   = sys.platform.startswith('linux')

DEBUG = False
    print('file', __file__)           # this in _MEI* (parent's = '')
    print('argv', sys.argv[0])        # 'frigcal.exe' (+path if not in cwd)
    print('exec', sys.executable)     # 'C:\...\frigcal.exe' (abs of argv[0])
    print('path', sys.path)           # just 2 _MEI* temp unzip folder paths
    print('cwd ', os.getcwd())        # 'C:\...' frigcal.exe dir (iff clicked!)


# Set global import-path context
if hasattr(sys, 'frozen') and sys.frozen == 'macosx_app':
    # 1) Mac py2app app-bundle folder distribution
    # Frozen importer's bootloader is in's Content/MacOS dir.
    # Add '.' for importing config module in app's Content/Resources dir.
    # dirname(__file__) and cwd work for icons, UserGuide.html, scripts,
    # and imports: code is source files, run by the app's bundled Python.
    # Ok to use cwd here: py2app cds to the data dir by default anyhow. 
    sys.path.append(os.getcwd())    # for configs .py

elif hasattr(sys, 'frozen') and (RunningOnWindows or RunningOnLinux):
    # 2) Windows and Linux PyInstaller single-file executable distribution
    # Use exe's path (not temp _MEI*) for config module and all data items.
    # The config module cannot be in PyInstaller's auto-unzip Temp dir.
    # DROPPED os.chdir(): this made empty __file__ dir map to install dir,
    # but precluded any relative paths in cmdline args to frozen exes; see
    # fetchMyInstallDir() below for the later explicit-install-dir scheme.
    exepath = sys.argv[0]
    exedir  = os.path.dirname(os.path.abspath(exepath))
    sys.path.append(exedir)         # for configs .py import
    ##os.chdir(exedir)              # for extras => now call fetchMyInstallDir!
    # 3) Portable Source code distributions - no tweaking required
    # The src dir is on sys.path: no action required for imports.
    # Data will be located by dirname(__file__) and/or cwd.


def fetchMyInstallDir(__file__):     # not global __file__
    call this to fetch folder where extra items reside;
    use to access installed icons, help, readme, scripts;
    replaces former os.chdir() which precluded rel paths;
    the return value is always an absolute pathname;
    pass importer's __file__ to __file__ arg: for frozen
    Mac apps, this module's dir(__file__) is in a zipfile,
    and differs from the importer's dir(__file__); they're
    the same for source code, and unused for Win/Lin exes;
    if hasattr(sys, 'frozen') and (RunningOnWindows or RunningOnLinux):
        # PyInstaller executable: from sys.argv[0] = exe's dir;
        # __file__ dir is empty and cwd may be any user folder
        # if the importer is run from a command line elsewhere;
        exepath = sys.argv[0]
        exedir  = os.path.dirname(os.path.abspath(exepath))
        return exedir

        # Mac app bundle or source-code: from __file__ as usual;
        # cwd is anywhere: return importing file's install folder;
        # this mod's __file__ is *not* ok to use here for frozen
        # Mac apps: it's in a zipfile, not importer's Resources/;
        srcpath = __file__
        srcdir  = os.path.dirname(os.path.abspath(srcpath))
        return srcdir

[Home] Books Programs Blog Python Author Training Search Email ©M.Lutz