.. _packaging_pypi: ============================================ Packaging an Application from a PyPI Package ============================================ In this section, we'll show how to package the `pyflakes `_ program using a published PyPI package. (Pyflakes is a Python linter.) First, let's create an empty project:: $ pyoxidizer init-config-file pyflakes Next, we need to edit the :ref:`configuration file ` to tell PyOxidizer about pyflakes. Open the ``pyflakes/pyoxidizer.bzl`` file in your favorite editor. Find the ``make_exe()`` function. This function returns a :ref:`PythonExecutable ` instance which defines a standalone executable containing Python. This function is a registered *target*, which is a named entity that can be individually built or run. By returning a ``PythonExecutable`` instance, this function/target is saying *build an executable containing Python*. The ``PythonExecutable`` type holds all state needed to package and run a Python interpreter. This includes low-level interpreter configuration settings to which Python resources (like source and bytecode modules) are embedded in that executable binary. This type exposes an :ref:`add_in_memory_python_resources() ` method which adds an iterable of objects representing Python resources to the set of embedded resources. Elsewhere in this function, the ``dist`` variable holds an instance of :ref:`PythonDistribution `. This type represents a Python distribution, which is a fancy way of saying *an implementation of Python*. In addition to defining the files constituting that distribution, a ``PythonDistribution`` exposes methods for performing Python packaging. One of those methods is :ref:`pip_install() `, which invokes ``pip install`` using that Python distribution. To add a new Python package to our executable, we call ``dist.pip_install()`` then add the results to our ``PythonExecutable`` instance. This is done like so: .. code-block:: python exe.add_in_memory_python_resources(dist.pip_install(["pyflakes==2.1.1"])) The inner call to ``dist.pip_install()`` will effectively run ``pip install pyflakes==2.1.1`` and collect a set of installed Python resources (like module sources and bytecode data) and return that as an iterable data structure. The ``exe.add_in_memory_python_resources()`` call will then embed these resources in the built executable binary. Next, we tell PyOxidizer to run ``pyflakes`` when the interpreter is executed: .. code-block:: python run_eval="from pyflakes.api import main; main()", This says to effectively run the Python code ``eval(from pyflakes.api import main; main())`` when the embedded interpreter starts. The new ``make_exe()`` function should look something like the following (with comments removed for brevity): .. code-block:: python def make_exe(): dist = default_python_distribution() config = PythonInterpreterConfig( run_eval="from pyflakes.api import main; main()", ) exe = dist.to_python_executable( name="pyflakes", config=config, extension_module_filter="all", include_sources=True, include_resources=False, include_test=False, ) exe.add_in_memory_python_resources(dist.pip_install(["pyflakes==2.1.1"])) return exe With the configuration changes made, we can build and run a ``pyflakes`` native executable:: # From outside the ``pyflakes`` directory $ pyoxidizer run --path /path/to/pyflakes/project -- /path/to/python/file/to/analyze # From inside the ``pyflakes`` directory $ pyoxidizer run -- /path/to/python/file/to/analyze # Or if you prefer the Rust native tools $ cargo run -- /path/to/python/file/to/analyze By default, ``pyflakes`` analyzes Python source code passed to it via stdin.