def test_reading_manifest(tmpdir): """Check not using invalid encoding when reading XML manifest files Currently, Python 3.6.5, "open" built-in functions uses the encoding which locale.getpreferredencoding() returns. But generally, XML manifest files are written with UTF-8 even localized Windows. We check here not to use local encoding against UTF-8 manifest file. """ # This import only works on Windows. Place it here, protected by the # ``@skipif_notwin`` decorator. from PyInstaller.utils.win32 import winmanifest # We create the XML file written with UTF-8 as Microsoft tools do. tmppath = tmpdir.join('manifest.xml') with tmppath.open('wt', ensure=True, encoding='utf-8') as write_handle: write_handle.write(test_manifest_which_uses_non_ascii) # ... and check the following method always uses UTF-8. # It will read the file, reformat and overwrite it. winmanifest.create_manifest(str(tmppath), None, None)
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.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")) self.pkg = PKG( self.toc, cdict=kwargs.get('cdict', None), exclude_binaries=self.exclude_binaries, strip_binaries=self.strip, upx_binaries=self.upx, ) 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 __init__(self, *args, **kwargs): """ args One or more arguments that are either TOCs Targets. kwargs Possible keywork arguments: 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.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) # 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 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")) self.pkg = PKG(self.toc, cdict=kwargs.get('cdict', None), exclude_binaries=self.exclude_binaries, strip_binaries=self.strip, upx_binaries=self.upx, ) 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 __init__(self, *args, **kwargs): """ args One or more arguments that are either TOCs Targets. kwargs Possible keyword 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 for example a supervisor process signals both the bootloader and the child (e.g., via a process group) to avoid signalling the child twice. console On Windows or Mac OS 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 messages 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 and Mac OS 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. Use 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 would not attempt to write one from scratch). uac_admin Windows only. Setting to True creates a Manifest with will request elevation upon application start. uac_uiaccess Windows only. Setting to True allows an elevated application to work with Remote Desktop. embed_manifest Windows only. Setting to True (the default) embeds the manifest into the executable. Setting to False generates an external .exe.manifest file. Applicable only in onedir mode (exclude_binaries=True); in onefile mode (exclude_binaries=False), the manifest is always embedded in the executable, regardless of this option. 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.embed_manifest = kwargs.get('embed_manifest', True) 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) # Create the CArchive PKG in WORKPATH. When instancing PKG(), set name so that guts check can test whether the # file already exists. self.pkgname = os.path.join(CONF['workpath'], 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.exclude_binaries: # onefile mode forces embed_manifest=True if not self.embed_manifest: logger.warning("Ignoring embed_manifest=False setting in onefile mode!") self.embed_manifest = True if not self.icon: # --icon not specified; use default from bootloader folder if self.console: ico = 'icon-console.ico' else: ico = 'icon-windowed.ico' self.icon = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'bootloader', 'images', ico) 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" # If external manifest file is requested (supported only in onedir mode), add the file to the TOC in order # for it to be collected as an external manifest file. Otherwise, the assembly pipeline will embed the # manifest into the executable later on. if not self.embed_manifest: self.toc.append((manifest_filename, filename, 'BINARY')) 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, name=self.pkgname, 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__()