# PyInstaller plugin for Poetry
Easily create executable binaries from your `pyproject.toml` using [PyInstaller](https://pyinstaller.org).
## Features
* **Multiple distribution formats**
* **Single file** created in `dist` folder (executable archive)
* **Folder** created in `dist` folder (containing executable and libraries)
* **Bundled** executable in platform specific wheels as scripts
* Both single file & folder distribution type can be bundled in wheels
## Installation
To install `poetry-pyinstaller-plugin` run the following command:
```shell
poetry self add poetry-pyinstaller-plugin
# or
pipx inject poetry poetry-pyinstaller-plugin
```
If you are having troubles to install the plugin please refer to Poetry documentation: https://python-poetry.org/docs/plugins/#using-plugins
## Configuration
Are listed in this sections all options available to configure `poetry-pyinstaller-plugin` in your `pyproject.toml`
* `[tool.poetry-pyinstaller-plugin]`
* `version` (string)
* Version of PyInstaller to use during build
* Does not support version constraint
* `exclude-include` (boolean)
* Exclude poetry include. Default: `False`
* `pre-build` (string)
* Pre-build hook. `path.to.my.hook:pre-build-hook`
* `post-build` (string)
* Post-build hook. `path.to.my.hook:post-build-hook`
* `use-poetry-install` (boolean)
* The default mode `False` installs packages (including "*pyinstaller*", "*certifi*" & "*cffi*") to the actual
virtual environment by using internally pip. It will not use `poetry.lock` file, just the dependencies from the
`pyproject.toml` configuration file.
* When set to `True` the virtual environment should be completely installed by poetry including "*pyinstaller*"
and optional "*certifi*" & "*cffi*" (for custom certificates).\
This is done by adding them as dependencies to the `pyproject.toml` configuration file and run `poetry install`
before starting `poetry build` command. Recommendation is the usage of an separate dependency group for
pyinstaller.
* `scripts` (dictionary)
* Where key is the program name and value a path to script or a `PyInstallerTarget` spec
* Example: `prog-name = "my_package/script.py"`
* `certifi` (dictionary)
* `append` (list): List of certificates to include in `certifi.where()`
* `collect` (dictionary)
* `submodules` (list): Collect all submodules for specified package(s) or module(s)
* `data` (list): Collect all data for specified package(s) or module(s)
* `binaries` (list): Collect all binaries for specified package(s) or module(s)
* `all` (list): Collect all submodules, data files, and binaries for specified package(s) or module(s)
* `copy-metadata` (list) : list of packages for which metadata must be copied
* `recursive-copy-metadata` (list) : list of packages for which metadata must be copied (including dependencies)
* `include` (dictionary) :
* Data file(s) to include. `{source: destination}`
* `package` (dictionary) :
* File(s) to include with executable. `{source: destination}`
`PyinstallerTarget` spec:
* `source` (string): Path to your program entrypoint
* `type` (string, **default:** `onedir`): Type of distribution format. Must be one of `onefile`, `onedir`
* `bundle` (boolean, **default:** `false`): Include executable binary onto wheel
* `noupx` (boolean, **default:** `false`) : Disable UPX archiving
* `strip` (boolean, **default** `false`) : Apply a symbol-table strip to the executable and shared libs (not recommended for Windows)
* `console` (boolean, **default** `false`) : Open a console window for standard i/o (default). On Windows this option has no effect if the first script is a ‘.pyw’ file.
* `windowed` (boolean, **default** `false`) : Windows and Mac OS X: do not provide a console window for standard i/o. On Mac OS this also triggers building a Mac OS .app bundle. On Windows this option is automatically set if the first script is a ‘.pyw’ file. This option is ignored on *NIX systems.
* `icon` (Path, **default** PyInstaller’s icon) : FILE.ico: apply the icon to a Windows executable. FILE.exe,ID: extract the icon with ID from an exe. FILE.icns: apply the icon to the .app bundle on Mac OS. Use “NONE” to not apply any icon, thereby making the OS to show some default
* `uac_admin` (boolean, **default** `false`) : Using this option creates a Manifest that will request elevation upon application start.
* `uac_uiaccess` (boolean, **default** `false`) : Using this option allows an elevated application to work with Remote Desktop.
* `argv_emulation` (boolean, **default** `false`) : Enable argv emulation for macOS app bundles. If enabled, the initial open document/URL event is processed by the bootloader and the passed file paths or URLs are appended to sys.argv.
* `arch` (string, **default** `null`) : Target architecture (macOS only; valid values: x86_64, arm64, universal2).
* `hiddenimport` (string | list), **default** `null`) : Hidden imports needed by the program (eg PIL._tkinter_finder for customtkinter).
* `runtime_hooks` (List[str], **default** `null`): One or more runtime hook paths to bundle with the executable. These hooks are executed before any other code or module to set up special features of the runtime environment.
* `add_version` (bool, **default** `False`): Add `tool.poetry.version` to built executable (suffix)
* `when` (str, **default** `None`): Restrict build depending on package version. Possible values: `release`, `prerelease`. Target allways built when unset (default: `None`)
### Examples
```toml
[tool.poetry-pyinstaller-plugin]
# Pyinstaller version (Optional, latest if not set)
# Does not support version constraint (eg: ^6.4)
version = "6.7.0"
# Disable UPX compression
disable-upx = true
# Include metadata from selected packages (including dependencies)
recursive-copy-metadata = [
"requests"
]
# Include metadata from selected packages
copy-metadata = [
"boto3"
]
[tool.poetry-pyinstaller-plugin.scripts]
hello-world = "my_package/main.py"
# Equivalent to
hello-world = { source = "my_package/main.py", type = "onedir", bundle = false }
# Single file bundled in wheel
single-file-bundled = { source = "my_package/main.py", type = "onefile", bundle = true}
# Single file with package version in final executable name
hello-world = { source = "my_package/main.py", type = "onedir", add_version = true } # -> hello-world-X.X.X
# Restrict build on package version
hello-world = { source = "my_package/main.py", type = "onedir", when = "release" } # -> when tool.poetry.version == x.x.x
hello-world-internal = { source = "my_package/main.py", type = "onedir", when = "prerelease" } # -> when tool.poetry.version == x.x.x[a|b|rc]
# Folder bundled in wheel
folder-bundled = { source = "my_package/main.py", type = "onedir", bundle = true}
# Include a runtime hook
hook-example = { runtime_hooks = ['hooks/my_hook.py'], source = ... }
[tool.poetry-pyinstaller-plugin.certifi]
# Section dedicated to certifi, required if certificates must be included in certifi store
append = ['certs/my_cert.pem']
[tool.poetry-pyinstaller-plugin.collect]
# Collect all submodules, data files & binaries for 'package_A' and 'package_B'
all = ['package_A', 'package_B']
```
## Usage
Once configured `poetry-pyinstaller-plugin` is attached to the `poetry build` command.
```text
$ poetry build
Building binaries with PyInstaller Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]
- Building hello-world DIRECTORY
- Built hello-world -> 'dist/pyinstaller/hello-world'
- Building single-file-bundled SINGLE_FILE BUNDLED
- Built single-file-bundled -> 'dist/pyinstaller/single-file-bundled'
- Building folder-bundled DIRECTORY BUNDLED
- Built folder-bundled -> 'dist/pyinstaller/folder-bundled'
Building my_package (0.0.0)
- Building sdist
- Built my_package-0.0.0.tar.gz
- Building wheel
- Built my_package-0.0.0-py3-none-any.whl
- Adding single-file-bundled to data scripts my_package-0.0.0-py3-none-any.whl
- Adding folder-bundled to data scripts my_package-0.0.0-py3-none-any.whl
Replacing platform in wheels (manylinux_2_35_x86_64)
- my_package-0.0.0-py3-none-manylinux_2_35_x86_64.whl
```
### Build verbosity settings
Logging verbosity during PyInstaller build phase is configured through `poetry build` command using `--verbose/-v` option.
Available levels:
* `-v` : Set `--log-level=WARN`
* `-vv` : Set `--log-level=INFO`
* `-vvv` : Set `--log-level=DEBUG` & `--debug=all`
#### Example:
```text
$ poetry build --format pyinstaller -v
Using virtualenv: /home/.../.cache/pypoetry/virtualenvs/one-file-rP3OcWW--py3.10
- Installing requests (>=2.32.3,<3.0.0)
Preparing PyInstaller 6.4.0 environment /home/.../.cache/pypoetry/virtualenvs/one-file-rP3OcWW--py3.10
Building binaries with PyInstaller Python 3.10 [manylinux_2_35_x86_64]
- Building one-file SINGLE_FILE
59 INFO: PyInstaller: 6.4.0, contrib hooks: 2024.7
59 INFO: Python: 3.10.12
60 INFO: Platform: Linux-6.5.0-41-generic-x86_64-with-glibc2.35
60 INFO: wrote dist/pyinstaller/manylinux_2_35_x86_64/.specs/one-file.spec
...
4009 INFO: Appending PKG archive to custom ELF section in EXE
4020 INFO: Building EXE from EXE-00.toc completed successfully.
- Built one-file -> 'dist/pyinstaller/manylinux_2_35_x86_64/one-file'
```
Expected directory structure:
```text
.
├── build ...................... PyInstaller intermediate build directory
│ ├── folder-bundled
│ ├── hello-world
│ └── single-file-bundled
├── dist ....................... Result of `poetry build` command
│ ├── pyinstaller ............. PyInstaller output
│ │ ├── .specs/ ............ Specs files
│ │ ├── hello-world/
│ │ ├── folder-bundled/
│ │ └── single-file-bundled
│ ├── my_package-0.0.0-py3-none-manylinux_2_35_x86_64.whl ... Wheel with bundled binaries
│ └── my_package-0.0.0.tar.gz ............................... Source archive, binaries are never included
├── pyproject.toml
└── my_package
├── __init__.py
└── main.py
```
## Dependencies notice
Major benefit of this plugin is to create dependency free wheels with executable binaries (including dependencies).
It is then recommended to include your dependencies as optional in your `pyproject.toml`
### Example
```toml
[tool.poetry]
name = "my-package"
[tool.poetry.dependencies]
python = "^3.8"
rich = {version = "^13.7.0", optional = true}
[tool.poetry.extras]
with-deps = ["rich"]
```
Resulting package will not require any dependency except if installed with extra `with-deps`.
```shell
# Installation without dependencies (included in executable binaries)
$ pip install my-package
# Installation with dependencies (If package imported as modules in another project)
$ pip install my-package[with-deps]
```
Bundled binaries must be built with all dependencies installed in build environment.
## Packaging additional files
This plugin by default supports `tool.poetry.include`, but it can be disabled
for more control. You can also add files *next* to the executable by using the
`package` setting
### Example
```toml
[tool.poetry]
name = "my_project"
include = [
{ path = "README.md", format = ["sdist"] },
]
[tool.poetry-pyinstaller-plugin]
# Disable [tool.poetry.include] and use plugin settings instead
exclude-include = true
[tool.poetry-pyinstaller-plugin.scripts]
hello-world = "my_package/main.py"
[tool.poetry-pyinstaller-plugin.package]
# 1-1 next to executable
"README.md" = "."
# renaming next to executable
"user/README.md" = "USER_README.md"
# directory next to executable
"docs" = "."
[tool.poetry-pyinstaller-plugin.include]
# loose files in bundle
"icons/*" = "."
# entire directory in bundle
"images/*" = "element_images"
```
Expected directory structure:
```text
.
├── build ...................... PyInstaller intermediate build directory
├── dist ....................... Result of `poetry build` command
│ ├── pyinstaller ............. PyInstaller output
│ │ ├── .specs/ ............ Specs files
│ │ └── hello-world/
│ │ ├── docs/ ............ Packaged Docs
│ │ │ ├── how_to.md
│ │ │ └── if_breaks.md
│ │ ├── my_project_internal/ ............ Onedir bundle
│ │ │ ├── main_icon.svg ............... Included icon
│ │ │ ├── extra_icon.svg .............. Included icon
│ │ │ └── element_images/ ............. Included images
│ │ │ ├── footer_icon.svg
│ │ │ └── header_icon.svg
│ │ ├── my_project.exe ............ Bundled program
│ │ ├── README.md ................. Packaged Readme
│ │ └── USER_README.md. ........... Packaged User Readme
│ ├── my_package-0.0.0-py3-none-manylinux_2_35_x86_64.whl ... Wheel with bundled binaries
│ └── my_package-0.0.0.tar.gz ............................... Source archive, includes README.md
├── docs/
│ ├── how_to.md
│ └── if_breaks.md
├── user/
│ └── README.md
├── icons/
│ ├── main_icon.svg
│ └── extra_icon.svg
├── images/
│ ├── footer_icon.md
│ └── header_icon.svg
├── pyproject.toml
├── README.py
└── my_package
├── __init__.py
└── main.py
```
## Hooks
The `pre-build` and `post-build` settings allow you to call a python function before and after the pyinstaller build. Each hook is passed a [hook interface](#hook_interface) class that allows access to Poetry, io and the virtual environment.
This lets you have further control in niche situations.
### Example
```toml
[tool.poetry]
name = "my_project"
[tool.poetry-pyinstaller-plugin]
# ran after requirements install and before builds
pre-build = "hooks.pyinstaller:post_build"
# ran after all builds are done
post-build = "hooks.pyinstaller:post_build"
[tool.poetry-pyinstaller-plugin.scripts]
hello-world = "my_package/main.py"
[tool.poetry-pyinstaller-plugin.package]
# package output from mkdocs
"site" = "docs"
```
<a name="hooks_pyinstaller"></a> **hooks/pyinstaller.py**:
```python
import shutil
from pathlib import Path
from typing import TYPE_CHECKING
def pre_build(interface) -> None:
"""
Pyinstaller pre build hook. Build local documentation.
"""
interface.write_line(" - <b>Building local docs</b>")
test_group = interface.poetry.package._dependency_groups["docs"] # noqa: SLF001
for req in test_group.dependencies:
pip_r = req.base_pep_508_name_resolved.replace(" (", "").replace(
")", ""
)
interface.write_line(f" - Installing <c1>{req}</c1>")
interface.run_pip(
"install",
"--disable-pip-version-check",
"--ignore-installed",
"--no-input",
pip_r,
)
interface.run("poetry", "run", "mkdocs", "build", "--no-directory-urls")
interface.write_line(" - <fg=green>Docs built</>")
def post_build(interface) -> None:
"""
Pyinstaller post build hook. Version built directory, remove generated folders.
"""
dist_path = Path("dist", "pyinstaller", interface.platform)
version = interface.pyproject_data["tool"]["poetry"]["version"]
interface.write_line(" - <b>Visioning built</b>")
for script in interface.pyproject_data["tool"]["poetry-pyinstaller-plugin"]["scripts"]:
source = Path(dist_path, script)
destination = Path(dist_path, f"{script}_{version}")
if destination.exists():
shutil.rmtree(destination) # remove existing
shutil.move(f"{source}", f"{destination}")
interface.write_line(
f" - Updated "
f"<success>{script}</success> -> "
f"<success>{script}_{version}</success>"
)
interface.write_line(" - <b>Cleaning</b>")
shutil.rmtree(Path("build"))
interface.write_line(" - Removed build directory")
shutil.rmtree(Path("site"))
interface.write_line(" - Removed site directory")
```
<details>
<summary><a name="hook_interface"></a>Hook Interface</summary>
Here are the attributes and functions for the hook interface class, see example [hook file](#hooks_pyinstaller) for basic usage.
> Note: If using linter(s), placing this class in a `TYPE_CHECKING` block will remove *most* errors.
```python
from typing import Dict, List, Any
class PyIntallerHookInterface:
"""
Pyinstaller hook interface
Attributes:
_io (IO): cleo.io.io IO instance
_venv (VirtualEnv): poetry.utils.env VirtualEnv instance
poetry (Poetry): poetry.poetry Poetry instance
pyproject_data (dict): pyproject.TOML contents
platform (str): platform string
"""
poetry: Any
pyproject_data: Dict
platform: str
def run(self, command: str, *args: str) -> None:
"""Run command in virtual environment"""
def run_pip(self, *args: str) -> None:
"""Install requirements in virtual environment"""
def write_line(self, output: str) -> None:
"""Output message with Poetry IO"""
```
</details>
Raw data
{
"_id": null,
"home_page": "https://github.com/thmahe/poetry-pyinstaller-plugin",
"name": "poetry-pyinstaller-plugin",
"maintainer": null,
"docs_url": null,
"requires_python": "<=3.13,>=3.8",
"maintainer_email": null,
"keywords": "poetry, plugin, pyinstaller, binary",
"author": "Thomas Mah\u00e9",
"author_email": "contact@tmahe.dev",
"download_url": "https://files.pythonhosted.org/packages/b8/92/ce26d071cfb82efdd29b44ecad2f488d7a51d1155e71e2085e7ecda9d774/poetry_pyinstaller_plugin-1.2.1.tar.gz",
"platform": null,
"description": "# PyInstaller plugin for Poetry\n\nEasily create executable binaries from your `pyproject.toml` using [PyInstaller](https://pyinstaller.org).\n\n## Features\n* **Multiple distribution formats**\n * **Single file** created in `dist` folder (executable archive)\n * **Folder** created in `dist` folder (containing executable and libraries)\n * **Bundled** executable in platform specific wheels as scripts\n * Both single file & folder distribution type can be bundled in wheels\n\n## Installation\n\nTo install `poetry-pyinstaller-plugin` run the following command:\n```shell\npoetry self add poetry-pyinstaller-plugin\n# or\npipx inject poetry poetry-pyinstaller-plugin\n```\n\nIf you are having troubles to install the plugin please refer to Poetry documentation: https://python-poetry.org/docs/plugins/#using-plugins\n\n## Configuration\n\nAre listed in this sections all options available to configure `poetry-pyinstaller-plugin` in your `pyproject.toml`\n\n* `[tool.poetry-pyinstaller-plugin]`\n * `version` (string) \n * Version of PyInstaller to use during build\n * Does not support version constraint\n * `exclude-include` (boolean) \n * Exclude poetry include. Default: `False`\n * `pre-build` (string)\n * Pre-build hook. `path.to.my.hook:pre-build-hook`\n * `post-build` (string)\n * Post-build hook. `path.to.my.hook:post-build-hook`\n * `use-poetry-install` (boolean) \n * The default mode `False` installs packages (including \"*pyinstaller*\", \"*certifi*\" & \"*cffi*\") to the actual\n virtual environment by using internally pip. It will not use `poetry.lock` file, just the dependencies from the\n `pyproject.toml` configuration file.\n * When set to `True` the virtual environment should be completely installed by poetry including \"*pyinstaller*\"\n and optional \"*certifi*\" & \"*cffi*\" (for custom certificates).\\\n This is done by adding them as dependencies to the `pyproject.toml` configuration file and run `poetry install`\n before starting `poetry build` command. Recommendation is the usage of an separate dependency group for\n pyinstaller.\n * `scripts` (dictionary) \n * Where key is the program name and value a path to script or a `PyInstallerTarget` spec\n * Example: `prog-name = \"my_package/script.py\"`\n * `certifi` (dictionary)\n * `append` (list): List of certificates to include in `certifi.where()`\n * `collect` (dictionary)\n * `submodules` (list): Collect all submodules for specified package(s) or module(s)\n * `data` (list): Collect all data for specified package(s) or module(s)\n * `binaries` (list): Collect all binaries for specified package(s) or module(s)\n * `all` (list): Collect all submodules, data files, and binaries for specified package(s) or module(s)\n * `copy-metadata` (list) : list of packages for which metadata must be copied\n * `recursive-copy-metadata` (list) : list of packages for which metadata must be copied (including dependencies)\n * `include` (dictionary) : \n * Data file(s) to include. `{source: destination}`\n * `package` (dictionary) : \n * File(s) to include with executable. `{source: destination}`\n\n`PyinstallerTarget` spec:\n* `source` (string): Path to your program entrypoint\n* `type` (string, **default:** `onedir`): Type of distribution format. Must be one of `onefile`, `onedir`\n* `bundle` (boolean, **default:** `false`): Include executable binary onto wheel\n* `noupx` (boolean, **default:** `false`) : Disable UPX archiving\n* `strip` (boolean, **default** `false`) : Apply a symbol-table strip to the executable and shared libs (not recommended for Windows)\n* `console` (boolean, **default** `false`) : Open a console window for standard i/o (default). On Windows this option has no effect if the first script is a \u2018.pyw\u2019 file.\n* `windowed` (boolean, **default** `false`) : Windows and Mac OS X: do not provide a console window for standard i/o. On Mac OS this also triggers building a Mac OS .app bundle. On Windows this option is automatically set if the first script is a \u2018.pyw\u2019 file. This option is ignored on *NIX systems.\n* `icon` (Path, **default** PyInstaller\u2019s icon) : FILE.ico: apply the icon to a Windows executable. FILE.exe,ID: extract the icon with ID from an exe. FILE.icns: apply the icon to the .app bundle on Mac OS. Use \u201cNONE\u201d to not apply any icon, thereby making the OS to show some default\n* `uac_admin` (boolean, **default** `false`) : Using this option creates a Manifest that will request elevation upon application start.\n* `uac_uiaccess` (boolean, **default** `false`) : Using this option allows an elevated application to work with Remote Desktop.\n* `argv_emulation` (boolean, **default** `false`) : Enable argv emulation for macOS app bundles. If enabled, the initial open document/URL event is processed by the bootloader and the passed file paths or URLs are appended to sys.argv.\n* `arch` (string, **default** `null`) : Target architecture (macOS only; valid values: x86_64, arm64, universal2).\n* `hiddenimport` (string | list), **default** `null`) : Hidden imports needed by the program (eg PIL._tkinter_finder for customtkinter).\n* `runtime_hooks` (List[str], **default** `null`): One or more runtime hook paths to bundle with the executable. These hooks are executed before any other code or module to set up special features of the runtime environment.\n* `add_version` (bool, **default** `False`): Add `tool.poetry.version` to built executable (suffix)\n* `when` (str, **default** `None`): Restrict build depending on package version. Possible values: `release`, `prerelease`. Target allways built when unset (default: `None`)\n\n### Examples\n\n```toml\n[tool.poetry-pyinstaller-plugin]\n# Pyinstaller version (Optional, latest if not set)\n# Does not support version constraint (eg: ^6.4)\nversion = \"6.7.0\"\n\n# Disable UPX compression\ndisable-upx = true\n\n# Include metadata from selected packages (including dependencies)\nrecursive-copy-metadata = [\n \"requests\"\n]\n\n# Include metadata from selected packages\ncopy-metadata = [\n \"boto3\"\n]\n\n[tool.poetry-pyinstaller-plugin.scripts]\nhello-world = \"my_package/main.py\"\n# Equivalent to\nhello-world = { source = \"my_package/main.py\", type = \"onedir\", bundle = false }\n\n# Single file bundled in wheel\nsingle-file-bundled = { source = \"my_package/main.py\", type = \"onefile\", bundle = true}\n\n# Single file with package version in final executable name\nhello-world = { source = \"my_package/main.py\", type = \"onedir\", add_version = true } # -> hello-world-X.X.X\n\n# Restrict build on package version\nhello-world = { source = \"my_package/main.py\", type = \"onedir\", when = \"release\" } # -> when tool.poetry.version == x.x.x\nhello-world-internal = { source = \"my_package/main.py\", type = \"onedir\", when = \"prerelease\" } # -> when tool.poetry.version == x.x.x[a|b|rc]\n\n# Folder bundled in wheel\nfolder-bundled = { source = \"my_package/main.py\", type = \"onedir\", bundle = true}\n\n# Include a runtime hook\nhook-example = { runtime_hooks = ['hooks/my_hook.py'], source = ... }\n\n[tool.poetry-pyinstaller-plugin.certifi]\n# Section dedicated to certifi, required if certificates must be included in certifi store\nappend = ['certs/my_cert.pem']\n\n[tool.poetry-pyinstaller-plugin.collect]\n# Collect all submodules, data files & binaries for 'package_A' and 'package_B'\nall = ['package_A', 'package_B']\n```\n\n## Usage\n\nOnce configured `poetry-pyinstaller-plugin` is attached to the `poetry build` command.\n```text\n$ poetry build\nBuilding binaries with PyInstaller Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]\n - Building hello-world DIRECTORY\n - Built hello-world -> 'dist/pyinstaller/hello-world'\n - Building single-file-bundled SINGLE_FILE BUNDLED\n - Built single-file-bundled -> 'dist/pyinstaller/single-file-bundled'\n - Building folder-bundled DIRECTORY BUNDLED\n - Built folder-bundled -> 'dist/pyinstaller/folder-bundled'\nBuilding my_package (0.0.0)\n - Building sdist\n - Built my_package-0.0.0.tar.gz\n - Building wheel\n - Built my_package-0.0.0-py3-none-any.whl\n - Adding single-file-bundled to data scripts my_package-0.0.0-py3-none-any.whl\n - Adding folder-bundled to data scripts my_package-0.0.0-py3-none-any.whl\nReplacing platform in wheels (manylinux_2_35_x86_64)\n - my_package-0.0.0-py3-none-manylinux_2_35_x86_64.whl\n```\n\n### Build verbosity settings\n\nLogging verbosity during PyInstaller build phase is configured through `poetry build` command using `--verbose/-v` option.\n\nAvailable levels:\n* `-v` : Set `--log-level=WARN`\n* `-vv` : Set `--log-level=INFO`\n* `-vvv` : Set `--log-level=DEBUG` & `--debug=all`\n#### Example:\n```text\n$ poetry build --format pyinstaller -v\nUsing virtualenv: /home/.../.cache/pypoetry/virtualenvs/one-file-rP3OcWW--py3.10\n - Installing requests (>=2.32.3,<3.0.0)\nPreparing PyInstaller 6.4.0 environment /home/.../.cache/pypoetry/virtualenvs/one-file-rP3OcWW--py3.10\nBuilding binaries with PyInstaller Python 3.10 [manylinux_2_35_x86_64]\n - Building one-file SINGLE_FILE\n 59 INFO: PyInstaller: 6.4.0, contrib hooks: 2024.7\n 59 INFO: Python: 3.10.12\n 60 INFO: Platform: Linux-6.5.0-41-generic-x86_64-with-glibc2.35\n 60 INFO: wrote dist/pyinstaller/manylinux_2_35_x86_64/.specs/one-file.spec\n ...\n 4009 INFO: Appending PKG archive to custom ELF section in EXE\n 4020 INFO: Building EXE from EXE-00.toc completed successfully.\n - Built one-file -> 'dist/pyinstaller/manylinux_2_35_x86_64/one-file'\n```\n\nExpected directory structure:\n```text\n.\n\u251c\u2500\u2500 build ...................... PyInstaller intermediate build directory\n\u2502 \u251c\u2500\u2500 folder-bundled\n\u2502 \u251c\u2500\u2500 hello-world\n\u2502 \u2514\u2500\u2500 single-file-bundled \n\u251c\u2500\u2500 dist ....................... Result of `poetry build` command\n\u2502 \u251c\u2500\u2500 pyinstaller ............. PyInstaller output\n\u2502 \u2502 \u251c\u2500\u2500 .specs/ ............ Specs files\n\u2502 \u2502 \u251c\u2500\u2500 hello-world/\n\u2502 \u2502 \u251c\u2500\u2500 folder-bundled/ \n\u2502 \u2502 \u2514\u2500\u2500 single-file-bundled\n\u2502 \u251c\u2500\u2500 my_package-0.0.0-py3-none-manylinux_2_35_x86_64.whl ... Wheel with bundled binaries\n\u2502 \u2514\u2500\u2500 my_package-0.0.0.tar.gz ............................... Source archive, binaries are never included\n\u251c\u2500\u2500 pyproject.toml\n\u2514\u2500\u2500 my_package\n \u251c\u2500\u2500 __init__.py\n \u2514\u2500\u2500 main.py\n```\n\n## Dependencies notice\n\nMajor benefit of this plugin is to create dependency free wheels with executable binaries (including dependencies).\n\nIt is then recommended to include your dependencies as optional in your `pyproject.toml`\n\n### Example\n```toml\n[tool.poetry]\nname = \"my-package\"\n\n[tool.poetry.dependencies]\npython = \"^3.8\"\nrich = {version = \"^13.7.0\", optional = true}\n\n[tool.poetry.extras]\nwith-deps = [\"rich\"]\n```\n\nResulting package will not require any dependency except if installed with extra `with-deps`.\n```shell\n# Installation without dependencies (included in executable binaries)\n$ pip install my-package\n\n# Installation with dependencies (If package imported as modules in another project)\n$ pip install my-package[with-deps] \n```\n\nBundled binaries must be built with all dependencies installed in build environment.\n\n## Packaging additional files\n\nThis plugin by default supports `tool.poetry.include`, but it can be disabled\nfor more control. You can also add files *next* to the executable by using the\n`package` setting\n\n### Example\n```toml\n[tool.poetry]\nname = \"my_project\"\ninclude = [\n { path = \"README.md\", format = [\"sdist\"] },\n]\n\n[tool.poetry-pyinstaller-plugin]\n# Disable [tool.poetry.include] and use plugin settings instead\nexclude-include = true\n\n[tool.poetry-pyinstaller-plugin.scripts]\nhello-world = \"my_package/main.py\"\n\n[tool.poetry-pyinstaller-plugin.package]\n# 1-1 next to executable\n\"README.md\" = \".\"\n\n# renaming next to executable\n\"user/README.md\" = \"USER_README.md\"\n\n# directory next to executable\n\"docs\" = \".\"\n\n[tool.poetry-pyinstaller-plugin.include]\n# loose files in bundle\n\"icons/*\" = \".\"\n\n# entire directory in bundle\n\"images/*\" = \"element_images\"\n```\n\nExpected directory structure:\n```text\n.\n\u251c\u2500\u2500 build ...................... PyInstaller intermediate build directory\n\u251c\u2500\u2500 dist ....................... Result of `poetry build` command\n\u2502 \u251c\u2500\u2500 pyinstaller ............. PyInstaller output\n\u2502 \u2502 \u251c\u2500\u2500 .specs/ ............ Specs files\n\u2502 \u2502 \u2514\u2500\u2500 hello-world/\n\u2502 \u2502 \u251c\u2500\u2500 docs/ ............ Packaged Docs\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 how_to.md\n\u2502 \u2502 \u2502 \u2514\u2500\u2500 if_breaks.md\n\u2502 \u2502 \u251c\u2500\u2500 my_project_internal/ ............ Onedir bundle\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 main_icon.svg ............... Included icon\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 extra_icon.svg .............. Included icon\n\u2502 \u2502 \u2502 \u2514\u2500\u2500 element_images/ ............. Included images\n\u2502 \u2502 \u2502 \u251c\u2500\u2500 footer_icon.svg\n\u2502 \u2502 \u2502 \u2514\u2500\u2500 header_icon.svg\n\u2502 \u2502 \u251c\u2500\u2500 my_project.exe ............ Bundled program\n\u2502 \u2502 \u251c\u2500\u2500 README.md ................. Packaged Readme\n\u2502 \u2502 \u2514\u2500\u2500 USER_README.md. ........... Packaged User Readme\n\u2502 \u251c\u2500\u2500 my_package-0.0.0-py3-none-manylinux_2_35_x86_64.whl ... Wheel with bundled binaries\n\u2502 \u2514\u2500\u2500 my_package-0.0.0.tar.gz ............................... Source archive, includes README.md\n\u251c\u2500\u2500 docs/\n\u2502 \u251c\u2500\u2500 how_to.md\n\u2502 \u2514\u2500\u2500 if_breaks.md\n\u251c\u2500\u2500 user/\n\u2502 \u2514\u2500\u2500 README.md\n\u251c\u2500\u2500 icons/\n\u2502 \u251c\u2500\u2500 main_icon.svg\n\u2502 \u2514\u2500\u2500 extra_icon.svg\n\u251c\u2500\u2500 images/\n\u2502 \u251c\u2500\u2500 footer_icon.md\n\u2502 \u2514\u2500\u2500 header_icon.svg\n\u251c\u2500\u2500 pyproject.toml\n\u251c\u2500\u2500 README.py\n\u2514\u2500\u2500 my_package\n \u251c\u2500\u2500 __init__.py\n \u2514\u2500\u2500 main.py\n```\n\n## Hooks\n\nThe `pre-build` and `post-build` settings allow you to call a python function before and after the pyinstaller build. Each hook is passed a [hook interface](#hook_interface) class that allows access to Poetry, io and the virtual environment.\n\nThis lets you have further control in niche situations.\n\n### Example\n```toml\n[tool.poetry]\nname = \"my_project\"\n\n[tool.poetry-pyinstaller-plugin]\n# ran after requirements install and before builds\npre-build = \"hooks.pyinstaller:post_build\"\n\n# ran after all builds are done\npost-build = \"hooks.pyinstaller:post_build\"\n\n[tool.poetry-pyinstaller-plugin.scripts]\nhello-world = \"my_package/main.py\"\n\n[tool.poetry-pyinstaller-plugin.package]\n# package output from mkdocs\n\"site\" = \"docs\"\n```\n\n<a name=\"hooks_pyinstaller\"></a> **hooks/pyinstaller.py**:\n```python\nimport shutil\nfrom pathlib import Path\nfrom typing import TYPE_CHECKING\n\ndef pre_build(interface) -> None:\n \"\"\"\n Pyinstaller pre build hook. Build local documentation.\n \"\"\"\n interface.write_line(\" - <b>Building local docs</b>\")\n\n test_group = interface.poetry.package._dependency_groups[\"docs\"] # noqa: SLF001\n for req in test_group.dependencies:\n pip_r = req.base_pep_508_name_resolved.replace(\" (\", \"\").replace(\n \")\", \"\"\n )\n interface.write_line(f\" - Installing <c1>{req}</c1>\")\n interface.run_pip(\n \"install\",\n \"--disable-pip-version-check\",\n \"--ignore-installed\",\n \"--no-input\",\n pip_r,\n )\n\n interface.run(\"poetry\", \"run\", \"mkdocs\", \"build\", \"--no-directory-urls\")\n interface.write_line(\" - <fg=green>Docs built</>\")\n\ndef post_build(interface) -> None:\n \"\"\"\n Pyinstaller post build hook. Version built directory, remove generated folders.\n \"\"\"\n dist_path = Path(\"dist\", \"pyinstaller\", interface.platform)\n version = interface.pyproject_data[\"tool\"][\"poetry\"][\"version\"]\n\n interface.write_line(\" - <b>Visioning built</b>\")\n for script in interface.pyproject_data[\"tool\"][\"poetry-pyinstaller-plugin\"][\"scripts\"]:\n source = Path(dist_path, script)\n destination = Path(dist_path, f\"{script}_{version}\")\n\n if destination.exists():\n shutil.rmtree(destination) # remove existing\n\n shutil.move(f\"{source}\", f\"{destination}\")\n interface.write_line(\n f\" - Updated \"\n f\"<success>{script}</success> -> \"\n f\"<success>{script}_{version}</success>\"\n )\n\n interface.write_line(\" - <b>Cleaning</b>\")\n shutil.rmtree(Path(\"build\"))\n interface.write_line(\" - Removed build directory\")\n shutil.rmtree(Path(\"site\"))\n interface.write_line(\" - Removed site directory\")\n```\n\n<details>\n\n<summary><a name=\"hook_interface\"></a>Hook Interface</summary>\n\nHere are the attributes and functions for the hook interface class, see example [hook file](#hooks_pyinstaller) for basic usage.\n\n> Note: If using linter(s), placing this class in a `TYPE_CHECKING` block will remove *most* errors.\n\n```python\nfrom typing import Dict, List, Any\n\nclass PyIntallerHookInterface:\n \"\"\"\n Pyinstaller hook interface\n\n Attributes:\n _io (IO): cleo.io.io IO instance\n _venv (VirtualEnv): poetry.utils.env VirtualEnv instance\n poetry (Poetry): poetry.poetry Poetry instance\n pyproject_data (dict): pyproject.TOML contents\n platform (str): platform string\n \"\"\"\n\n poetry: Any\n pyproject_data: Dict\n platform: str\n\n def run(self, command: str, *args: str) -> None:\n \"\"\"Run command in virtual environment\"\"\"\n\n def run_pip(self, *args: str) -> None:\n \"\"\"Install requirements in virtual environment\"\"\"\n\n def write_line(self, output: str) -> None:\n \"\"\"Output message with Poetry IO\"\"\"\n```\n\n</details>\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Poetry plugin to build and/or bundle executable binaries with PyInstaller",
"version": "1.2.1",
"project_urls": {
"Homepage": "https://github.com/thmahe/poetry-pyinstaller-plugin",
"Repository": "https://github.com/thmahe/poetry-pyinstaller-plugin"
},
"split_keywords": [
"poetry",
" plugin",
" pyinstaller",
" binary"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "3577cc39fb21be89692129910c882d8ae275be650fbf40cd793155b30cc8060a",
"md5": "7263c27a5979af15f89e104e87e408a7",
"sha256": "070318d1d92054f84c7fc58234fe68f68f3b2b0b5c954b24e77d97179a20b556"
},
"downloads": -1,
"filename": "poetry_pyinstaller_plugin-1.2.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "7263c27a5979af15f89e104e87e408a7",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<=3.13,>=3.8",
"size": 15595,
"upload_time": "2024-10-30T20:57:06",
"upload_time_iso_8601": "2024-10-30T20:57:06.075960Z",
"url": "https://files.pythonhosted.org/packages/35/77/cc39fb21be89692129910c882d8ae275be650fbf40cd793155b30cc8060a/poetry_pyinstaller_plugin-1.2.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "b892ce26d071cfb82efdd29b44ecad2f488d7a51d1155e71e2085e7ecda9d774",
"md5": "50e8ad90b985137d622ae5a592d4cd5e",
"sha256": "c88511ccc8c3497b57f773f5f3993cbb3f4858b48c270593416261dc816dd2bc"
},
"downloads": -1,
"filename": "poetry_pyinstaller_plugin-1.2.1.tar.gz",
"has_sig": false,
"md5_digest": "50e8ad90b985137d622ae5a592d4cd5e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<=3.13,>=3.8",
"size": 17821,
"upload_time": "2024-10-30T20:57:07",
"upload_time_iso_8601": "2024-10-30T20:57:07.022112Z",
"url": "https://files.pythonhosted.org/packages/b8/92/ce26d071cfb82efdd29b44ecad2f488d7a51d1155e71e2085e7ecda9d774/poetry_pyinstaller_plugin-1.2.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-10-30 20:57:07",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "thmahe",
"github_project": "poetry-pyinstaller-plugin",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "poetry-pyinstaller-plugin"
}