def test_append_other_case_binary(): # binary files should use C-I comparisons. 'LiBrEADlInE.so.6' should not be added. toc = TOC(ELEMS1) toc.append(('LiBrEADlInE.so.6', '/lib64/libreadline.so.6', 'BINARY')) expected = list(ELEMS1) assert toc == expected
def __init__(self, *args, **kws): from PyInstaller.config import CONF # BUNDLE only has a sense under Mac OS X, it's a noop on other platforms if not is_darwin: return # get a path to a .icns icon for the app bundle. self.icon = kws.get('icon') if not self.icon: # --icon not specified; use the default in the pyinstaller folder self.icon = os.path.join( os.path.dirname(os.path.dirname(__file__)), 'bootloader', 'images', 'icon-windowed.icns') else: # user gave an --icon=path. If it is relative, make it # relative to the spec file location. if not os.path.isabs(self.icon): self.icon = os.path.join(CONF['specpath'], self.icon) # ensure icon path is absolute self.icon = os.path.abspath(self.icon) Target.__init__(self) # .app bundle is created in DISTPATH. self.name = kws.get('name', None) base_name = os.path.basename(self.name) self.name = os.path.join(CONF['distpath'], base_name) self.appname = os.path.splitext(base_name)[0] self.version = kws.get("version", "0.0.0") self.toc = TOC() self.strip = False self.upx = False self.console = True self.target_arch = None self.codesign_identity = None self.entitlements_file = None # .app bundle identifier for Code Signing self.bundle_identifier = kws.get('bundle_identifier') if not self.bundle_identifier: # Fallback to appname. self.bundle_identifier = self.appname self.info_plist = kws.get('info_plist', None) for arg in args: if isinstance(arg, EXE): self.toc.append( (os.path.basename(arg.name), arg.name, arg.typ)) self.toc.extend(arg.dependencies) self.strip = arg.strip self.upx = arg.upx self.upx_exclude = arg.upx_exclude self.console = arg.console self.target_arch = arg.target_arch self.codesign_identity = arg.codesign_identity self.entitlements_file = arg.entitlements_file elif isinstance(arg, TOC): self.toc.extend(arg) # TOC doesn't have a strip or upx attribute, so there is no way for us to # tell which cache we should draw from. elif isinstance(arg, COLLECT): self.toc.extend(arg.toc) self.strip = arg.strip_binaries self.upx = arg.upx_binaries self.upx_exclude = arg.upx_exclude self.console = arg.console self.target_arch = arg.target_arch self.codesign_identity = arg.codesign_identity self.entitlements_file = arg.entitlements_file else: logger.info("unsupported entry %s", arg.__class__.__name__) # Now, find values for app filepath (name), app name (appname), and name # of the actual executable (exename) from the first EXECUTABLE item in # toc, which might have come from a COLLECT too (not from an EXE). for inm, name, typ in self.toc: if typ == "EXECUTABLE": self.exename = name break self.__postinit__()
def __init__(self, *args, **kwargs): """ args One or more arguments that are either TOCs Targets. kwargs Possible keywork arguments: bootloader_ignore_signals Non-Windows only. If True, the bootloader process will ignore all ignorable signals. If False (default), it will forward all signals to the child process. Useful in situations where e.g. a supervisor process signals both the bootloader and child (e.g. via a process group) to avoid signalling the child twice. console On Windows or OSX governs whether to use the console executable or the windowed executable. Always True on Linux/Unix (always console executable - it does not matter there). debug Setting to True gives you progress mesages from the executable (for console=False there will be annoying MessageBoxes on Windows). name The filename for the executable. On Windows suffix '.exe' is appended. exclude_binaries Forwarded to the PKG the EXE builds. icon Windows or OSX only. icon='myicon.ico' to use an icon file or icon='notepad.exe,0' to grab an icon resource. version Windows only. version='myversion.txt'. Use grab_version.py to get a version resource from an executable and then edit the output to create your own. (The syntax of version resources is so arcane that I wouldn't attempt to write one from scratch). uac_admin Windows only. Setting to True creates a Manifest with will request elevation upon application restart uac_uiaccess Windows only. Setting to True allows an elevated application to work with Remote Desktop """ from ..config import CONF Target.__init__(self) # Available options for EXE in .spec files. self.exclude_binaries = kwargs.get('exclude_binaries', False) self.bootloader_ignore_signals = kwargs.get( 'bootloader_ignore_signals', False) self.console = kwargs.get('console', True) self.debug = kwargs.get('debug', False) self.name = kwargs.get('name', None) self.icon = kwargs.get('icon', None) self.versrsrc = kwargs.get('version', None) self.manifest = kwargs.get('manifest', None) self.resources = kwargs.get('resources', []) self.strip = kwargs.get('strip', False) self.upx_exclude = kwargs.get("upx_exclude", []) self.runtime_tmpdir = kwargs.get('runtime_tmpdir', None) # If ``append_pkg`` is false, the archive will not be appended # to the exe, but copied beside it. self.append_pkg = kwargs.get('append_pkg', True) # On Windows allows the exe to request admin privileges. self.uac_admin = kwargs.get('uac_admin', False) self.uac_uiaccess = kwargs.get('uac_uiaccess', False) if CONF['hasUPX']: self.upx = kwargs.get('upx', False) else: self.upx = False # Old .spec format included in 'name' the path where to put created # app. New format includes only exename. # # Ignore fullpath in the 'name' and prepend DISTPATH or WORKPATH. # DISTPATH - onefile # WORKPATH - onedir if self.exclude_binaries: # onedir mode - create executable in WORKPATH. self.name = os.path.join(CONF['workpath'], os.path.basename(self.name)) else: # onefile mode - create executable in DISTPATH. self.name = os.path.join(CONF['distpath'], os.path.basename(self.name)) # Old .spec format included on Windows in 'name' .exe suffix. if is_win or is_cygwin: # Append .exe suffix if it is not already there. if not self.name.endswith('.exe'): self.name += '.exe' base_name = os.path.splitext(os.path.basename(self.name))[0] else: base_name = os.path.basename(self.name) self.pkgname = base_name + '.pkg' self.toc = TOC() for arg in args: if isinstance(arg, TOC): self.toc.extend(arg) elif isinstance(arg, Target): self.toc.append((os.path.basename(arg.name), arg.name, arg.typ)) self.toc.extend(arg.dependencies) else: self.toc.extend(arg) if self.runtime_tmpdir is not None: self.toc.append(("pyi-runtime-tmpdir " + self.runtime_tmpdir, "", "OPTION")) if self.bootloader_ignore_signals: # no value; presence means "true" self.toc.append(("pyi-bootloader-ignore-signals", "", "OPTION")) if is_win: filename = os.path.join(CONF['workpath'], CONF['specnm'] + ".exe.manifest") self.manifest = winmanifest.create_manifest(filename, self.manifest, self.console, self.uac_admin, self.uac_uiaccess) manifest_filename = os.path.basename(self.name) + ".manifest" self.toc.append((manifest_filename, filename, 'BINARY')) if not self.exclude_binaries: # Onefile mode: manifest file is explicitly loaded. # Store name of manifest file as bootloader option. Allows # the exe to be renamed. self.toc.append(("pyi-windows-manifest-filename " + manifest_filename, "", "OPTION")) if self.versrsrc: if not os.path.isabs(self.versrsrc): # relative version-info path is relative to spec file self.versrsrc = os.path.join( CONF['specpath'], self.versrsrc) self.pkg = PKG(self.toc, cdict=kwargs.get('cdict', None), exclude_binaries=self.exclude_binaries, strip_binaries=self.strip, upx_binaries=self.upx, upx_exclude=self.upx_exclude ) self.dependencies = self.pkg.dependencies # Get the path of the bootloader and store it in a TOC, so it # can be checked for being changed. exe = self._bootloader_file('run', '.exe' if is_win or is_cygwin else '') self.exefiles = TOC([(os.path.basename(exe), exe, 'EXECUTABLE')]) self.__postinit__()
def test_extend(): toc = TOC(ELEMS1) toc.extend(ELEMS2) expected = list(ELEMS1) expected.extend(ELEMS2) assert toc == expected
def test_extend_existing(): toc = TOC(ELEMS1) toc.extend(ELEMS1) expected = list(ELEMS1) assert toc == expected
def test_insert_existing(): toc = TOC(ELEMS1) toc.insert(0, ELEMS1[-1]) toc.insert(1, ELEMS1[-1]) expected = list(ELEMS1) assert toc == expected
def test_insert_keep_filename(): # name in TOC should be the same as the one added toc = TOC() entry = ('EnCodIngs', '/usr/lib/python2.7/encodings.py', 'BINARY') toc.insert(1, entry) assert toc[0][0] == entry[0]
def test_append_existing(): toc = TOC(ELEMS1) toc.append(ELEMS1[-1]) expected = list(ELEMS1) assert toc == expected
def test_insert(): toc = TOC(ELEMS1) toc.insert(1, ('li-la-lu', '/home/myself/li-la-su', 'SOMETHING')) expected = list(ELEMS1) expected.insert(1, ('li-la-lu', '/home/myself/li-la-su', 'SOMETHING')) assert toc == expected
def test_append(): toc = TOC(ELEMS1) toc.append(('li-la-lu', '/home/myself/li-la-su', 'SOMETHING')) expected = list(ELEMS1) expected.append(('li-la-lu', '/home/myself/li-la-su', 'SOMETHING')) assert toc == expected
def test_init(): toc = TOC(ELEMS1) assert len(toc) == 3 assert toc == list(ELEMS1)
def test_init_empty(): toc = TOC() assert len(toc) == 0
def __init__(self, *args, **kwargs): """ args One or more arguments that are either TOCs Targets. kwargs Possible keywork arguments: bootloader_ignore_signals Non-Windows only. If True, the bootloader process will ignore all ignorable signals. If False (default), it will forward all signals to the child process. Useful in situations where e.g. a supervisor process signals both the bootloader and child (e.g. via a process group) to avoid signalling the child twice. console On Windows or OSX governs whether to use the console executable or the windowed executable. Always True on Linux/Unix (always console executable - it does not matter there). disable_windowed_traceback Disable traceback dump of unhandled exception in windowed (noconsole) mode (Windows and macOS only), and instead display a message that this feature is disabled. debug Setting to True gives you progress mesages from the executable (for console=False there will be annoying MessageBoxes on Windows). name The filename for the executable. On Windows suffix '.exe' is appended. exclude_binaries Forwarded to the PKG the EXE builds. icon Windows or OSX only. icon='myicon.ico' to use an icon file or icon='notepad.exe,0' to grab an icon resource. Defaults to use PyInstaller's console or windowed icon. icon=`NONE` to not add any icon. version Windows only. version='myversion.txt'. Use grab_version.py to get a version resource from an executable and then edit the output to create your own. (The syntax of version resources is so arcane that I wouldn't attempt to write one from scratch). uac_admin Windows only. Setting to True creates a Manifest with will request elevation upon application restart uac_uiaccess Windows only. Setting to True allows an elevated application to work with Remote Desktop target_arch macOS only. Used to explicitly specify the target architecture; either single-arch ('x86_64' or 'arm64') or 'universal2'. Used in checks that the collected binaries contain the requires arch slice(s) and/or to convert fat binaries into thin ones as necessary. If not specified (default), a single-arch build corresponding to running architecture is assumed. codesign_identity macOS only. Use the provided identity to sign collected binaries and the generated executable. If signing identity is not provided, ad-hoc signing is performed. entitlements_file macOS only. Optional path to entitlements file to use with code signing of collected binaries (--entitlements option to codesign utility). """ from PyInstaller.config import CONF Target.__init__(self) # Available options for EXE in .spec files. self.exclude_binaries = kwargs.get('exclude_binaries', False) self.bootloader_ignore_signals = kwargs.get( 'bootloader_ignore_signals', False) self.console = kwargs.get('console', True) self.disable_windowed_traceback = kwargs.get( 'disable_windowed_traceback', False) self.debug = kwargs.get('debug', False) self.name = kwargs.get('name', None) self.icon = kwargs.get('icon', None) self.versrsrc = kwargs.get('version', None) self.manifest = kwargs.get('manifest', None) self.resources = kwargs.get('resources', []) self.strip = kwargs.get('strip', False) self.upx_exclude = kwargs.get("upx_exclude", []) self.runtime_tmpdir = kwargs.get('runtime_tmpdir', None) # If ``append_pkg`` is false, the archive will not be appended # to the exe, but copied beside it. self.append_pkg = kwargs.get('append_pkg', True) # On Windows allows the exe to request admin privileges. self.uac_admin = kwargs.get('uac_admin', False) self.uac_uiaccess = kwargs.get('uac_uiaccess', False) # Target architecture (macOS only) self.target_arch = kwargs.get('target_arch', None) if is_darwin: if self.target_arch is None: import platform self.target_arch = platform.machine() else: assert self.target_arch in {'x86_64', 'arm64', 'universal2'}, \ f"Unsupported target arch: {self.target_arch}" logger.info("EXE target arch: %s", self.target_arch) else: self.target_arch = None # explicitly disable # Code signing identity (macOS only) self.codesign_identity = kwargs.get('codesign_identity', None) if is_darwin: logger.info("Code signing identity: %s", self.codesign_identity) else: self.codesign_identity = None # explicitly disable # Code signing entitlements self.entitlements_file = kwargs.get('entitlements_file', None) if CONF['hasUPX']: self.upx = kwargs.get('upx', False) else: self.upx = False # Old .spec format included in 'name' the path where to put created # app. New format includes only exename. # # Ignore fullpath in the 'name' and prepend DISTPATH or WORKPATH. # DISTPATH - onefile # WORKPATH - onedir if self.exclude_binaries: # onedir mode - create executable in WORKPATH. self.name = os.path.join(CONF['workpath'], os.path.basename(self.name)) else: # onefile mode - create executable in DISTPATH. self.name = os.path.join(CONF['distpath'], os.path.basename(self.name)) # Old .spec format included on Windows in 'name' .exe suffix. if is_win or is_cygwin: # Append .exe suffix if it is not already there. if not self.name.endswith('.exe'): self.name += '.exe' base_name = os.path.splitext(os.path.basename(self.name))[0] else: base_name = os.path.basename(self.name) self.pkgname = base_name + '.pkg' self.toc = TOC() for arg in args: if isinstance(arg, TOC): self.toc.extend(arg) elif isinstance(arg, Target): self.toc.append( (os.path.basename(arg.name), arg.name, arg.typ)) self.toc.extend(arg.dependencies) else: self.toc.extend(arg) if self.runtime_tmpdir is not None: self.toc.append( ("pyi-runtime-tmpdir " + self.runtime_tmpdir, "", "OPTION")) if self.bootloader_ignore_signals: # no value; presence means "true" self.toc.append(("pyi-bootloader-ignore-signals", "", "OPTION")) if self.disable_windowed_traceback: # no value; presence means "true" self.toc.append(("pyi-disable-windowed-traceback", "", "OPTION")) if is_win: if not self.icon: # --icon not specified; use default from bootloader folder if self.console: icon = 'icon-console.ico' else: icon = 'icon-windowed.ico' self.icon = os.path.join( os.path.dirname(os.path.dirname(__file__)), 'bootloader', 'images', icon) filename = os.path.join(CONF['workpath'], CONF['specnm'] + ".exe.manifest") self.manifest = winmanifest.create_manifest( filename, self.manifest, self.console, self.uac_admin, self.uac_uiaccess) manifest_filename = os.path.basename(self.name) + ".manifest" self.toc.append((manifest_filename, filename, 'BINARY')) if not self.exclude_binaries: # Onefile mode: manifest file is explicitly loaded. # Store name of manifest file as bootloader option. Allows # the exe to be renamed. self.toc.append( ("pyi-windows-manifest-filename " + manifest_filename, "", "OPTION")) if self.versrsrc: if (not isinstance(self.versrsrc, versioninfo.VSVersionInfo) and not os.path.isabs(self.versrsrc)): # relative version-info path is relative to spec file self.versrsrc = os.path.join(CONF['specpath'], self.versrsrc) self.pkg = PKG(self.toc, cdict=kwargs.get('cdict', None), exclude_binaries=self.exclude_binaries, strip_binaries=self.strip, upx_binaries=self.upx, upx_exclude=self.upx_exclude, target_arch=self.target_arch, codesign_identity=self.codesign_identity, entitlements_file=self.entitlements_file) self.dependencies = self.pkg.dependencies # Get the path of the bootloader and store it in a TOC, so it # can be checked for being changed. exe = self._bootloader_file('run', '.exe' if is_win or is_cygwin else '') self.exefiles = TOC([(os.path.basename(exe), exe, 'EXECUTABLE')]) self.__postinit__()
def test_insert_other_case(): # should not be added if the filenames are the same on a case-insensitive system. toc = TOC(ELEMS1) toc.insert(1, ('EnCodIngs', '/usr/lib/python2.7/encodings.py', 'BINARY')) expected = list(ELEMS1) assert toc == expected