Skip to content

Commit 6cc5cff

Browse files
committed
Incorporate review comments
1 parent 56a8650 commit 6cc5cff

File tree

1 file changed

+45
-16
lines changed

1 file changed

+45
-16
lines changed

source/guides/windows-applications-embedding.rst

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ integrates much better with the operating system if the application is delivered
1717
as a native Windows executable. However, Python is not a natively compiled
1818
language, and so does not create executables by default.
1919

20-
The normal way around this issue is to make your Python code into a library, and
21-
declare one or more "script entry points" for the library. When the library is
22-
installed, the installer will generate a native executable which invokes the
23-
Python interpreter, calling your entry point function. This is a very effective
24-
solution, and is used by many Python applications. It is supported by utilities
25-
such as ``pipx`` and ``uv tool``, which make managing such entry points (and the
26-
virtual environments needed to support them) easy.
20+
One way around this issue is to make your Python code into a library, and
21+
declare one or more :ref:`script entry points <script-entry-points>` for the
22+
library. When the library is installed, the installer will provide an executable
23+
which invokes the Python interpreter, calling your entry point function. This is
24+
a very effective solution, and is used by many Python applications. It is
25+
supported by utilities such as ``pipx`` and ``uv tool``, which make managing
26+
such entry points (and the virtual environments needed to support them) easy.
2727

2828
There are, however, some downsides to this approach. The entry point wrapper
2929
results in a chain of processes being created - the wrapper itself, the virtual
@@ -90,10 +90,27 @@ need to do is make a small modification to the wrapper code.
9090
Your code can use 3rd party dependencies freely. These will be installed along
9191
with your application.
9292

93-
When you are ready to build your application, you can install the Python code
94-
using::
93+
You can create your application code in whatever way you prefer - there is no
94+
particular need to make it buildable as a wheel. For the purposes of this
95+
discussion, we will assume one of two project layouts:
9596

96-
pip install --target "<Application directory>\lib" MyAwesomePythonApp
97+
1. A project which can be installed via ``pip install``, with all of its
98+
dependencies listed in the ``pyproject.toml`` file, as normal.
99+
2. A Python application stored in a local directory. In this case, third party
100+
dependencies are listed in a ``requirements.txt`` file.
101+
102+
When you are ready to build your application, you need to copy all of the
103+
required code and dependencies into the ``lib`` directory of the application.
104+
For case (1), this can be done using::
105+
106+
pip install --target "<Application directory>\lib" .
107+
108+
For case (2), you should copy your application code into the ``lib`` directory
109+
and then run::
110+
111+
pip install --target "<Application directory>\lib" -r requirements.txt
112+
113+
to install the 3rd party dependencies.
97114

98115
You can then run your application as follows::
99116

@@ -154,6 +171,10 @@ application code should look like the following::
154171
/* Include the Python headers */
155172
#include <Python.h>
156173

174+
#define PYTHON_LOCATION L"interp"
175+
#define APP_MODULE "MyAwesomePythonApp"
176+
#define APP_FUNCTION "main"
177+
157178
/* Finding the Python interpreter */
158179
#include <windows.h>
159180
#include <pathcch.h>
@@ -188,7 +209,7 @@ application code should look like the following::
188209
* This MUST be called before any functions from the Python
189210
* runtime are called.
190211
*/
191-
if (!dll_dir(L"interp"))
212+
if (!dll_dir(PYTHON_LOCATION))
192213
return -1;
193214

194215
/* Initialise the Python configuration */
@@ -214,10 +235,10 @@ application code should look like the following::
214235
*/
215236

216237
int exitCode = -1;
217-
PyObject *module = PyImport_ImportModule("MyAwesomePythonApp");
238+
PyObject *module = PyImport_ImportModule(APP_MODULE);
218239
if (module) {
219240
// Pass any more arguments here
220-
PyObject *result = PyObject_CallMethod(module, "main", NULL);
241+
PyObject *result = PyObject_CallMethod(module, APP_FUNCTION, NULL);
221242
if (result) {
222243
exitCode = 0;
223244
Py_DECREF(result);
@@ -342,8 +363,16 @@ needs a GUI, the simplest option is likely to be to use one of the other GUI
342363
frameworks available from PyPI, such as PyQt or wxPython.
343364

344365
If your only option is tkinter, you will need to add a copy to the embedded
345-
distribution, or use a different distribution. Both of these options are outside
346-
the scope of this guide, however.
366+
distribution. You can get the relevant files from a full Python installation
367+
(which must be the same version as you're using for your application). The
368+
files you need are:
369+
370+
* ``_tkinter.pyd``, ``tcl*.dll``, ``tk*.dll`` and ``zlib1.dll`` from
371+
``{sys.prefix}\DLLs``
372+
* The ``tcl`` directory from ``{sys.prefix}``
373+
* The ``tkinter`` directory from ``{sys.prefix}\Lib``
374+
375+
You should copy all of these into your embedded interpreter directory.
347376

348377
Subprocesses and ``sys.executable``
349378
-----------------------------------
@@ -373,7 +402,7 @@ positive side, though, operating systems other than Windows have less need for
373402
this, as support for interpreted code as applications is generally better. In
374403
particular, on Unix a Python file with a "shebang" line is treated as a
375404
first-class application, and there is no benefit to making a native
376-
appliocation.
405+
application.
377406

378407
So while this discussion is specific to Windows, the problem it is solving is
379408
*also* unique to Windows.

0 commit comments

Comments
 (0)