PyInstaller Bundles#
PyInstaller is a popular tool in the Python ecosystem used to convert Python applications into standalone executables. It’s beneficial when you want to distribute your Python code as a single package, making it easier for users who might not have Python or the required dependencies installed.
We provide an easy way to use PyInstaller to bundle
optimization applications for distribution with
all dependencies including solvers. You can bundle your optimization application using
python -m amplpy.bundle script_name.py where script_name.py is the main Python script of your application for distribution. In the dist folder you will find the bundled app ready to distribute to your users. This works on Windows, Linux, and macOS.
In case amplpy.bundle is not available, please upgrade amplpy to the latest version with python -m pip install amplpy --upgrade.
Quick Example#
Create and enable a new virtual environment.
$ python -m venv venv # Create a new virtual environment $ source venv/bin/activate # On Linux and macOS $ venvironment\Scripts\activate # On Windows
Note
The use of a clean virtual environment is important to reduce the dependencies included in the bundled app.
Install any dependencies you may need on the new virtual environment.
$ python -m pip install -r requirements.txt
Install
amplpyand the solver modules you need.# Install Python API for AMPL $ python -m pip install amplpy --upgrade # Install solvers (e.g., HiGHS, Gurobi, COIN-OR) $ python -m amplpy.modules install highs gurobi coin
Create your main python script.
For instance
script_name.py:from amplpy import AMPL ampl = AMPL() ampl.eval(r""" param n integer > 0; # N-queens var Row {1..n} integer >= 1 <= n; s.t. row_attacks: alldiff ({j in 1..n} Row[j]); s.t. diag_attacks: alldiff ({j in 1..n} Row[j]+j); s.t. rdiag_attacks: alldiff ({j in 1..n} Row[j]-j); """) n = 10 ampl.param["n"] = n ampl.solve(solver="highs") solution = ampl.get_data("Row").to_dict() queens = set((int(r) - 1, int(c) - 1) for c, r in solution.items()) print("Solution") for r in range(n): print("".join([" Q " if (r, c) in queens else " + " for c in range(n)]))
Install PyInstaller.
python -m pip install pyinstaller
On Windows, we encountered issues with the latest version, but version 5.1 worked. You can install it with
python -m pip install pyinstaller==5.1. On Linux and macOS, the latest version worked without issues.Bundle your application.
python -m amplpy.bundle script_name.py ... Your executable is at ".../dist/script_name/script_name".
By default the license file will be excluded from the bundle. You can include the license file with:
python -m amplpy.bundle script_name.py --keep-license
Test your executable.
$ dist/script_name/script_name HiGHS 1.6.0: optimal solution 155 simplex iterations 1 branching nodes Objective = find a feasible point. Solution Q + + + + + + + + + + + + + + + + Q + + + + + + + Q + + + + + Q + + + + + + + + + + + + + + Q + + + + + + + + + + + + Q + + + Q + + + + + + + + + + + + + + Q + + + + + Q + + + + + + + Q + + + + + + +
Distribute your bundled application.
Distribute the folder
dist/script_name.
Licensing#
In most situations you will not want to include your own AMPL license in the bundle for distribution. There are two recommend ways of dealing with that:
a) Specify the location of the license file for instance in the user home directory:
Start your script with:
import os from amplpy import AMPL os.environ["AMPL_LICFILE"] = os.path.join(os.path.expanduser("~"), "ampl.lic") ...
The person using your bundled app will just need to have the
ampl.licfile in the home directory.b) Use an environment variable to pass the license UUID to the application:
Start your script with:
import os from amplpy import AMPL, modules modules.activate(os.environ["AMPLKEY_UUID"]) ...
The person using your bundled app will just need to set the environment variable
AMPLKEY_UUIDwith the license UUID to use.