xref: /aosp_15_r20/external/pigweed/docs/python_build.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker=========================
4*61c4878aSAndroid Build Coastguard WorkerPigweed's GN Python Build
5*61c4878aSAndroid Build Coastguard Worker=========================
6*61c4878aSAndroid Build Coastguard Worker
7*61c4878aSAndroid Build Coastguard Worker.. seealso::
8*61c4878aSAndroid Build Coastguard Worker   - :bdg-ref-primary-line:`module-pw_build-python` for detailed template usage.
9*61c4878aSAndroid Build Coastguard Worker   - :bdg-ref-primary-line:`module-pw_build` for other GN templates available
10*61c4878aSAndroid Build Coastguard Worker     within Pigweed.
11*61c4878aSAndroid Build Coastguard Worker   - :bdg-ref-primary-line:`docs-build-system` for a high level guide and
12*61c4878aSAndroid Build Coastguard Worker     background information on Pigweed's build system as a whole.
13*61c4878aSAndroid Build Coastguard Worker
14*61c4878aSAndroid Build Coastguard WorkerPigweed uses a custom GN-based build system to manage its Python code. The
15*61c4878aSAndroid Build Coastguard WorkerPigweed Python build supports packaging, installation and distribution of
16*61c4878aSAndroid Build Coastguard Workerinterdependent local Python packages. It also provides for fast, incremental
17*61c4878aSAndroid Build Coastguard Workerstatic analysis and test running suitable for live use during development (e.g.
18*61c4878aSAndroid Build Coastguard Workerwith :ref:`module-pw_watch`) or in continuous integration.
19*61c4878aSAndroid Build Coastguard Worker
20*61c4878aSAndroid Build Coastguard WorkerPigweed's Python code is exclusively managed by GN, but the GN-based build may
21*61c4878aSAndroid Build Coastguard Workerbe used alongside CMake, Bazel, or any other build system. Pigweed's environment
22*61c4878aSAndroid Build Coastguard Workersetup uses GN to set up the initial Python environment, regardless of the final
23*61c4878aSAndroid Build Coastguard Workerbuild system. As needed, non-GN projects can declare just their Python packages
24*61c4878aSAndroid Build Coastguard Workerin GN.
25*61c4878aSAndroid Build Coastguard Worker
26*61c4878aSAndroid Build Coastguard WorkerHow it Works
27*61c4878aSAndroid Build Coastguard Worker============
28*61c4878aSAndroid Build Coastguard WorkerIn addition to compiler commands a Pigweed GN build will execute Python scripts
29*61c4878aSAndroid Build Coastguard Workerfor various reasons including running tests, linting code, generating protos and
30*61c4878aSAndroid Build Coastguard Workermore. All these scripts are run as part of a
31*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_build-pw_python_action` GN template which will ultimately run
32*61c4878aSAndroid Build Coastguard Worker``python``. Running Python on it's own by default will make any Python packages
33*61c4878aSAndroid Build Coastguard Workerinstalled on the users system available for importing. This is not good and can
34*61c4878aSAndroid Build Coastguard Workerlead to flaky builds when different packages are installed on each developer
35*61c4878aSAndroid Build Coastguard Workerworkstation. To get around this the Python community uses `virtual environments
36*61c4878aSAndroid Build Coastguard Worker<https://docs.python.org/3/library/venv.html>`_ (venvs) that expose a specific
37*61c4878aSAndroid Build Coastguard Workerset of Python packages separate from the host system.
38*61c4878aSAndroid Build Coastguard Worker
39*61c4878aSAndroid Build Coastguard WorkerWhen a Pigweed GN build starts a single venv is created for use by all
40*61c4878aSAndroid Build Coastguard Worker:ref:`pw_python_actions <module-pw_build-pw_python_action>` throughout the build
41*61c4878aSAndroid Build Coastguard Workergraph. Once created, all required third-party Python packages needed for the
42*61c4878aSAndroid Build Coastguard Workerproject are installed. At that point no further modifications are made to
43*61c4878aSAndroid Build Coastguard Workerthe venv. Of course if a new third-party package dependency is added it will be
44*61c4878aSAndroid Build Coastguard Workerinstalled too. Beyond that all venvs remain static. More venvs can be created
45*61c4878aSAndroid Build Coastguard Workerwith the :ref:`module-pw_build-pw_python_venv` template if desired, but only one
46*61c4878aSAndroid Build Coastguard Workeris used by default.
47*61c4878aSAndroid Build Coastguard Worker
48*61c4878aSAndroid Build Coastguard Worker.. card::
49*61c4878aSAndroid Build Coastguard Worker
50*61c4878aSAndroid Build Coastguard Worker   **Every pw_python_action is run inside a venv**
51*61c4878aSAndroid Build Coastguard Worker   ^^^
52*61c4878aSAndroid Build Coastguard Worker   .. mermaid::
53*61c4878aSAndroid Build Coastguard Worker      :caption:
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard Worker      flowchart LR
56*61c4878aSAndroid Build Coastguard Worker        out[GN Build Dir<br/>fa:fa-folder out]
57*61c4878aSAndroid Build Coastguard Worker
58*61c4878aSAndroid Build Coastguard Worker        out -->|ninja -C out| createvenvs
59*61c4878aSAndroid Build Coastguard Worker
60*61c4878aSAndroid Build Coastguard Worker        createvenvs(Create venvs)
61*61c4878aSAndroid Build Coastguard Worker        createvenvs --> pyactions1
62*61c4878aSAndroid Build Coastguard Worker        createvenvs --> pyactions2
63*61c4878aSAndroid Build Coastguard Worker
64*61c4878aSAndroid Build Coastguard Worker        subgraph pyactions1[Python venv 1]
65*61c4878aSAndroid Build Coastguard Worker          direction TB
66*61c4878aSAndroid Build Coastguard Worker          venv1(fa:fa-folder out/python-venv &nbsp)
67*61c4878aSAndroid Build Coastguard Worker          a1["pw_python_action('one')"]
68*61c4878aSAndroid Build Coastguard Worker          a2["pw_python_action('two')"]
69*61c4878aSAndroid Build Coastguard Worker          venv1 --> a1
70*61c4878aSAndroid Build Coastguard Worker          venv1 --> a2
71*61c4878aSAndroid Build Coastguard Worker        end
72*61c4878aSAndroid Build Coastguard Worker
73*61c4878aSAndroid Build Coastguard Worker        subgraph pyactions2[Python venv 2]
74*61c4878aSAndroid Build Coastguard Worker          direction TB
75*61c4878aSAndroid Build Coastguard Worker          venv2(fa:fa-folder out/another-venv &nbsp)
76*61c4878aSAndroid Build Coastguard Worker          a3["pw_python_action('three')"]
77*61c4878aSAndroid Build Coastguard Worker          a4["pw_python_action('four')"]
78*61c4878aSAndroid Build Coastguard Worker          venv2 --> a3
79*61c4878aSAndroid Build Coastguard Worker          venv2 --> a4
80*61c4878aSAndroid Build Coastguard Worker        end
81*61c4878aSAndroid Build Coastguard Worker
82*61c4878aSAndroid Build Coastguard Worker.. note::
83*61c4878aSAndroid Build Coastguard Worker
84*61c4878aSAndroid Build Coastguard Worker   Pigweed uses `this venv target
85*61c4878aSAndroid Build Coastguard Worker   <https://cs.opensource.google/pigweed/pigweed/+/main:pw_env_setup/BUILD.gn?q=pigweed_build_venv>`_
86*61c4878aSAndroid Build Coastguard Worker   if a project does not specify it's own build venv. See
87*61c4878aSAndroid Build Coastguard Worker   :bdg-ref-primary-line:`docs-python-build-python-gn-venv` on how to define
88*61c4878aSAndroid Build Coastguard Worker   your own default venv.
89*61c4878aSAndroid Build Coastguard Worker
90*61c4878aSAndroid Build Coastguard WorkerHaving a static venv containing only third-party dependencies opens the flood
91*61c4878aSAndroid Build Coastguard Workergates for python scripts to run. If the venv only contains third-party
92*61c4878aSAndroid Build Coastguard Workerdependencies you may be wondering how you can import your own in-tree Python
93*61c4878aSAndroid Build Coastguard Workerpackages. Python code run in the build may still import any in-tree Python
94*61c4878aSAndroid Build Coastguard Workerpackages created with :ref:`module-pw_build-pw_python_package`
95*61c4878aSAndroid Build Coastguard Workertemplates. However this only works if a correct ``python_deps`` arg is
96*61c4878aSAndroid Build Coastguard Workerprovided. Having that Python dependency defined in GN allows the
97*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_build-pw_python_action`
98*61c4878aSAndroid Build Coastguard Workerto set `PYTHONPATH
99*61c4878aSAndroid Build Coastguard Worker<https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH>`_ so that given
100*61c4878aSAndroid Build Coastguard Workerpackage can be imported. This has the benefit of the build failing if a
101*61c4878aSAndroid Build Coastguard Workerdependency for any Python action or package is missing.
102*61c4878aSAndroid Build Coastguard Worker
103*61c4878aSAndroid Build Coastguard Worker.. admonition:: Benefits of Python ``venvs`` in GN
104*61c4878aSAndroid Build Coastguard Worker   :class: important
105*61c4878aSAndroid Build Coastguard Worker
106*61c4878aSAndroid Build Coastguard Worker   - Using venvs to execute Python in GN provides reproducible builds with fixed
107*61c4878aSAndroid Build Coastguard Worker     third-party dependencies.
108*61c4878aSAndroid Build Coastguard Worker   - Using ``PYTHONPATH`` coupled with ``python_deps`` to import in-tree Python
109*61c4878aSAndroid Build Coastguard Worker     packages enforces dependency correctness.
110*61c4878aSAndroid Build Coastguard Worker
111*61c4878aSAndroid Build Coastguard Worker
112*61c4878aSAndroid Build Coastguard WorkerManaging Python Requirements
113*61c4878aSAndroid Build Coastguard Worker============================
114*61c4878aSAndroid Build Coastguard Worker
115*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build-python-gn-venv:
116*61c4878aSAndroid Build Coastguard Worker
117*61c4878aSAndroid Build Coastguard WorkerBuild Time Python Virtualenv
118*61c4878aSAndroid Build Coastguard Worker----------------------------
119*61c4878aSAndroid Build Coastguard WorkerPigweed's GN Python build infrastructure relies on `Python virtual environments
120*61c4878aSAndroid Build Coastguard Worker<https://docs.python.org/3/library/venv.html>`_ for executing Python code. This
121*61c4878aSAndroid Build Coastguard Workerprovides a controlled isolated environment with a defined set of third party
122*61c4878aSAndroid Build Coastguard WorkerPython constraints where all Python tests, linting and
123*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_build-pw_python_action` targets are executed.
124*61c4878aSAndroid Build Coastguard Worker
125*61c4878aSAndroid Build Coastguard WorkerThere must be at least one venv for Python defined in GN. There can be multiple
126*61c4878aSAndroid Build Coastguard Workervenvs but one must be the designated default.
127*61c4878aSAndroid Build Coastguard Worker
128*61c4878aSAndroid Build Coastguard WorkerThe default build venv is specified via a GN arg and is best set in the root
129*61c4878aSAndroid Build Coastguard Worker``.gn`` or ``BUILD.gn`` file. For example:
130*61c4878aSAndroid Build Coastguard Worker
131*61c4878aSAndroid Build Coastguard Worker.. code-block::
132*61c4878aSAndroid Build Coastguard Worker
133*61c4878aSAndroid Build Coastguard Worker   pw_build_PYTHON_BUILD_VENV = "//:project_build_venv"
134*61c4878aSAndroid Build Coastguard Worker
135*61c4878aSAndroid Build Coastguard Worker.. tip::
136*61c4878aSAndroid Build Coastguard Worker   Additional :ref:`module-pw_build-pw_python_venv` targets can be created as
137*61c4878aSAndroid Build Coastguard Worker   needed. The :ref:`module-pw_build-pw_python_action` template can take an
138*61c4878aSAndroid Build Coastguard Worker   optional ``venv`` argument to specify which Python venv it should run
139*61c4878aSAndroid Build Coastguard Worker   within. If not specified the target referred in the
140*61c4878aSAndroid Build Coastguard Worker   ``pw_build_PYTHON_BUILD_VENV`` is used.
141*61c4878aSAndroid Build Coastguard Worker
142*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build-python-gn-requirements-files:
143*61c4878aSAndroid Build Coastguard Worker
144*61c4878aSAndroid Build Coastguard WorkerThird-party Python Requirements and Constraints
145*61c4878aSAndroid Build Coastguard Worker-----------------------------------------------
146*61c4878aSAndroid Build Coastguard WorkerYour project may have third party Python dependencies you wish to install into
147*61c4878aSAndroid Build Coastguard Workerthe bootstrapped environment and in the GN build venv. There are two main ways
148*61c4878aSAndroid Build Coastguard Workerto add Python package dependencies:
149*61c4878aSAndroid Build Coastguard Worker
150*61c4878aSAndroid Build Coastguard Worker**Adding Requirements Files**
151*61c4878aSAndroid Build Coastguard Worker
152*61c4878aSAndroid Build Coastguard Worker1. Add a ``install_requires`` entry to a ``setup.cfg`` file defined in a
153*61c4878aSAndroid Build Coastguard Worker   :ref:`module-pw_build-pw_python_package` template. This is the best option
154*61c4878aSAndroid Build Coastguard Worker   if your in-tree Python package requires an external Python package.
155*61c4878aSAndroid Build Coastguard Worker
156*61c4878aSAndroid Build Coastguard Worker2. Create a standard Python ``requirements.txt`` file in your project and add it
157*61c4878aSAndroid Build Coastguard Worker   to the ``pw_build_PIP_REQUIREMENTS`` GN arg list.
158*61c4878aSAndroid Build Coastguard Worker
159*61c4878aSAndroid Build Coastguard Worker   Requirements files support a wide range of install locations including
160*61c4878aSAndroid Build Coastguard Worker   packages from pypi.org, the local file system and git repos. See `pip's
161*61c4878aSAndroid Build Coastguard Worker   Requirements File documentation
162*61c4878aSAndroid Build Coastguard Worker   <https://pip.pypa.io/en/stable/user_guide/#requirements-files>`_ for more
163*61c4878aSAndroid Build Coastguard Worker   info.
164*61c4878aSAndroid Build Coastguard Worker
165*61c4878aSAndroid Build Coastguard Worker   The GN arg can be set in your project's root ``.gn`` or ``BUILD.gn`` file.
166*61c4878aSAndroid Build Coastguard Worker
167*61c4878aSAndroid Build Coastguard Worker   .. code-block::
168*61c4878aSAndroid Build Coastguard Worker
169*61c4878aSAndroid Build Coastguard Worker      pw_build_PIP_REQUIREMENTS = [
170*61c4878aSAndroid Build Coastguard Worker        # Project specific requirements
171*61c4878aSAndroid Build Coastguard Worker        "//tools/requirements.txt",
172*61c4878aSAndroid Build Coastguard Worker      ]
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard Worker   See the :ref:`docs-python-build-python-gn-structure` section below for a full
175*61c4878aSAndroid Build Coastguard Worker   code listing.
176*61c4878aSAndroid Build Coastguard Worker
177*61c4878aSAndroid Build Coastguard Worker**Adding Constraints Files**
178*61c4878aSAndroid Build Coastguard Worker
179*61c4878aSAndroid Build Coastguard WorkerEvery project should ideally inherit Pigweed's third party Python package
180*61c4878aSAndroid Build Coastguard Workerversion. This is accomplished via `Python constraints files
181*61c4878aSAndroid Build Coastguard Worker<https://pip.pypa.io/en/stable/user_guide/#constraints-files>`_. Constraints
182*61c4878aSAndroid Build Coastguard Workercontrol which versions of packages get installed by ``pip`` if that package is
183*61c4878aSAndroid Build Coastguard Workerinstalled. To inherit Pigweed's Python constraints include ``constraint.list``
184*61c4878aSAndroid Build Coastguard Workerfrom the ``pw_env_setup`` module from in your top level ``.gn`` file. Additonal
185*61c4878aSAndroid Build Coastguard Workerproject specific constraints can be appended to this list.
186*61c4878aSAndroid Build Coastguard Worker
187*61c4878aSAndroid Build Coastguard Worker.. code-block::
188*61c4878aSAndroid Build Coastguard Worker
189*61c4878aSAndroid Build Coastguard Worker   pw_build_PIP_CONSTRAINTS = [
190*61c4878aSAndroid Build Coastguard Worker     "$dir_pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list",
191*61c4878aSAndroid Build Coastguard Worker     "//tools/constraints.txt",
192*61c4878aSAndroid Build Coastguard Worker   ]
193*61c4878aSAndroid Build Coastguard Worker
194*61c4878aSAndroid Build Coastguard WorkerIn-tree ``pw_python_package`` Requirements
195*61c4878aSAndroid Build Coastguard Worker------------------------------------------
196*61c4878aSAndroid Build Coastguard WorkerA given venv inherits a project's requirements and constraint files by default
197*61c4878aSAndroid Build Coastguard Workervia the ``pw_build_PIP_CONSTRAINTS`` and ``pw_build_PIP_REQUIREMENTS`` GN args
198*61c4878aSAndroid Build Coastguard Workeras described above. This can be overridden if needed.
199*61c4878aSAndroid Build Coastguard Worker
200*61c4878aSAndroid Build Coastguard Worker``generated_requirements.txt``
201*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
202*61c4878aSAndroid Build Coastguard WorkerTo ensure the requirements of in-tree :ref:`module-pw_build-pw_python_package`
203*61c4878aSAndroid Build Coastguard Workertargets are installed :ref:`module-pw_build-pw_python_venv` introduces the
204*61c4878aSAndroid Build Coastguard Worker``source_packages`` argument. This is a list of in-tree ``pw_python_package``
205*61c4878aSAndroid Build Coastguard WorkerGN targets expected to be used within the venv. When the venv is created each
206*61c4878aSAndroid Build Coastguard Worker``pw_python_package``'s ``setup.cfg`` file is read to pull the
207*61c4878aSAndroid Build Coastguard Worker``install_requires`` section for all third party dependencies. The full list of
208*61c4878aSAndroid Build Coastguard Workerall in-tree packages and any in-tree transitive dependencies is then written to
209*61c4878aSAndroid Build Coastguard Workerthe out directory in a single ``generated_requirements.txt``.
210*61c4878aSAndroid Build Coastguard Worker
211*61c4878aSAndroid Build Coastguard WorkerTake the ``//pw_build/py/gn_tests:downstream_tools_build_venv`` example below,
212*61c4878aSAndroid Build Coastguard Workerits ``source package`` is a single ``pw_python_distribution`` package which
213*61c4878aSAndroid Build Coastguard Workerbundles the ``pw_env_setup`` and ``pw_console`` ``pw_python_package``s. Those
214*61c4878aSAndroid Build Coastguard Workertwo packages each depend on a few other ``pw_python_package`` targets. The
215*61c4878aSAndroid Build Coastguard Workeroutput ``generated_requirements.txt`` below merges all these package deps and
216*61c4878aSAndroid Build Coastguard Workeradds ``-c`` lines for constraint files.
217*61c4878aSAndroid Build Coastguard Worker
218*61c4878aSAndroid Build Coastguard Worker.. seealso::
219*61c4878aSAndroid Build Coastguard Worker   The pip documentation on the `Requirements File Format
220*61c4878aSAndroid Build Coastguard Worker   <https://pip.pypa.io/en/stable/reference/requirements-file-format/#requirements-file-format>`_
221*61c4878aSAndroid Build Coastguard Worker
222*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: pw_build/py/gn_tests/BUILD.gn
223*61c4878aSAndroid Build Coastguard Worker   :start-after: [downstream-project-venv]
224*61c4878aSAndroid Build Coastguard Worker   :end-before: [downstream-project-venv]
225*61c4878aSAndroid Build Coastguard Worker
226*61c4878aSAndroid Build Coastguard Worker.. code-block::
227*61c4878aSAndroid Build Coastguard Worker   :caption: :octicon:`file;1em` out/python/gen/pw_build/py/gn_tests/downstream_tools_build_venv/generated_requirements.txt
228*61c4878aSAndroid Build Coastguard Worker   :name: generated_requirements
229*61c4878aSAndroid Build Coastguard Worker
230*61c4878aSAndroid Build Coastguard Worker   # Auto-generated requirements.txt from the following packages:
231*61c4878aSAndroid Build Coastguard Worker   #
232*61c4878aSAndroid Build Coastguard Worker   # //pw_arduino_build/py:py
233*61c4878aSAndroid Build Coastguard Worker   # //pw_build/py/gn_tests:downstream_project_tools
234*61c4878aSAndroid Build Coastguard Worker   # //pw_build/py:py
235*61c4878aSAndroid Build Coastguard Worker   # //pw_cli/py:py
236*61c4878aSAndroid Build Coastguard Worker   # //pw_console/py:py
237*61c4878aSAndroid Build Coastguard Worker   # //pw_env_setup/py:py
238*61c4878aSAndroid Build Coastguard Worker   # //pw_log_tokenized/py:py
239*61c4878aSAndroid Build Coastguard Worker   # //pw_package/py:py
240*61c4878aSAndroid Build Coastguard Worker   # //pw_presubmit/py:py
241*61c4878aSAndroid Build Coastguard Worker   # //pw_stm32cube_build/py:py
242*61c4878aSAndroid Build Coastguard Worker
243*61c4878aSAndroid Build Coastguard Worker   # Constraint files:
244*61c4878aSAndroid Build Coastguard Worker   -c ../../../../../../../pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list
245*61c4878aSAndroid Build Coastguard Worker
246*61c4878aSAndroid Build Coastguard Worker   black>=23.1.0
247*61c4878aSAndroid Build Coastguard Worker   build>=0.8.0
248*61c4878aSAndroid Build Coastguard Worker   coloredlogs
249*61c4878aSAndroid Build Coastguard Worker   coverage
250*61c4878aSAndroid Build Coastguard Worker   ipython
251*61c4878aSAndroid Build Coastguard Worker   jinja2
252*61c4878aSAndroid Build Coastguard Worker   mypy>=0.971
253*61c4878aSAndroid Build Coastguard Worker   parameterized
254*61c4878aSAndroid Build Coastguard Worker   pip-tools>=6.12.3
255*61c4878aSAndroid Build Coastguard Worker   prompt-toolkit>=3.0.26
256*61c4878aSAndroid Build Coastguard Worker   psutil
257*61c4878aSAndroid Build Coastguard Worker   ptpython>=3.0.20
258*61c4878aSAndroid Build Coastguard Worker   pygments
259*61c4878aSAndroid Build Coastguard Worker   pylint>=2.9.3
260*61c4878aSAndroid Build Coastguard Worker   pyperclip
261*61c4878aSAndroid Build Coastguard Worker   pyserial>=3.5,<4.0
262*61c4878aSAndroid Build Coastguard Worker   pyyaml
263*61c4878aSAndroid Build Coastguard Worker   setuptools
264*61c4878aSAndroid Build Coastguard Worker   six
265*61c4878aSAndroid Build Coastguard Worker   toml
266*61c4878aSAndroid Build Coastguard Worker   types-pygments
267*61c4878aSAndroid Build Coastguard Worker   types-pyserial>=3.5,<4.0
268*61c4878aSAndroid Build Coastguard Worker   types-pyyaml
269*61c4878aSAndroid Build Coastguard Worker   types-setuptools
270*61c4878aSAndroid Build Coastguard Worker   types-six
271*61c4878aSAndroid Build Coastguard Worker   websockets
272*61c4878aSAndroid Build Coastguard Worker   wheel
273*61c4878aSAndroid Build Coastguard Worker   yapf>=0.31.0
274*61c4878aSAndroid Build Coastguard Worker
275*61c4878aSAndroid Build Coastguard Worker``compiled_requirements.txt``
276*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
277*61c4878aSAndroid Build Coastguard WorkerThe above ``generated_requirements.txt`` file is then fed into the
278*61c4878aSAndroid Build Coastguard Worker``pip-compile`` command from `the pip-tools package
279*61c4878aSAndroid Build Coastguard Worker<https://pypi.org/project/pip-tools>`_ to fully expand and pin each package with
280*61c4878aSAndroid Build Coastguard Workerhashes. The resulting ``compiled_requirements.txt`` can then be used as the
281*61c4878aSAndroid Build Coastguard Workersingle Python requirements file for replicating this ``pw_python_venv``
282*61c4878aSAndroid Build Coastguard Workerelsewhere. Each ``pw_python_venv`` will get this single file containing the
283*61c4878aSAndroid Build Coastguard Workerexact versions of each required Python package.
284*61c4878aSAndroid Build Coastguard Worker
285*61c4878aSAndroid Build Coastguard Worker.. tip::
286*61c4878aSAndroid Build Coastguard Worker   The ``compiled_requirements.txt`` generated by a ``pw_python_venv`` is used
287*61c4878aSAndroid Build Coastguard Worker   by the :ref:`module-pw_build-pw_python_zip_with_setup` template when
288*61c4878aSAndroid Build Coastguard Worker   producing a self contained zip of in-tree and third party Python packages.
289*61c4878aSAndroid Build Coastguard Worker
290*61c4878aSAndroid Build Coastguard WorkerBelow is a snippet of the ``compiled_requirements.txt`` for this
291*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_build-pw_python_venv` target:
292*61c4878aSAndroid Build Coastguard Worker``//pw_build/py/gn_tests:downstream_tools_build_venv``
293*61c4878aSAndroid Build Coastguard Worker
294*61c4878aSAndroid Build Coastguard Worker.. code-block::
295*61c4878aSAndroid Build Coastguard Worker   :caption: :octicon:`file;1em` out/python/gen/pw_build/py/gn_tests/downstream_tools_build_venv/compiled_requirements.txt
296*61c4878aSAndroid Build Coastguard Worker   :name: compiled_requirements
297*61c4878aSAndroid Build Coastguard Worker
298*61c4878aSAndroid Build Coastguard Worker   #
299*61c4878aSAndroid Build Coastguard Worker   # This file is autogenerated by pip-compile with Python 3.11
300*61c4878aSAndroid Build Coastguard Worker   # by the following command:
301*61c4878aSAndroid Build Coastguard Worker   #
302*61c4878aSAndroid Build Coastguard Worker   #    pip-compile --allow-unsafe --generate-hashes
303*61c4878aSAndroid Build Coastguard Worker   #      --output-file=python/gen/pw_build/py/gn_tests/downstream_tools_build_venv/compiled_requirements.txt
304*61c4878aSAndroid Build Coastguard Worker   #      --resolver=backtracking
305*61c4878aSAndroid Build Coastguard Worker   #      python/gen/pw_build/py/gn_tests/downstream_tools_build_venv/generated_requirements.txt
306*61c4878aSAndroid Build Coastguard Worker   #
307*61c4878aSAndroid Build Coastguard Worker   appdirs==1.4.4 \
308*61c4878aSAndroid Build Coastguard Worker       --hash=sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41 \
309*61c4878aSAndroid Build Coastguard Worker       --hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128
310*61c4878aSAndroid Build Coastguard Worker       # via
311*61c4878aSAndroid Build Coastguard Worker       #   -c python/gen/pw_build/py/gn_tests/downstream_tools_build_venv/../../../../../../../pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list
312*61c4878aSAndroid Build Coastguard Worker       #   ptpython
313*61c4878aSAndroid Build Coastguard Worker   astroid==2.14.2 \
314*61c4878aSAndroid Build Coastguard Worker       --hash=sha256:0e0e3709d64fbffd3037e4ff403580550f14471fd3eaae9fa11cc9a5c7901153 \
315*61c4878aSAndroid Build Coastguard Worker       --hash=sha256:a3cf9f02c53dd259144a7e8f3ccd75d67c9a8c716ef183e0c1f291bc5d7bb3cf
316*61c4878aSAndroid Build Coastguard Worker       # via
317*61c4878aSAndroid Build Coastguard Worker       #   -c python/gen/pw_build/py/gn_tests/downstream_tools_build_venv/../../../../../../../pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list
318*61c4878aSAndroid Build Coastguard Worker       #   pylint
319*61c4878aSAndroid Build Coastguard Worker   ...
320*61c4878aSAndroid Build Coastguard Worker
321*61c4878aSAndroid Build Coastguard WorkerThe presence of hashes in the above example can be controlled via the
322*61c4878aSAndroid Build Coastguard Worker``pip_generate_hashes`` arg to the :ref:`module-pw_build-pw_python_venv`
323*61c4878aSAndroid Build Coastguard Workertemplate.
324*61c4878aSAndroid Build Coastguard Worker
325*61c4878aSAndroid Build Coastguard WorkerCaching Python Packages for Offline Installation
326*61c4878aSAndroid Build Coastguard Worker------------------------------------------------
327*61c4878aSAndroid Build Coastguard Worker
328*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build-downloading-packages:
329*61c4878aSAndroid Build Coastguard Worker
330*61c4878aSAndroid Build Coastguard WorkerDownloading Packages
331*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^
332*61c4878aSAndroid Build Coastguard WorkerThe :ref:`module-pw_build-pw_python_venv` target adds an optional sub target
333*61c4878aSAndroid Build Coastguard Workerthat will download all Python packages from remote servers into a local
334*61c4878aSAndroid Build Coastguard Workerdirectory. The remote server is typically `pypi.org <https://pypi.org/>`_.
335*61c4878aSAndroid Build Coastguard Worker
336*61c4878aSAndroid Build Coastguard WorkerTaking the ``//pw_build/py/gn_tests:downstream_tools_build_venv`` target as an
337*61c4878aSAndroid Build Coastguard Workerexample again let's build a local cache. To run the download target append
338*61c4878aSAndroid Build Coastguard Worker``.vendor_wheels`` to the end of the ``pw_python_venv`` target name. In this
339*61c4878aSAndroid Build Coastguard Workerexample it would be
340*61c4878aSAndroid Build Coastguard Worker``//pw_build/py/gn_tests:downstream_tools_build_venv.vendor_wheels``
341*61c4878aSAndroid Build Coastguard Worker
342*61c4878aSAndroid Build Coastguard WorkerTo build that one gn target with ninja, pass the output name from gn as a target
343*61c4878aSAndroid Build Coastguard Workername for ninja:
344*61c4878aSAndroid Build Coastguard Worker
345*61c4878aSAndroid Build Coastguard Worker.. code-block:: bash
346*61c4878aSAndroid Build Coastguard Worker
347*61c4878aSAndroid Build Coastguard Worker   gn gen out
348*61c4878aSAndroid Build Coastguard Worker   ninja -C out \
349*61c4878aSAndroid Build Coastguard Worker     $(gn ls out --as=output \
350*61c4878aSAndroid Build Coastguard Worker       '//pw_build/py/gn_tests:downstream_tools_build_venv.vendor_wheels')
351*61c4878aSAndroid Build Coastguard Worker
352*61c4878aSAndroid Build Coastguard WorkerThis creates a ``wheels`` folder with all downloaded packages and a
353*61c4878aSAndroid Build Coastguard Worker``pip_download_log.txt`` with verbose logs from running ``pip download``.
354*61c4878aSAndroid Build Coastguard Worker
355*61c4878aSAndroid Build Coastguard Worker.. code-block::
356*61c4878aSAndroid Build Coastguard Worker   :caption: :octicon:`file-directory;1em` Vendor wheels output directory
357*61c4878aSAndroid Build Coastguard Worker   :name: vendor-wheel-output
358*61c4878aSAndroid Build Coastguard Worker
359*61c4878aSAndroid Build Coastguard Worker   out/python/gen/pw_build/py/gn_tests/downstream_tools_build_venv.vendor_wheels/
360*61c4878aSAndroid Build Coastguard Worker   ├── pip_download_log.txt
361*61c4878aSAndroid Build Coastguard Worker   └── wheels
362*61c4878aSAndroid Build Coastguard Worker       ├── appdirs-1.4.4-py2.py3-none-any.whl
363*61c4878aSAndroid Build Coastguard Worker       ├── astroid-2.14.2-py3-none-any.whl
364*61c4878aSAndroid Build Coastguard Worker       ├── backcall-0.2.0-py2.py3-none-any.whl
365*61c4878aSAndroid Build Coastguard Worker       ├── black-23.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
366*61c4878aSAndroid Build Coastguard Worker       ├ ...
367*61c4878aSAndroid Build Coastguard Worker       ├── websockets-10.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
368*61c4878aSAndroid Build Coastguard Worker       ├── wheel-0.40.0-py3-none-any.whl
369*61c4878aSAndroid Build Coastguard Worker       ├── wrapt-1.14.1.tar.gz
370*61c4878aSAndroid Build Coastguard Worker       └── yapf-0.31.0-py2.py3-none-any.whl
371*61c4878aSAndroid Build Coastguard Worker
372*61c4878aSAndroid Build Coastguard WorkerNote the above output has both Python wheel ``.whl`` and source distribution
373*61c4878aSAndroid Build Coastguard Worker``.tar.gz`` files. The ``.whl`` may contain Python packages with precompiled C
374*61c4878aSAndroid Build Coastguard Workerextensions. This is denoted by this part of the filename:
375*61c4878aSAndroid Build Coastguard Worker``cp311-cp311-manylinux_2_17_x86_64.whl``. These binary packages are selected by
376*61c4878aSAndroid Build Coastguard Workerthe ``pip download`` command based on the host machine python version, OS, and
377*61c4878aSAndroid Build Coastguard WorkerCPU architecture.
378*61c4878aSAndroid Build Coastguard Worker
379*61c4878aSAndroid Build Coastguard Worker.. warning::
380*61c4878aSAndroid Build Coastguard Worker   If you need to cache Python packages for multiple platforms the
381*61c4878aSAndroid Build Coastguard Worker   ``.vendor_wheels`` target will need to be run for each combination of Python
382*61c4878aSAndroid Build Coastguard Worker   version, host operating system and architecture. For example, look at `the
383*61c4878aSAndroid Build Coastguard Worker   files available for numpy <https://pypi.org/project/cffi/#files>`_. Some
384*61c4878aSAndroid Build Coastguard Worker   combinations are:
385*61c4878aSAndroid Build Coastguard Worker
386*61c4878aSAndroid Build Coastguard Worker   - cp311, manylinux_2_17_x86_64
387*61c4878aSAndroid Build Coastguard Worker   - cp311, manylinux2014_x86_64
388*61c4878aSAndroid Build Coastguard Worker   - cp311, macosx_11_0_arm64
389*61c4878aSAndroid Build Coastguard Worker   - cp311, macosx_10_9_x86_64
390*61c4878aSAndroid Build Coastguard Worker   - cp311, win_amd64
391*61c4878aSAndroid Build Coastguard Worker   - cp311, win32
392*61c4878aSAndroid Build Coastguard Worker
393*61c4878aSAndroid Build Coastguard Worker   Plus all of the above duplicated for Python 3.10 and 3.9 (``cp310`` and
394*61c4878aSAndroid Build Coastguard Worker   ``cp39``).
395*61c4878aSAndroid Build Coastguard Worker
396*61c4878aSAndroid Build Coastguard Worker   The output of multiple ``.vendor_wheels`` runs on different host systems can
397*61c4878aSAndroid Build Coastguard Worker   all be merged into the same output directory.
398*61c4878aSAndroid Build Coastguard Worker
399*61c4878aSAndroid Build Coastguard Worker``.vendor_wheels`` can attempt to download binary packages for multiple
400*61c4878aSAndroid Build Coastguard Workerplatforms all at once by setting a GN arg:
401*61c4878aSAndroid Build Coastguard Worker
402*61c4878aSAndroid Build Coastguard Worker.. code-block::
403*61c4878aSAndroid Build Coastguard Worker
404*61c4878aSAndroid Build Coastguard Worker   pw_build_PYTHON_PIP_DOWNLOAD_ALL_PLATFORMS = true
405*61c4878aSAndroid Build Coastguard Worker
406*61c4878aSAndroid Build Coastguard WorkerThis will invoke `pip download
407*61c4878aSAndroid Build Coastguard Worker<https://pip.pypa.io/en/stable/cli/pip_download/>`_ for each combination of
408*61c4878aSAndroid Build Coastguard Workerplatform, architecture and Python version. This can take a significant amount of
409*61c4878aSAndroid Build Coastguard Workertime to complete. The current set of combinations is shown below:
410*61c4878aSAndroid Build Coastguard Worker
411*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: pw_build/py/pw_build/generate_python_wheel_cache.py
412*61c4878aSAndroid Build Coastguard Worker   :start-after: [wheel-platform-args]
413*61c4878aSAndroid Build Coastguard Worker   :end-before: [wheel-platform-args]
414*61c4878aSAndroid Build Coastguard Worker
415*61c4878aSAndroid Build Coastguard Worker.. warning::
416*61c4878aSAndroid Build Coastguard Worker   The set of Python packages that will be downloaded is determined by the
417*61c4878aSAndroid Build Coastguard Worker   ``compiled_requirements.txt`` file. This file can only be generated for the
418*61c4878aSAndroid Build Coastguard Worker   current host OS and Python version. `pip-tools
419*61c4878aSAndroid Build Coastguard Worker   <https://pypi.org/project/pip-tools>`_ does not expand requirements for
420*61c4878aSAndroid Build Coastguard Worker   `platform specific dependencies
421*61c4878aSAndroid Build Coastguard Worker   <https://setuptools.pypa.io/en/latest/userguide/dependency_management.html#platform-specific-dependencies>`_. For
422*61c4878aSAndroid Build Coastguard Worker   example ipython defines these two requirements:
423*61c4878aSAndroid Build Coastguard Worker
424*61c4878aSAndroid Build Coastguard Worker   .. code-block::
425*61c4878aSAndroid Build Coastguard Worker
426*61c4878aSAndroid Build Coastguard Worker      appnope; sys_platform == "darwin"
427*61c4878aSAndroid Build Coastguard Worker      colorama; sys_platform == "win32"
428*61c4878aSAndroid Build Coastguard Worker
429*61c4878aSAndroid Build Coastguard Worker   If pip-tools is run on Linux then the above packages will not appear in
430*61c4878aSAndroid Build Coastguard Worker   ``compiled_requirements.txt`` and not downloaded by the ``.vendor_wheels``
431*61c4878aSAndroid Build Coastguard Worker   target.
432*61c4878aSAndroid Build Coastguard Worker
433*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build-installing-offline:
434*61c4878aSAndroid Build Coastguard Worker
435*61c4878aSAndroid Build Coastguard WorkerInstalling Offline
436*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^
437*61c4878aSAndroid Build Coastguard WorkerOnce the vendor wheel output is saved to a directory in your project you can use
438*61c4878aSAndroid Build Coastguard Workerthis as the default pip install location in two different ways.
439*61c4878aSAndroid Build Coastguard Worker
440*61c4878aSAndroid Build Coastguard WorkerGN Args
441*61c4878aSAndroid Build Coastguard Worker.......
442*61c4878aSAndroid Build Coastguard WorkerSetting these args in the ``//.gn`` file will add the relevant pip command line
443*61c4878aSAndroid Build Coastguard Workerargs to perform offline installations.
444*61c4878aSAndroid Build Coastguard Worker
445*61c4878aSAndroid Build Coastguard Worker.. code-block::
446*61c4878aSAndroid Build Coastguard Worker
447*61c4878aSAndroid Build Coastguard Worker   # Adds --no-index forcing pip to not reach out to the internet (pypi.org) to
448*61c4878aSAndroid Build Coastguard Worker   # download packages. Using this option requires setting
449*61c4878aSAndroid Build Coastguard Worker   # pw_build_PYTHON_PIP_INSTALL_FIND_LINKS as well.
450*61c4878aSAndroid Build Coastguard Worker   pw_build_PYTHON_PIP_INSTALL_OFFLINE = true
451*61c4878aSAndroid Build Coastguard Worker
452*61c4878aSAndroid Build Coastguard Worker   # List of paths to folders containing Python wheels (*.whl) or source tar
453*61c4878aSAndroid Build Coastguard Worker   # files (*.tar.gz). Pip will check each of these directories when looking for
454*61c4878aSAndroid Build Coastguard Worker   # potential install candidates.
455*61c4878aSAndroid Build Coastguard Worker   pw_build_PYTHON_PIP_INSTALL_FIND_LINKS = [
456*61c4878aSAndroid Build Coastguard Worker     "//environment/cipd/packages/python_packages/universal",
457*61c4878aSAndroid Build Coastguard Worker     "//environment/cipd/packages/python_packages/linux/cp311",
458*61c4878aSAndroid Build Coastguard Worker   ]
459*61c4878aSAndroid Build Coastguard Worker
460*61c4878aSAndroid Build Coastguard Worker   # Optional: Adds '--no-cache-dir' forcing pip to ignore any previously cached
461*61c4878aSAndroid Build Coastguard Worker   # Python packages. On most systems this is located in ~/.cache/pip/
462*61c4878aSAndroid Build Coastguard Worker   pw_build_PYTHON_PIP_INSTALL_DISABLE_CACHE = false
463*61c4878aSAndroid Build Coastguard Worker
464*61c4878aSAndroid Build Coastguard WorkerUsing a ``.pip.conf`` File
465*61c4878aSAndroid Build Coastguard Worker..........................
466*61c4878aSAndroid Build Coastguard Worker1. Create a ``//pip.conf`` file containing:
467*61c4878aSAndroid Build Coastguard Worker
468*61c4878aSAndroid Build Coastguard Worker   .. code-block::
469*61c4878aSAndroid Build Coastguard Worker      :caption: :octicon:`file;1em` //pip.conf
470*61c4878aSAndroid Build Coastguard Worker      :name: pip-conf-file
471*61c4878aSAndroid Build Coastguard Worker
472*61c4878aSAndroid Build Coastguard Worker      [global]
473*61c4878aSAndroid Build Coastguard Worker      # Disable searching pypi.org for packages
474*61c4878aSAndroid Build Coastguard Worker      no-index = True
475*61c4878aSAndroid Build Coastguard Worker      # Find packages in these directories:
476*61c4878aSAndroid Build Coastguard Worker      find-links =
477*61c4878aSAndroid Build Coastguard Worker          file://third_party/python_packages/universal
478*61c4878aSAndroid Build Coastguard Worker          file://third_party/python_packages/linux/cp311
479*61c4878aSAndroid Build Coastguard Worker
480*61c4878aSAndroid Build Coastguard Worker   This tells pip to not search pypi.org for packages and only look in
481*61c4878aSAndroid Build Coastguard Worker   ``third_party/python_packages/universal`` and
482*61c4878aSAndroid Build Coastguard Worker   ``third_party/python_packages/linux/cp311``. These paths can be absolute or
483*61c4878aSAndroid Build Coastguard Worker   are relative to the ``pip.conf`` file.
484*61c4878aSAndroid Build Coastguard Worker
485*61c4878aSAndroid Build Coastguard Worker2. In the project ``bootstrap.sh`` set ``PIP_CONFIG_FILE`` to the location of
486*61c4878aSAndroid Build Coastguard Worker   this file.
487*61c4878aSAndroid Build Coastguard Worker
488*61c4878aSAndroid Build Coastguard Worker   .. code-block:: bash
489*61c4878aSAndroid Build Coastguard Worker
490*61c4878aSAndroid Build Coastguard Worker      export PIP_CONFIG_FILE="${PW_PROJECT_ROOT}/pip.conf"
491*61c4878aSAndroid Build Coastguard Worker
492*61c4878aSAndroid Build Coastguard Worker   With that environment var set all invocations of pip will apply the config file
493*61c4878aSAndroid Build Coastguard Worker   settings above.
494*61c4878aSAndroid Build Coastguard Worker
495*61c4878aSAndroid Build Coastguard Worker.. seealso::
496*61c4878aSAndroid Build Coastguard Worker   The ``pip`` `documentation on Configuration
497*61c4878aSAndroid Build Coastguard Worker   <https://pip.pypa.io/en/stable/topics/configuration/>`_.
498*61c4878aSAndroid Build Coastguard Worker
499*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build-python-gn-structure:
500*61c4878aSAndroid Build Coastguard Worker
501*61c4878aSAndroid Build Coastguard WorkerGN File Structure for Python Code
502*61c4878aSAndroid Build Coastguard Worker=================================
503*61c4878aSAndroid Build Coastguard WorkerHere is a full example of what is required to build Python packages using
504*61c4878aSAndroid Build Coastguard WorkerPigweed's GN build system. A brief file hierarchy is shown here with file
505*61c4878aSAndroid Build Coastguard Workercontent following. See also :ref:`docs-python-build-structure` below for details
506*61c4878aSAndroid Build Coastguard Workeron the structure of Python packages.
507*61c4878aSAndroid Build Coastguard Worker
508*61c4878aSAndroid Build Coastguard Worker.. code-block::
509*61c4878aSAndroid Build Coastguard Worker   :caption: :octicon:`file-directory;1em` Top level GN file hierarchy
510*61c4878aSAndroid Build Coastguard Worker   :name: gn-python-file-tree
511*61c4878aSAndroid Build Coastguard Worker
512*61c4878aSAndroid Build Coastguard Worker   project_root/
513*61c4878aSAndroid Build Coastguard Worker   ├── .gn
514*61c4878aSAndroid Build Coastguard Worker   ├── BUILDCONFIG.gn
515*61c4878aSAndroid Build Coastguard Worker   ├── build_overrides/
516*61c4878aSAndroid Build Coastguard Worker   │   └── pigweed.gni
517*61c4878aSAndroid Build Coastguard Worker   ├── BUILD.gn
518*61c4878aSAndroid Build Coastguard Worker519*61c4878aSAndroid Build Coastguard Worker   ├── python_package1/
520*61c4878aSAndroid Build Coastguard Worker   │   ├── BUILD.gn
521*61c4878aSAndroid Build Coastguard Worker   │   ├── setup.cfg
522*61c4878aSAndroid Build Coastguard Worker   │   ├── pyproject.toml
523*61c4878aSAndroid Build Coastguard Worker   │   │
524*61c4878aSAndroid Build Coastguard Worker   │   ├── package_name/
525*61c4878aSAndroid Build Coastguard Worker   │   │   ├── module_a.py
526*61c4878aSAndroid Build Coastguard Worker   │   │   ├── module_b.py
527*61c4878aSAndroid Build Coastguard Worker   │   │   ├── py.typed
528*61c4878aSAndroid Build Coastguard Worker   │   │   └── nested_package/
529*61c4878aSAndroid Build Coastguard Worker   │   │       ├── py.typed
530*61c4878aSAndroid Build Coastguard Worker   │   │       └── module_c.py
531*61c4878aSAndroid Build Coastguard Worker   │   │
532*61c4878aSAndroid Build Coastguard Worker   │   ├── module_a_test.py
533*61c4878aSAndroid Build Coastguard Worker   │   └── module_c_test.py
534*61c4878aSAndroid Build Coastguard Worker535*61c4878aSAndroid Build Coastguard Worker   ├── third_party/
536*61c4878aSAndroid Build Coastguard Worker   │   └── pigweed/
537*61c4878aSAndroid Build Coastguard Worker538*61c4878aSAndroid Build Coastguard Worker   └── ...
539*61c4878aSAndroid Build Coastguard Worker
540*61c4878aSAndroid Build Coastguard Worker- :octicon:`file-directory;1em` project_root/
541*61c4878aSAndroid Build Coastguard Worker
542*61c4878aSAndroid Build Coastguard Worker  - :octicon:`file;1em` .gn
543*61c4878aSAndroid Build Coastguard Worker
544*61c4878aSAndroid Build Coastguard Worker    .. code-block::
545*61c4878aSAndroid Build Coastguard Worker
546*61c4878aSAndroid Build Coastguard Worker       buildconfig = "//BUILDCONFIG.gn"
547*61c4878aSAndroid Build Coastguard Worker       import("//build_overrides/pigweed.gni")
548*61c4878aSAndroid Build Coastguard Worker
549*61c4878aSAndroid Build Coastguard Worker       default_args = {
550*61c4878aSAndroid Build Coastguard Worker         pw_build_PIP_CONSTRAINTS = [
551*61c4878aSAndroid Build Coastguard Worker           # Inherit Pigweed Python constraints
552*61c4878aSAndroid Build Coastguard Worker           "$dir_pw_env_setup/py/pw_env_setup/virtualenv_setup/constraint.list",
553*61c4878aSAndroid Build Coastguard Worker
554*61c4878aSAndroid Build Coastguard Worker           # Project specific constraints file
555*61c4878aSAndroid Build Coastguard Worker           "//tools/constraint.txt",
556*61c4878aSAndroid Build Coastguard Worker         ]
557*61c4878aSAndroid Build Coastguard Worker
558*61c4878aSAndroid Build Coastguard Worker         pw_build_PIP_REQUIREMENTS = [
559*61c4878aSAndroid Build Coastguard Worker           # Project specific requirements
560*61c4878aSAndroid Build Coastguard Worker           "//tools/requirements.txt",
561*61c4878aSAndroid Build Coastguard Worker         ]
562*61c4878aSAndroid Build Coastguard Worker
563*61c4878aSAndroid Build Coastguard Worker         # Default gn build virtualenv target.
564*61c4878aSAndroid Build Coastguard Worker         pw_build_PYTHON_BUILD_VENV = "//:project_build_venv"
565*61c4878aSAndroid Build Coastguard Worker       }
566*61c4878aSAndroid Build Coastguard Worker
567*61c4878aSAndroid Build Coastguard Worker    .. tip::
568*61c4878aSAndroid Build Coastguard Worker
569*61c4878aSAndroid Build Coastguard Worker       There are some additional gn args to control how pip installations are
570*61c4878aSAndroid Build Coastguard Worker       performed during the build.
571*61c4878aSAndroid Build Coastguard Worker
572*61c4878aSAndroid Build Coastguard Worker       .. literalinclude:: pw_build/python_gn_args.gni
573*61c4878aSAndroid Build Coastguard Worker          :start-after: [default-pip-gn-args]
574*61c4878aSAndroid Build Coastguard Worker          :end-before: [default-pip-gn-args]
575*61c4878aSAndroid Build Coastguard Worker
576*61c4878aSAndroid Build Coastguard Worker  - :octicon:`file;1em` BUILDCONFIG.gn
577*61c4878aSAndroid Build Coastguard Worker
578*61c4878aSAndroid Build Coastguard Worker    .. code-block::
579*61c4878aSAndroid Build Coastguard Worker
580*61c4878aSAndroid Build Coastguard Worker       _pigweed_directory = {
581*61c4878aSAndroid Build Coastguard Worker         import("//build_overrides/pigweed.gni")
582*61c4878aSAndroid Build Coastguard Worker       }
583*61c4878aSAndroid Build Coastguard Worker
584*61c4878aSAndroid Build Coastguard Worker       set_default_toolchain("${_pigweed_directory.dir_pw_toolchain}/default")
585*61c4878aSAndroid Build Coastguard Worker
586*61c4878aSAndroid Build Coastguard Worker  - :octicon:`file-directory;1em` build_overrides / :octicon:`file;1em` pigweed.gni
587*61c4878aSAndroid Build Coastguard Worker
588*61c4878aSAndroid Build Coastguard Worker    .. code-block::
589*61c4878aSAndroid Build Coastguard Worker
590*61c4878aSAndroid Build Coastguard Worker       declare_args() {
591*61c4878aSAndroid Build Coastguard Worker         # Location of the Pigweed repository.
592*61c4878aSAndroid Build Coastguard Worker         dir_pigweed = "//third_party/pigweed/"
593*61c4878aSAndroid Build Coastguard Worker       }
594*61c4878aSAndroid Build Coastguard Worker
595*61c4878aSAndroid Build Coastguard Worker       # Upstream Pigweed modules.
596*61c4878aSAndroid Build Coastguard Worker       import("$dir_pigweed/modules.gni")
597*61c4878aSAndroid Build Coastguard Worker
598*61c4878aSAndroid Build Coastguard Worker  - :octicon:`file;1em` BUILD.gn
599*61c4878aSAndroid Build Coastguard Worker
600*61c4878aSAndroid Build Coastguard Worker    .. code-block::
601*61c4878aSAndroid Build Coastguard Worker
602*61c4878aSAndroid Build Coastguard Worker       import("//build_overrides/pigweed.gni")
603*61c4878aSAndroid Build Coastguard Worker
604*61c4878aSAndroid Build Coastguard Worker       import("$dir_pw_build/python.gni")
605*61c4878aSAndroid Build Coastguard Worker       import("$dir_pw_build/python_dist.gni")
606*61c4878aSAndroid Build Coastguard Worker       import("$dir_pw_build/python_venv.gni")
607*61c4878aSAndroid Build Coastguard Worker       import("$dir_pw_unit_test/test.gni")
608*61c4878aSAndroid Build Coastguard Worker
609*61c4878aSAndroid Build Coastguard Worker       # Lists all the targets build by default with e.g. `ninja -C out`.
610*61c4878aSAndroid Build Coastguard Worker       group("default") {
611*61c4878aSAndroid Build Coastguard Worker         deps = [
612*61c4878aSAndroid Build Coastguard Worker           ":python.lint",
613*61c4878aSAndroid Build Coastguard Worker           ":python.tests",
614*61c4878aSAndroid Build Coastguard Worker         ]
615*61c4878aSAndroid Build Coastguard Worker       }
616*61c4878aSAndroid Build Coastguard Worker
617*61c4878aSAndroid Build Coastguard Worker       # This group is built during bootstrap to setup the interactive Python
618*61c4878aSAndroid Build Coastguard Worker       # environment.
619*61c4878aSAndroid Build Coastguard Worker       pw_python_group("python") {
620*61c4878aSAndroid Build Coastguard Worker         python_deps = [
621*61c4878aSAndroid Build Coastguard Worker           # Generate and pip install _all_python_packages
622*61c4878aSAndroid Build Coastguard Worker           ":pip_install_project_tools",
623*61c4878aSAndroid Build Coastguard Worker         ]
624*61c4878aSAndroid Build Coastguard Worker       }
625*61c4878aSAndroid Build Coastguard Worker
626*61c4878aSAndroid Build Coastguard Worker       # In-tree Python packages
627*61c4878aSAndroid Build Coastguard Worker       _project_python_packages = [
628*61c4878aSAndroid Build Coastguard Worker         "//python_package1",
629*61c4878aSAndroid Build Coastguard Worker       ]
630*61c4878aSAndroid Build Coastguard Worker
631*61c4878aSAndroid Build Coastguard Worker       # Pigweed Python packages to include
632*61c4878aSAndroid Build Coastguard Worker       _pigweed_python_packages = [
633*61c4878aSAndroid Build Coastguard Worker         "$dir_pw_env_setup:core_pigweed_python_packages",
634*61c4878aSAndroid Build Coastguard Worker         "$dir_pigweed/targets/lm3s6965evb_qemu/py",
635*61c4878aSAndroid Build Coastguard Worker         "$dir_pigweed/targets/stm32f429i_disc1/py",
636*61c4878aSAndroid Build Coastguard Worker       ]
637*61c4878aSAndroid Build Coastguard Worker
638*61c4878aSAndroid Build Coastguard Worker       _all_python_packages =
639*61c4878aSAndroid Build Coastguard Worker           _project_python_packages + _pigweed_python_packages
640*61c4878aSAndroid Build Coastguard Worker
641*61c4878aSAndroid Build Coastguard Worker       # The default venv for Python actions in GN
642*61c4878aSAndroid Build Coastguard Worker       # Set this gn arg in a declare_args block in this file 'BUILD.gn' or in '.gn' to
643*61c4878aSAndroid Build Coastguard Worker       # use this venv.
644*61c4878aSAndroid Build Coastguard Worker       #
645*61c4878aSAndroid Build Coastguard Worker       #   pw_build_PYTHON_BUILD_VENV = "//:project_build_venv"
646*61c4878aSAndroid Build Coastguard Worker       #
647*61c4878aSAndroid Build Coastguard Worker       pw_python_venv("project_build_venv") {
648*61c4878aSAndroid Build Coastguard Worker         path = "$root_build_dir/python-venv"
649*61c4878aSAndroid Build Coastguard Worker         constraints = pw_build_PIP_CONSTRAINTS
650*61c4878aSAndroid Build Coastguard Worker         requirements = pw_build_PIP_REQUIREMENTS
651*61c4878aSAndroid Build Coastguard Worker
652*61c4878aSAndroid Build Coastguard Worker         # Ensure all third party Python dependencies are installed into this venv.
653*61c4878aSAndroid Build Coastguard Worker         # This works by checking the setup.cfg files for all packages listed here and
654*61c4878aSAndroid Build Coastguard Worker         # installing the packages listed in the [options].install_requires field.
655*61c4878aSAndroid Build Coastguard Worker         source_packages = _all_python_packages
656*61c4878aSAndroid Build Coastguard Worker       }
657*61c4878aSAndroid Build Coastguard Worker
658*61c4878aSAndroid Build Coastguard Worker       # This template collects all python packages and their dependencies into a
659*61c4878aSAndroid Build Coastguard Worker       # single super Python package for installation into the bootstrapped virtual
660*61c4878aSAndroid Build Coastguard Worker       # environment.
661*61c4878aSAndroid Build Coastguard Worker       pw_python_distribution("generate_project_python_distribution") {
662*61c4878aSAndroid Build Coastguard Worker         packages = _all_python_packages
663*61c4878aSAndroid Build Coastguard Worker         generate_setup_cfg = {
664*61c4878aSAndroid Build Coastguard Worker           name = "project-tools"
665*61c4878aSAndroid Build Coastguard Worker           version = "0.0.1"
666*61c4878aSAndroid Build Coastguard Worker           append_date_to_version = true
667*61c4878aSAndroid Build Coastguard Worker           include_default_pyproject_file = true
668*61c4878aSAndroid Build Coastguard Worker         }
669*61c4878aSAndroid Build Coastguard Worker       }
670*61c4878aSAndroid Build Coastguard Worker
671*61c4878aSAndroid Build Coastguard Worker       # Install the project-tools super Python package into the bootstrapped
672*61c4878aSAndroid Build Coastguard Worker       # Python venv.
673*61c4878aSAndroid Build Coastguard Worker       pw_python_pip_install("pip_install_project_tools") {
674*61c4878aSAndroid Build Coastguard Worker         packages = [ ":generate_project_python_distribution" ]
675*61c4878aSAndroid Build Coastguard Worker       }
676*61c4878aSAndroid Build Coastguard Worker
677*61c4878aSAndroid Build Coastguard Worker.. _docs-python-build-structure:
678*61c4878aSAndroid Build Coastguard Worker
679*61c4878aSAndroid Build Coastguard WorkerPigweed Module Structure for Python Code
680*61c4878aSAndroid Build Coastguard Worker========================================
681*61c4878aSAndroid Build Coastguard WorkerPigweed Python code is structured into standard Python packages. This makes it
682*61c4878aSAndroid Build Coastguard Workersimple to package and distribute Pigweed Python packages with common Python
683*61c4878aSAndroid Build Coastguard Workertools.
684*61c4878aSAndroid Build Coastguard Worker
685*61c4878aSAndroid Build Coastguard WorkerLike all Pigweed source code, Python packages are organized into Pigweed
686*61c4878aSAndroid Build Coastguard Workermodules. A module's Python package is nested under a ``py/`` directory (see
687*61c4878aSAndroid Build Coastguard Worker:ref:`Pigweed Module Stucture <docs-module-structure>`).
688*61c4878aSAndroid Build Coastguard Worker
689*61c4878aSAndroid Build Coastguard Worker.. code-block::
690*61c4878aSAndroid Build Coastguard Worker   :caption: :octicon:`file-directory;1em` Example layout of a Pigweed Python package.
691*61c4878aSAndroid Build Coastguard Worker   :name: python-file-tree
692*61c4878aSAndroid Build Coastguard Worker
693*61c4878aSAndroid Build Coastguard Worker   module_name/
694*61c4878aSAndroid Build Coastguard Worker   ├── py/
695*61c4878aSAndroid Build Coastguard Worker   │   ├── BUILD.gn
696*61c4878aSAndroid Build Coastguard Worker   │   ├── setup.cfg
697*61c4878aSAndroid Build Coastguard Worker   │   ├── pyproject.toml
698*61c4878aSAndroid Build Coastguard Worker   │   ├── package_name/
699*61c4878aSAndroid Build Coastguard Worker   │   │   ├── module_a.py
700*61c4878aSAndroid Build Coastguard Worker   │   │   ├── module_b.py
701*61c4878aSAndroid Build Coastguard Worker   │   │   ├── py.typed
702*61c4878aSAndroid Build Coastguard Worker   │   │   └── nested_package/
703*61c4878aSAndroid Build Coastguard Worker   │   │       ├── py.typed
704*61c4878aSAndroid Build Coastguard Worker   │   │       └── module_c.py
705*61c4878aSAndroid Build Coastguard Worker   │   ├── module_a_test.py
706*61c4878aSAndroid Build Coastguard Worker   │   └── module_c_test.py
707*61c4878aSAndroid Build Coastguard Worker   └── ...
708*61c4878aSAndroid Build Coastguard Worker
709*61c4878aSAndroid Build Coastguard WorkerThe ``BUILD.gn`` declares this package in GN. For upstream Pigweed, a presubmit
710*61c4878aSAndroid Build Coastguard Workercheck in ensures that all Python files are listed in a ``BUILD.gn``.
711*61c4878aSAndroid Build Coastguard Worker
712*61c4878aSAndroid Build Coastguard WorkerPigweed prefers to define Python packages using ``setup.cfg`` files. In the
713*61c4878aSAndroid Build Coastguard Workerabove file tree the ``pyproject.toml`` file is only a stub with the following
714*61c4878aSAndroid Build Coastguard Workercontent:
715*61c4878aSAndroid Build Coastguard Worker
716*61c4878aSAndroid Build Coastguard Worker.. code-block::
717*61c4878aSAndroid Build Coastguard Worker   :caption: :octicon:`file;1em` pyproject.toml
718*61c4878aSAndroid Build Coastguard Worker   :name: pyproject-toml-stub
719*61c4878aSAndroid Build Coastguard Worker
720*61c4878aSAndroid Build Coastguard Worker   [build-system]
721*61c4878aSAndroid Build Coastguard Worker   requires = ['setuptools', 'wheel']
722*61c4878aSAndroid Build Coastguard Worker   build-backend = 'setuptools.build_meta'
723*61c4878aSAndroid Build Coastguard Worker
724*61c4878aSAndroid Build Coastguard WorkerEach ``pyproject.toml`` file is required to specify which build system should be
725*61c4878aSAndroid Build Coastguard Workerused for the given Python package. In Pigweed's case it always specifies using
726*61c4878aSAndroid Build Coastguard Workersetuptools.
727*61c4878aSAndroid Build Coastguard Worker
728*61c4878aSAndroid Build Coastguard Worker.. seealso::
729*61c4878aSAndroid Build Coastguard Worker
730*61c4878aSAndroid Build Coastguard Worker   - ``setup.cfg`` examples at `Configuring setup() using setup.cfg files`_
731*61c4878aSAndroid Build Coastguard Worker   - ``pyproject.toml`` background at `Build System Support - How to use it?`_
732*61c4878aSAndroid Build Coastguard Worker
733*61c4878aSAndroid Build Coastguard Worker.. _module-pw_build-python-target:
734*61c4878aSAndroid Build Coastguard Worker
735*61c4878aSAndroid Build Coastguard Workerpw_python_package targets
736*61c4878aSAndroid Build Coastguard Worker-------------------------
737*61c4878aSAndroid Build Coastguard WorkerThe key abstraction in the Python build is the ``pw_python_package``.
738*61c4878aSAndroid Build Coastguard WorkerA ``pw_python_package`` represents a Python package as a GN target. It is
739*61c4878aSAndroid Build Coastguard Workerimplemented with a GN template. The ``pw_python_package`` template is documented
740*61c4878aSAndroid Build Coastguard Workerin :ref:`module-pw_build-python`.
741*61c4878aSAndroid Build Coastguard Worker
742*61c4878aSAndroid Build Coastguard WorkerThe key attributes of a ``pw_python_package`` are
743*61c4878aSAndroid Build Coastguard Worker
744*61c4878aSAndroid Build Coastguard Worker- a ``setup.cfg`` and ``pyproject.toml`` file,
745*61c4878aSAndroid Build Coastguard Worker- source files,
746*61c4878aSAndroid Build Coastguard Worker- test files,
747*61c4878aSAndroid Build Coastguard Worker- dependencies on other ``pw_python_package`` targets.
748*61c4878aSAndroid Build Coastguard Worker
749*61c4878aSAndroid Build Coastguard WorkerA ``pw_python_package`` target is composed of several GN subtargets. Each
750*61c4878aSAndroid Build Coastguard Workersubtarget represents different functionality in the Python build.
751*61c4878aSAndroid Build Coastguard Worker
752*61c4878aSAndroid Build Coastguard Worker- ``<name>`` - Represents the Python files in the build, but does not take any
753*61c4878aSAndroid Build Coastguard Worker  actions. All subtargets depend on this target.
754*61c4878aSAndroid Build Coastguard Worker- ``<name>.tests`` - Runs all tests for this package.
755*61c4878aSAndroid Build Coastguard Worker
756*61c4878aSAndroid Build Coastguard Worker  - ``<name>.tests.<test_file>`` - Runs the specified test.
757*61c4878aSAndroid Build Coastguard Worker
758*61c4878aSAndroid Build Coastguard Worker- ``<name>.lint`` - Runs static analysis tools on the Python code. This is a
759*61c4878aSAndroid Build Coastguard Worker  group of three subtargets:
760*61c4878aSAndroid Build Coastguard Worker
761*61c4878aSAndroid Build Coastguard Worker  - ``<name>.lint.mypy`` - Runs Mypy on all Python files, if enabled.
762*61c4878aSAndroid Build Coastguard Worker  - ``<name>.lint.pylint`` - Runs Pylint on all Python files, if enabled.
763*61c4878aSAndroid Build Coastguard Worker  - ``<name>.lint.ruff`` - Runs ruff on all Python files, if enabled.
764*61c4878aSAndroid Build Coastguard Worker
765*61c4878aSAndroid Build Coastguard Worker- ``<name>.install`` - Installs the package in a Python virtual environment.
766*61c4878aSAndroid Build Coastguard Worker- ``<name>.wheel`` - Builds a Python wheel for this package.
767*61c4878aSAndroid Build Coastguard Worker
768*61c4878aSAndroid Build Coastguard WorkerTo avoid unnecessary duplication, all Python actions are executed in the default
769*61c4878aSAndroid Build Coastguard Workertoolchain, even if they are referred to from other toolchains.
770*61c4878aSAndroid Build Coastguard Worker
771*61c4878aSAndroid Build Coastguard WorkerTesting
772*61c4878aSAndroid Build Coastguard Worker^^^^^^^
773*61c4878aSAndroid Build Coastguard WorkerTests for a Python package are listed in its ``pw_python_package`` target.
774*61c4878aSAndroid Build Coastguard WorkerAdding a new test is simple: write the test file and list it in its accompanying
775*61c4878aSAndroid Build Coastguard WorkerPython package. The build will run it when the test, the package, or one of its
776*61c4878aSAndroid Build Coastguard Workerdependencies is updated.
777*61c4878aSAndroid Build Coastguard Worker
778*61c4878aSAndroid Build Coastguard WorkerStatic analysis
779*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^
780*61c4878aSAndroid Build Coastguard Worker``pw_python_package`` targets are preconfigured to run Pylint, Mypy and Ruff on
781*61c4878aSAndroid Build Coastguard Workertheir source and test files. Users may specify which ``pylintrc``, ``mypy_ini``
782*61c4878aSAndroid Build Coastguard Workerand ``ruff_toml`` files to use on a per-package basis. The configuration files
783*61c4878aSAndroid Build Coastguard Workermay also be provided in the directory structure; the tools will locate them
784*61c4878aSAndroid Build Coastguard Workerusing their standard means. Like tests, static analysis is only run when files
785*61c4878aSAndroid Build Coastguard Workeror their dependencies change.
786*61c4878aSAndroid Build Coastguard Worker
787*61c4878aSAndroid Build Coastguard WorkerPackages may opt out of static analysis as necessary by setting
788*61c4878aSAndroid Build Coastguard Worker``static_analysis`` on the ``pw_python_package`` target.
789*61c4878aSAndroid Build Coastguard Worker
790*61c4878aSAndroid Build Coastguard WorkerThe default set of analysis tools to run can be set globally via a GN arg
791*61c4878aSAndroid Build Coastguard Worker``pw_build_PYTHON_STATIC_ANALYSIS_TOOLS``. By default this is set to include the
792*61c4878aSAndroid Build Coastguard Workerbelow tools:
793*61c4878aSAndroid Build Coastguard Worker
794*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: pw_build/python.gni
795*61c4878aSAndroid Build Coastguard Worker   :start-after: [python-static-analysis-tools]
796*61c4878aSAndroid Build Coastguard Worker   :end-before: [python-static-analysis-tools]
797*61c4878aSAndroid Build Coastguard Worker
798*61c4878aSAndroid Build Coastguard WorkerIn addition to user specified ``mypy_ini`` files some arguments are always
799*61c4878aSAndroid Build Coastguard Workerpassed to ``mypy`` by default. They can be seen in this excerpt of
800*61c4878aSAndroid Build Coastguard Worker``//pw_build/python.gni`` below:
801*61c4878aSAndroid Build Coastguard Worker
802*61c4878aSAndroid Build Coastguard Worker.. literalinclude:: pw_build/python.gni
803*61c4878aSAndroid Build Coastguard Worker   :start-after: [default-mypy-args]
804*61c4878aSAndroid Build Coastguard Worker   :end-before: [default-mypy-args]
805*61c4878aSAndroid Build Coastguard Worker
806*61c4878aSAndroid Build Coastguard WorkerBuilding Python wheels
807*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^^^
808*61c4878aSAndroid Build Coastguard Worker`Wheels <https://wheel.readthedocs.io/en/stable/>`_ are the standard format for
809*61c4878aSAndroid Build Coastguard Workerdistributing Python packages. The Pigweed Python build supports creating wheels
810*61c4878aSAndroid Build Coastguard Workerfor individual packages and groups of packages. Building the ``.wheel``
811*61c4878aSAndroid Build Coastguard Workersubtarget creates a ``.whl`` file for the package using the PyPA's `build
812*61c4878aSAndroid Build Coastguard Worker<https://pypa-build.readthedocs.io/en/stable/>`_ tool.
813*61c4878aSAndroid Build Coastguard Worker
814*61c4878aSAndroid Build Coastguard WorkerThe ``.wheel`` subtarget of any ``pw_python_package`` or
815*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_build-pw_python_distribution` records the location of the
816*61c4878aSAndroid Build Coastguard Workergenerated wheel with `GN metadata
817*61c4878aSAndroid Build Coastguard Worker<https://gn.googlesource.com/gn/+/HEAD/docs/reference.md#var_metadata>`_.
818*61c4878aSAndroid Build Coastguard WorkerWheels for a Python package and its transitive dependencies can be collected
819*61c4878aSAndroid Build Coastguard Workerfrom the ``pw_python_package_wheels`` key. See
820*61c4878aSAndroid Build Coastguard Worker:ref:`module-pw_build-python-dist`.
821*61c4878aSAndroid Build Coastguard Worker
822*61c4878aSAndroid Build Coastguard WorkerProtocol buffers
823*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^
824*61c4878aSAndroid Build Coastguard WorkerThe Pigweed GN build supports protocol buffers with the ``pw_proto_library``
825*61c4878aSAndroid Build Coastguard Workertarget (see :ref:`module-pw_protobuf_compiler`). Python protobuf modules are
826*61c4878aSAndroid Build Coastguard Workergenerated as standalone Python packages by default. Protocol buffers may also be
827*61c4878aSAndroid Build Coastguard Workernested within existing Python packages. In this case, the Python package in the
828*61c4878aSAndroid Build Coastguard Workersource tree is incomplete; the final Python package, including protobufs, is
829*61c4878aSAndroid Build Coastguard Workergenerated in the output directory.
830*61c4878aSAndroid Build Coastguard Worker
831*61c4878aSAndroid Build Coastguard WorkerGenerating setup.cfg
832*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^^^^^
833*61c4878aSAndroid Build Coastguard WorkerThe ``pw_python_package`` target in the ``BUILD.gn`` duplicates much of the
834*61c4878aSAndroid Build Coastguard Workerinformation in the ``setup.cfg`` file. In many cases, it would be possible to
835*61c4878aSAndroid Build Coastguard Workergenerate a ``setup.cfg`` file rather than including it in the source
836*61c4878aSAndroid Build Coastguard Workertree. However, removing the ``setup.cfg`` would preclude using a direct,
837*61c4878aSAndroid Build Coastguard Workereditable installation from the source tree.
838*61c4878aSAndroid Build Coastguard Worker
839*61c4878aSAndroid Build Coastguard WorkerPigweed packages containing protobufs are generated in full or in part. These
840*61c4878aSAndroid Build Coastguard Workerpackages may use generated setup files, since they are always packaged or
841*61c4878aSAndroid Build Coastguard Workerinstalled from the build output directory.
842*61c4878aSAndroid Build Coastguard Worker
843*61c4878aSAndroid Build Coastguard Worker
844*61c4878aSAndroid Build Coastguard WorkerRationale
845*61c4878aSAndroid Build Coastguard Worker=========
846*61c4878aSAndroid Build Coastguard Worker
847*61c4878aSAndroid Build Coastguard WorkerBackground
848*61c4878aSAndroid Build Coastguard Worker----------
849*61c4878aSAndroid Build Coastguard WorkerDeveloping software involves much more than writing source code. Software needs
850*61c4878aSAndroid Build Coastguard Workerto be compiled, executed, tested, analyzed, packaged, and deployed. As projects
851*61c4878aSAndroid Build Coastguard Workergrow beyond a few files, these tasks become impractical to manage manually.
852*61c4878aSAndroid Build Coastguard WorkerBuild systems automate these auxiliary tasks of software development, making it
853*61c4878aSAndroid Build Coastguard Workerpossible to build larger, more complex systems quickly and robustly.
854*61c4878aSAndroid Build Coastguard Worker
855*61c4878aSAndroid Build Coastguard WorkerPython is an interpreted language, but it shares most build automation concerns
856*61c4878aSAndroid Build Coastguard Workerwith other languages. Pigweed uses Python extensively and must address these
857*61c4878aSAndroid Build Coastguard Workerneeds for itself and its users.
858*61c4878aSAndroid Build Coastguard Worker
859*61c4878aSAndroid Build Coastguard WorkerExisting solutions
860*61c4878aSAndroid Build Coastguard Worker------------------
861*61c4878aSAndroid Build Coastguard WorkerThe Python programming langauge does not have an official build automation
862*61c4878aSAndroid Build Coastguard Workersystem. However, there are numerous Python-focused build automation tools with
863*61c4878aSAndroid Build Coastguard Workervarying degrees of adoption. See the `Python Wiki
864*61c4878aSAndroid Build Coastguard Worker<https://wiki.python.org/moin/ConfigurationAndBuildTools>`_ for examples.
865*61c4878aSAndroid Build Coastguard Worker
866*61c4878aSAndroid Build Coastguard WorkerA few Python tools have become defacto standards, including `setuptools
867*61c4878aSAndroid Build Coastguard Worker<https://pypi.org/project/setuptools/>`_, `wheel
868*61c4878aSAndroid Build Coastguard Worker<https://pypi.org/project/wheel/>`_, and `pip <https://pypi.org/project/pip/>`_.
869*61c4878aSAndroid Build Coastguard WorkerThese essential tools address key aspects of Python packaging and distribution,
870*61c4878aSAndroid Build Coastguard Workerbut are not intended for general build automation. Tools like `PyBuilder
871*61c4878aSAndroid Build Coastguard Worker<https://pybuilder.io/>`_ and `tox <https://tox.readthedocs.io/en/latest/>`_
872*61c4878aSAndroid Build Coastguard Workerprovide more general build automation for Python.
873*61c4878aSAndroid Build Coastguard Worker
874*61c4878aSAndroid Build Coastguard WorkerThe `Bazel <http://bazel.build/>`_ build system has first class support for
875*61c4878aSAndroid Build Coastguard WorkerPython and other languages used by Pigweed, including protocol buffers.
876*61c4878aSAndroid Build Coastguard Worker
877*61c4878aSAndroid Build Coastguard WorkerChallenges
878*61c4878aSAndroid Build Coastguard Worker----------
879*61c4878aSAndroid Build Coastguard WorkerPigweed's use of Python is different from many other projects. Pigweed is a
880*61c4878aSAndroid Build Coastguard Workermulti-language, modular project. It serves both as a library or middleware and
881*61c4878aSAndroid Build Coastguard Workeras a development environment.
882*61c4878aSAndroid Build Coastguard Worker
883*61c4878aSAndroid Build Coastguard WorkerThis section describes Python build automation challenges encountered by
884*61c4878aSAndroid Build Coastguard WorkerPigweed.
885*61c4878aSAndroid Build Coastguard Worker
886*61c4878aSAndroid Build Coastguard WorkerDependencies
887*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^
888*61c4878aSAndroid Build Coastguard WorkerPigweed is organized into distinct modules. In Python, each module is a separate
889*61c4878aSAndroid Build Coastguard Workerpackage, potentially with dependencies on other local or `PyPI
890*61c4878aSAndroid Build Coastguard Worker<https://pypi.org/>`_ packages.
891*61c4878aSAndroid Build Coastguard Worker
892*61c4878aSAndroid Build Coastguard WorkerThe basic Python packaging tools lack dependency tracking for local packages.
893*61c4878aSAndroid Build Coastguard WorkerFor example, a package's ``setup.cfg`` lists all of its dependencies, but
894*61c4878aSAndroid Build Coastguard Worker``pip`` is not aware of local packages until they are installed. Packages must
895*61c4878aSAndroid Build Coastguard Workerbe installed with their dependencies taken into account, in topological sorted
896*61c4878aSAndroid Build Coastguard Workerorder.
897*61c4878aSAndroid Build Coastguard Worker
898*61c4878aSAndroid Build Coastguard WorkerTo work around this, one could set up a private `PyPI server
899*61c4878aSAndroid Build Coastguard Worker<https://pypi.org/project/pypiserver/>`_ instance, but this is too cumbersome
900*61c4878aSAndroid Build Coastguard Workerfor daily development and incompatible with editable package installation.
901*61c4878aSAndroid Build Coastguard Worker
902*61c4878aSAndroid Build Coastguard WorkerTesting
903*61c4878aSAndroid Build Coastguard Worker^^^^^^^
904*61c4878aSAndroid Build Coastguard WorkerTests are crucial to having a healthy, maintainable codebase. While they take
905*61c4878aSAndroid Build Coastguard Workersome initial work to write, the time investment pays for itself many times over
906*61c4878aSAndroid Build Coastguard Workerby contributing to the long-term resilience of a codebase. Despite their
907*61c4878aSAndroid Build Coastguard Workerbenefit, developers don't always take the time to write tests. Any barriers to
908*61c4878aSAndroid Build Coastguard Workerwriting and running tests result in fewer tests and consequently more fragile,
909*61c4878aSAndroid Build Coastguard Workerbug-prone codebases.
910*61c4878aSAndroid Build Coastguard Worker
911*61c4878aSAndroid Build Coastguard WorkerThere are lots of great Python libraries for testing, such as
912*61c4878aSAndroid Build Coastguard Worker`unittest <https://docs.python.org/3/library/unittest.html>`_ and
913*61c4878aSAndroid Build Coastguard Worker`pytest <https://docs.pytest.org/en/stable/>`_. These tools make it easy to
914*61c4878aSAndroid Build Coastguard Workerwrite and execute individual Python tests, but are not well suited for managing
915*61c4878aSAndroid Build Coastguard Workersuites of interdependent tests in a large project. Writing a test with these
916*61c4878aSAndroid Build Coastguard Workerutilities does not automatically run them or keep running them as the codebase
917*61c4878aSAndroid Build Coastguard Workerchanges.
918*61c4878aSAndroid Build Coastguard Worker
919*61c4878aSAndroid Build Coastguard WorkerStatic analysis
920*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^
921*61c4878aSAndroid Build Coastguard Worker
922*61c4878aSAndroid Build Coastguard Worker.. seealso::
923*61c4878aSAndroid Build Coastguard Worker
924*61c4878aSAndroid Build Coastguard Worker   :bdg-ref-primary-line:`docs-automated-analysis` for info on other static
925*61c4878aSAndroid Build Coastguard Worker   analysis tools used in Pigweed.
926*61c4878aSAndroid Build Coastguard Worker
927*61c4878aSAndroid Build Coastguard WorkerVarious static analysis tools exist for Python. Two widely used, powerful tools
928*61c4878aSAndroid Build Coastguard Workerare `Pylint <https://www.pylint.org/>`_ and `Mypy <http://mypy-lang.org/>`_.
929*61c4878aSAndroid Build Coastguard WorkerUsing these tools improves code quality, as they catch bugs, encourage good
930*61c4878aSAndroid Build Coastguard Workerdesign practices, and enforce a consistent coding style. As with testing,
931*61c4878aSAndroid Build Coastguard Workerbarriers to running static analysis tools cause many developers to skip them.
932*61c4878aSAndroid Build Coastguard WorkerSome developers may not even be aware of these tools.
933*61c4878aSAndroid Build Coastguard Worker
934*61c4878aSAndroid Build Coastguard WorkerDeploying static analysis tools to a codebase like Pigweed has some challenges.
935*61c4878aSAndroid Build Coastguard WorkerMypy and Pylint are simple to run, but they are extremely slow. Ideally, these
936*61c4878aSAndroid Build Coastguard Workertools would be run constantly during development, but only on files that change.
937*61c4878aSAndroid Build Coastguard WorkerThese tools do not have built-in support for incremental runs or dependency
938*61c4878aSAndroid Build Coastguard Workertracking.
939*61c4878aSAndroid Build Coastguard Worker
940*61c4878aSAndroid Build Coastguard WorkerAnother challenge is configuration. Mypy and Pylint support using configuration
941*61c4878aSAndroid Build Coastguard Workerfiles to select which checks to run and how to apply them. Both tools only
942*61c4878aSAndroid Build Coastguard Workersupport using a single configuration file for an entire run, which poses a
943*61c4878aSAndroid Build Coastguard Workerchallenge to modular middleware systems where different parts of a project may
944*61c4878aSAndroid Build Coastguard Workerrequire different configurations.
945*61c4878aSAndroid Build Coastguard Worker
946*61c4878aSAndroid Build Coastguard WorkerProtocol buffers
947*61c4878aSAndroid Build Coastguard Worker^^^^^^^^^^^^^^^^
948*61c4878aSAndroid Build Coastguard Worker`Protocol buffers <https://developers.google.com/protocol-buffers>`_ are an
949*61c4878aSAndroid Build Coastguard Workerefficient system for serializing structured data. They are widely used by Google
950*61c4878aSAndroid Build Coastguard Workerand other companies.
951*61c4878aSAndroid Build Coastguard Worker
952*61c4878aSAndroid Build Coastguard WorkerThe protobuf compiler ``protoc`` generates Python modules from ``.proto`` files.
953*61c4878aSAndroid Build Coastguard Worker``protoc`` strictly generates protobuf modules according to their directory
954*61c4878aSAndroid Build Coastguard Workerstructure. This works well in a monorepo, but poses a challenge to a middleware
955*61c4878aSAndroid Build Coastguard Workersystem like Pigweed. Generating protobufs by path also makes integrating
956*61c4878aSAndroid Build Coastguard Workerprotobufs with existing packages awkward.
957*61c4878aSAndroid Build Coastguard Worker
958*61c4878aSAndroid Build Coastguard WorkerRequirements
959*61c4878aSAndroid Build Coastguard Worker------------
960*61c4878aSAndroid Build Coastguard WorkerPigweed aims to provide high quality software components and a fast, effective,
961*61c4878aSAndroid Build Coastguard Workerflexible development experience for its customers. Pigweed's high-level goals
962*61c4878aSAndroid Build Coastguard Workerand the `challenges`_ described above inform these requirements for the Pigweed
963*61c4878aSAndroid Build Coastguard WorkerPython build.
964*61c4878aSAndroid Build Coastguard Worker
965*61c4878aSAndroid Build Coastguard Worker- Integrate seamlessly with the other Pigweed build tools.
966*61c4878aSAndroid Build Coastguard Worker- Easy to use independently, even if primarily using a different build system.
967*61c4878aSAndroid Build Coastguard Worker- Support standard packaging and distribution with setuptools, wheel, and pip.
968*61c4878aSAndroid Build Coastguard Worker- Correctly manage interdependent local Python packages.
969*61c4878aSAndroid Build Coastguard Worker- Out-of-the-box support for writing and running tests.
970*61c4878aSAndroid Build Coastguard Worker- Preconfigured, trivial-to-run static analysis integration for Pylint and Mypy.
971*61c4878aSAndroid Build Coastguard Worker- Fast, dependency-aware incremental rebuilds and test execution, suitable for
972*61c4878aSAndroid Build Coastguard Worker  use with :ref:`module-pw_watch`.
973*61c4878aSAndroid Build Coastguard Worker- Seamless protocol buffer support.
974*61c4878aSAndroid Build Coastguard Worker
975*61c4878aSAndroid Build Coastguard WorkerDesign Decision
976*61c4878aSAndroid Build Coastguard Worker---------------
977*61c4878aSAndroid Build Coastguard WorkerExisting Python tools may be effective for Python codebases, but their utility
978*61c4878aSAndroid Build Coastguard Workeris more limited in a multi-language project like Pigweed. The cost of bringing
979*61c4878aSAndroid Build Coastguard Workerup and maintaining an additional build automation system for a single language
980*61c4878aSAndroid Build Coastguard Workeris high.
981*61c4878aSAndroid Build Coastguard Worker
982*61c4878aSAndroid Build Coastguard WorkerPigweed uses GN as its primary build system for all languages. While GN does not
983*61c4878aSAndroid Build Coastguard Workernatively support Python, adding support is straightforward with GN templates.
984*61c4878aSAndroid Build Coastguard Worker
985*61c4878aSAndroid Build Coastguard WorkerGN has strong multi-toolchain and multi-language capabilities. In GN, it is
986*61c4878aSAndroid Build Coastguard Workerstraightforward to share targets and artifacts between different languages. For
987*61c4878aSAndroid Build Coastguard Workerexample, C++, Go, and Python targets can depend on the same protobuf
988*61c4878aSAndroid Build Coastguard Workerdeclaration. When using GN for multiple languages, Ninja schedules build steps
989*61c4878aSAndroid Build Coastguard Workerfor all languages together, resulting in faster total build times.
990*61c4878aSAndroid Build Coastguard Worker
991*61c4878aSAndroid Build Coastguard WorkerNot all Pigweed users build with GN. Of Pigweed's three supported build systems,
992*61c4878aSAndroid Build Coastguard WorkerGN is the fastest, lightest weight, and easiest to run. It also has simple,
993*61c4878aSAndroid Build Coastguard Workerclean syntax. This makes it feasible to use GN only for Python while building
994*61c4878aSAndroid Build Coastguard Workerprimarily with a different system.
995*61c4878aSAndroid Build Coastguard Worker
996*61c4878aSAndroid Build Coastguard WorkerGiven these considerations, GN is an ideal choice for Pigweed's Python build.
997*61c4878aSAndroid Build Coastguard Worker
998*61c4878aSAndroid Build Coastguard Worker.. _Configuring setup() using setup.cfg files: https://ipython.readthedocs.io/en/stable/interactive/reference.html#embedding
999*61c4878aSAndroid Build Coastguard Worker.. _Build System Support - How to use it?: https://setuptools.readthedocs.io/en/latest/build_meta.html?highlight=pyproject.toml#how-to-use-it
1000