Skip to main content

allow pip installable Python programs to be deployed as standalone applications (currently only on Microsoft Windows)

Project description

This project is still in its very early stages. This documentation is correspondingly rough and incomplete.

pydeploy is an experimental project to allow Python programs to be deployed as standalone applications (currently only on Microsoft Windows), provided they are written to be pip install-able by way of a pyproject.toml file.

Instead of using the PyInstaller approach, which is highly customized, pydeploy uses Python-native tooling and procedures. It uses the Python redistributable package to create a self-contained Python instance, and pip installs the needed files into it.

The end result should not cause antivirus systems to complain as it only uses the binaries already signed and redistributed with Python. You can further ensure this is the case by deploying your program with a .bat launcher instead of an .exe.

pydeploy has no dependencies other than the standard library.

Usage

1. Create a pip install-able project using pyproject.toml and the proper project layout

Basically, make your app into a pip-installable package using pyproject.toml. If you haven't learned how to do this yet, I highly recommend it. The examples directory will furnish some examples for how to do this for various kinds of programs.

Make a virtual environment for your project, and ideally use a src directory for your application code. You should also have a pyproject.toml file along these lines:

[project]
name = "myapp"
version = "0.1"

[build-system]
requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"

[project.scripts]
myproject = "myproject:main"

Note that the project.scripts section will be used by pydeploy to determine what .exe entry points to make. In this case, we will have a CLI entry point named myproject.exe in our deployable app directory.

Make sure your application works as a pip install-able project before you use pydeploy! Install your app into its own venv using the -e ("editable") flag, and test it that way.

If you want to copy data directories or other artifacts over to the target, see the section "Using the tool.pydeploy section of pyproject.toml to configure build behavior" below.

2. Install pydeploy into project venv

Use pip install pydeploy-win to install pydeploy.

You can also install directly from Github:

pip install git+https://github.com/syegulalp/pydeploy

3. Run pydeploy on your project

While in the project's root, type:

pydeploy .

(You can also use pd for short.)

If you want to supply an explicit path to a project:

pydeploy <project_dir>

This will analyze the pyproject.toml file and create a subdirectory named deploy_<version>, where <version> is the Python version for the currently active venv.

After the analysis and build process finishes you should have a dist subdirectory that contains your deployed project, along with a .zip archive of the project.

The resulting archive may be fairly large even for a simple "hello world" app, but I will introduce mechanisms in the future to make the deployed app less bulky by removing unused libraries.

Command line options

Pydeploy has a few command line switches, supplied along with the directory name for the project to build (the default is the current working directory):

  • -h: Print help.
  • -b: Create .bat launchers for the program rather than .exe files. This significantly reduces the chances of your package being flagged as malicious. Each entry point you define will have a separate .bat file associated with it. (NOTE: Read the "Tips" section ".bat entry points cannot use a function name" to understand how to use this correctly.)
  • -x: Does not build zip archives of the application files. Normally all Python files are packed into a zip file, but the original layout of Python files can be preserved with this option. Note that if pydeploy detects a mix of Python and other files in an app directory, it will fall back to this behavior for that app directory.
  • -s: Omit some of the larger and less commonly used standard library modules, which reduces the footprint of the redistributable. The variables remove_stdlib_for_smallify and remove_for_smallify list the libraries and modules in question. (This will eventually be replaced with a more fine-grained mechanism.)
  • -q: Don't show output from pip install, just the basic log info.

Including program assets

Many programs include data files that are not actually code -- for instance, a game with graphics and sound assets. Including these with your project is possible, but the best way to do this may requre you to slightly reorganize your project.

When you build a pydeploy project, you can create subdirectories that are immediate children of the program's current working directory:

your_program
    /libs # this contains the Python distribution
    /data # your program's data directory
    your_program.exe

This makes those directories easy to locate, as they are just children of the current working directory.

In your source repository, the best place for the data directory is in a subdirectory that mirrors its location, like this:

your_program_repo
    /src # your program data
    /data
    pyproject.toml

This keeps your data from being comingled with your program source.

Since you need to create an entry point to start your program, you can then launch the entry point in the root directory of your program's repository (the current working directory), and have the data directory also detected as a child of that current working directory.

To copy the data directory (or directories) to your deployement, you'll use data_dirs described in the next section.

You can see an example layout of a project that follows this pattern in the directory examples/pygame_asset.

Using the tool.pydeploy section of pyproject.toml to configure build behavior

You can configure some of Pydeploy's behaviors by adding a tool.pydeploy section to your pyproject.toml file.

[tool.pydeploy]
data_dirs = [["source_dir", "target_dir"]]
omit_files = ["libs/app/module/*.c", "libs/app/module/*.pyc"]

data_dirs

data_dirs is used to copy files from your source project tree, such as data files, into your distribution.

To use data_dirs, provide a list of two-item lists. The first item is the source directory in your project tree (with pyproject.toml as the root); the second item is the target directory with the executable directory as the root. (This is the directory that will by default be the current working directory when your app is launched.)

omit_files

omit_files is a list of glob patterns, starting from the root of the distribution directory. Files that match these patterns are removed from the distribution right before the .zip-archiving process. You can use this to remove things like build artfacts or other unwanted files from your shipped package. You can also use this to remove files from the runtime directory that aren't used in your program. E.g., if you don't use sqlite3 in your distribution, you can use *sqlite* to omit its files.

omit_from_stdlib

omit_from_stdlib is a list of glob patterns, starting from the root of the standard library .zip file. Files that match these patterns are removed from the standard library right before the .zip-archiving process. You can use this to remove standard library packages that aren't needed by your program, and do it more selectively than by using the -s switch.

Tips

Examples

The examples directory contains scaffolding examples for a few common project types -- a simple CLI, a windowed app using TKinter or Pygame, etc. This gallery will be expanded with time.

.bat entry points cannot use a function name, only a module

If you want to use a .bat launcher, and you have an entry point like this in your pyproject.toml, which specifies a function as well as a module:

[project.scripts]
shmup_c = "shmup.main:main"

.bat file launchers use python -m to launch the program, which can only accept a module name, not a module and a function name. shmup.main would be okay; shmup.main:main would not be.

To that end, ensure your entry point module runs your entry point function when executed directly:

# in shmup.main:
if __name__=="__main__":
    main()

The name of the module will be used automatically to construct the .bat launcher; it will simply truncate the name at the :.

Use an __init__.py in your application package's source directory

Some people encounter a problem where the editable install of their program works fine when they run it via the entry point, but the pydeploy-ed version crashes with an error like this:

Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "F:\Dev\myapp\deploy_3.13.5\dist\myapp.exe\__main__.py", line 4, in <module>
    from myapp.main import main
ModuleNotFoundError: No module named 'myapp'

To that end, if you don't have an __init__.py in the package's source root (e.g., /src/myapp), you need to add one. An empty one should work fine.

Todo

  • Support for including TKinter (not included with embedded redistributable)
  • Refactoring to allow each step to be executed separately, and allow the project to be used as a library with hooks for each step

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pydeploy_win-0.1.2.tar.gz (13.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pydeploy_win-0.1.2-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file pydeploy_win-0.1.2.tar.gz.

File metadata

  • Download URL: pydeploy_win-0.1.2.tar.gz
  • Upload date:
  • Size: 13.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pydeploy_win-0.1.2.tar.gz
Algorithm Hash digest
SHA256 5416899a6423756dca9b7662341147edd7fba9cdb39504f7747f0f0fecbb1063
MD5 8f30946e7ba620bc6aa7e40de0c65c30
BLAKE2b-256 00c974c9cc92eb785e8e9d4beb186787302d05fa86e604dc4bcb6fbb5840a4ee

See more details on using hashes here.

File details

Details for the file pydeploy_win-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: pydeploy_win-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 10.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for pydeploy_win-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 41f66ff7bee3089fa820e43f1a67f699c17723d8221617e18fc908770b728fea
MD5 1ca0fdbab2113506d34fdbee45075d43
BLAKE2b-256 78a22d398e5581f6f09b39ebbf09fc75954ee4eba21664709ed0ed8b0b90f894

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page