blob: 9b99e2be543cecb8c65ba37368fb09845912b0ee [file] [log] [blame]
Wyatt Heplerb3ea9802021-02-23 09:46:09 -08001.. _module-pw_build-python:
2
3-------------------
4Python GN templates
5-------------------
6The Python build is implemented with GN templates defined in
Joe Ethierfbe66152021-03-31 16:02:36 -07007``pw_build/python.gni``. See the .gni file for complete usage documentation.
Wyatt Heplerb3ea9802021-02-23 09:46:09 -08008
9.. seealso:: :ref:`docs-python-build`
10
Anthony DiGirolamo211dce42021-08-12 16:48:43 -070011.. _module-pw_build-pw_python_package:
12
Wyatt Heplerb3ea9802021-02-23 09:46:09 -080013pw_python_package
14=================
15The main Python template is ``pw_python_package``. Each ``pw_python_package``
16target represents a Python package. As described in
17:ref:`module-pw_build-python-target`, each ``pw_python_package`` expands to
18several subtargets. In summary, these are:
19
20- ``<name>`` - Represents the files themselves
21- ``<name>.lint`` - Runs static analysis
22- ``<name>.tests`` - Runs all tests for this package
23- ``<name>.install`` - Installs the package
24- ``<name>.wheel`` - Builds a Python wheel
25
Wyatt Heplerb85cda42021-04-07 13:13:15 -070026GN permits using abbreviated labels when the target name matches the directory
27name (e.g. ``//foo`` for ``//foo:foo``). For consistency with this, Python
28package subtargets are aliased to the directory when the target name is the
29same as the directory. For example, these two labels are equivalent:
30
31.. code-block::
32
33 //path/to/my_python_package:my_python_package.tests
34 //path/to/my_python_package:tests
35
Wyatt Heplerf6f74f42021-04-13 19:26:20 -070036The actions in a ``pw_python_package`` (e.g. installing packages and running
37Pylint) are done within a single GN toolchain to avoid duplication in
38multi-toolchain builds. This toolchain can be set with the
Joe Ethierfbe66152021-03-31 16:02:36 -070039``pw_build_PYTHON_TOOLCHAIN`` GN arg, which defaults to
40``$dir_pw_build/python_toolchain:python``.
Wyatt Heplerf6f74f42021-04-13 19:26:20 -070041
Wyatt Heplerb3ea9802021-02-23 09:46:09 -080042Arguments
43---------
44- ``setup`` - List of setup file paths (setup.py or pyproject.toml & setup.cfg),
45 which must all be in the same directory.
Wyatt Heplerb85cda42021-04-07 13:13:15 -070046- ``generate_setup``: As an alternative to ``setup``, generate setup files with
Anthony DiGirolamoafb861c2021-08-12 16:48:04 -070047 the keywords in this scope. ``name`` is required. This follows the same
48 structure as a ``setup.cfg`` file's `declarative config
49 <https://setuptools.readthedocs.io/en/latest/userguide/declarative_config.html>`_
50 For example:
Wyatt Heplerb85cda42021-04-07 13:13:15 -070051
52 .. code-block::
53
54 generate_setup = {
Anthony DiGirolamoafb861c2021-08-12 16:48:04 -070055 metadata = {
56 name = "a_nifty_package"
57 version = "1.2a"
58 }
59 options = {
60 install_requires = [ "a_pip_package" ]
61 }
Wyatt Heplerb85cda42021-04-07 13:13:15 -070062 }
63
Wyatt Heplerb3ea9802021-02-23 09:46:09 -080064- ``sources`` - Python sources files in the package.
65- ``tests`` - Test files for this Python package.
66- ``python_deps`` - Dependencies on other pw_python_packages in the GN build.
67- ``python_test_deps`` - Test-only pw_python_package dependencies.
68- ``other_deps`` - Dependencies on GN targets that are not pw_python_packages.
69- ``inputs`` - Other files to track, such as package_data.
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -080070- ``proto_library`` - A pw_proto_library target to embed in this Python package.
Wyatt Heplerb85cda42021-04-07 13:13:15 -070071 ``generate_setup`` is required in place of setup if proto_library is used. See
Wyatt Heplerdcfcecf2021-03-01 08:36:19 -080072 :ref:`module-pw_protobuf_compiler-add-to-python-package`.
Wyatt Heplerc2ce5242021-03-17 08:42:14 -070073- ``static_analysis`` List of static analysis tools to run; ``"*"`` (default)
74 runs all tools. The supported tools are ``"mypy"`` and ``"pylint"``.
Wyatt Heplerb3ea9802021-02-23 09:46:09 -080075- ``pylintrc`` - Optional path to a pylintrc configuration file to use. If not
76 provided, Pylint's default rcfile search is used. Pylint is executed
77 from the package's setup directory, so pylintrc files in that directory
78 will take precedence over others.
79- ``mypy_ini`` - Optional path to a mypy configuration file to use. If not
80 provided, mypy's default configuration file search is used. mypy is
81 executed from the package's setup directory, so mypy.ini files in that
82 directory will take precedence over others.
83
84Example
85-------
86This is an example Python package declaration for a ``pw_my_module`` module.
87
88.. code-block::
89
90 import("//build_overrides/pigweed.gni")
91
92 import("$dir_pw_build/python.gni")
93
94 pw_python_package("py") {
Anthony DiGirolamo7f8941f2021-08-24 10:02:04 -070095 setup = [
96 "pyproject.toml",
97 "setup.cfg",
98 "setup.py",
99 ]
Wyatt Heplerb3ea9802021-02-23 09:46:09 -0800100 sources = [
101 "pw_my_module/__init__.py",
102 "pw_my_module/alfa.py",
103 "pw_my_module/bravo.py",
104 "pw_my_module/charlie.py",
105 ]
106 tests = [
107 "alfa_test.py",
108 "charlie_test.py",
109 ]
110 python_deps = [
111 "$dir_pw_status/py",
112 ":some_protos.python",
113 ]
114 python_test_deps = [ "$dir_pw_build/py" ]
115 pylintrc = "$dir_pigweed/.pylintrc"
116 }
117
118pw_python_script
119================
120A ``pw_python_script`` represents a set of standalone Python scripts and/or
121tests. These files support all of the arguments of ``pw_python_package`` except
122those ``setup``. These targets can be installed, but this only installs their
123dependencies.
124
Wyatt Hepler473efe02021-05-04 14:15:16 -0700125``pw_python_script`` allows creating a
126:ref:`pw_python_action <module-pw_build-python-action>` associated with the
127script. To create an action, pass an ``action`` scope to ``pw_python_script``.
128If there is only a single source file, it serves as the action's ``script`` by
129default.
130
131An action in ``pw_python_script`` can always be replaced with a standalone
132``pw_python_action``, but using the embedded action has some advantages:
133
134- The embedded action target bridges the gap between actions and Python targets.
135 A Python script can be expressed in a single, concise GN target, rather than
136 in two overlapping, dependent targets.
137- The action automatically depends on the ``pw_python_script``. This ensures
138 that the script's dependencies are installed and the action automatically
139 reruns when the script's sources change, without needing to specify a
140 dependency, a step which is easy to forget.
141- Using a ``pw_python_script`` with an embedded action is a simple way to check
142 an existing action's script with Pylint or Mypy or to add tests.
143
Wyatt Heplerb3ea9802021-02-23 09:46:09 -0800144pw_python_group
145===============
146Represents a group of ``pw_python_package`` and ``pw_python_script`` targets.
147These targets do not add any files. Their subtargets simply forward to those of
148their dependencies.
149
Wyatt Heplerb3ea9802021-02-23 09:46:09 -0800150pw_python_requirements
151======================
152Represents a set of local and PyPI requirements, with no associated source
153files. These targets serve the role of a ``requirements.txt`` file.
Joe Ethierfbe66152021-03-31 16:02:36 -0700154
Michael Spang01faaf72021-06-09 22:38:40 -0400155When packages are installed by Pigweed, additional version constraints can be
156provided using the ``pw_build_PIP_CONSTRAINTS`` GN arg. This option should
157contain a list of paths to pass to the ``--constraint`` option of ``pip
158install``. This can be used to synchronize dependency upgrades across a project
159which facilitates reproducibility of builds.
160
161Note using multiple ``pw_python_requirements`` that install different versions
162of the same package will currently cause unpredictable results, while using
163constraints should have correct results (which may be an error indicating a
164conflict).
165
Joe Ethierfbe66152021-03-31 16:02:36 -0700166.. _module-pw_build-python-dist:
167
168---------------------
Anthony DiGirolamo211dce42021-08-12 16:48:43 -0700169Python Distributables
Joe Ethierfbe66152021-03-31 16:02:36 -0700170---------------------
171Pigweed also provides some templates to make it easier to bundle Python packages
172for deployment. These templates are found in ``pw_build/python_dist.gni``. See
173the .gni file for complete usage doclumentation.
174
175pw_python_wheels
176================
177Collects Python wheels for one or more ``pw_python_package`` targets, plus any
178additional ``pw_python_package`` targets they depend on, directly or indirectly.
179Note that this does not include Python dependencies that come from outside the
180GN build, like packages from PyPI, for example. Those should still be declared
181in the package's ``setup.py`` file as usual.
182
183Arguments
184---------
185- ``packages`` - List of ``pw_python_package`` targets whose wheels should be
186 included; their dependencies will be pulled in as wheels also.
187
188Wheel collection under the hood
189-------------------------------
190The ``.wheel`` subtarget of every ``pw_python_package`` generates a wheel
191(``.whl``) for the Python package. The ``pw_python_wheels`` template figures
192out which wheels to collect by traversing the ``pw_python_package_wheels``
193`GN metadata
Rob Mohr463700d2021-05-22 10:31:03 -0700194<https://gn.googlesource.com/gn/+/HEAD/docs/reference.md#var_metadata>`_ key,
Joe Ethierfbe66152021-03-31 16:02:36 -0700195which lists the output directory for each wheel.
196
197The ``pw_mirror_tree`` template is then used to collect wheels in an output
198directory:
199
200.. code-block::
201
202 import("$dir_pw_build/mirror_tree.gni")
203
204 pw_mirror_tree("my_wheels") {
205 path_data_keys = [ "pw_python_package_wheels" ]
206 deps = [ ":python_packages.wheel" ]
207 directory = "$root_out_dir/the_wheels"
208 }
209
210pw_python_zip_with_setup
211========================
212Generates a ``.zip`` archive suitable for deployment outside of the project's
213developer environment. The generated ``.zip`` contains Python wheels
214(``.whl`` files) for one or more ``pw_python_package`` targets, plus wheels for
215any additional ``pw_python_package`` targets in the GN build they depend on,
216directly or indirectly. Dependencies from outside the GN build, such as packages
217from PyPI, must be listed in packages' ``setup.py`` files as usual.
218
219The ``.zip`` also includes simple setup scripts for Linux,
220MacOS, and Windows. The setup scripts automatically create a Python virtual
221environment and install the whole collection of wheels into it using ``pip``.
222
223Optionally, additional files and directories can be included in the archive.
224
225Arguments
226---------
227- ``packages`` - A list of `pw_python_package` targets whose wheels should be
228 included; their dependencies will be pulled in as wheels also.
229- ``inputs`` - An optional list of extra files to include in the generated
230 ``.zip``, formatted the same way as the ``inputs`` argument to ``pw_zip``
231 targets.
232- ``dirs`` - An optional list of directories to include in the generated
233 ``.zip``, formatted the same was as the ``dirs`` argument to ``pw_zip``
234 targets.
235
236Example
237-------
238
239.. code-block::
240
241 import("//build_overrides/pigweed.gni")
242
243 import("$dir_pw_build/python_dist.gni")
244
245 pw_python_zip_with_setup("my_tools") {
246 packages = [ ":some_python_package" ]
247 inputs = [ "$dir_pw_build/python_dist/README.md > /${target_name}/" ]
248 }
Anthony DiGirolamo211dce42021-08-12 16:48:43 -0700249
250pw_create_python_source_tree
251============================
252
253Generates a directory of Python packages from source files suitable for
254deployment outside of the project developer environment. The resulting directory
255contains only files mentioned in each package's ``setup.cfg`` file. This is
256useful for bundling multiple Python packages up into a single package for
257distribution to other locations like `<http://pypi.org>`_.
258
259Arguments
260---------
261
262- ``packages`` - A list of :ref:`module-pw_build-pw_python_package` targets to be installed into
263 the build directory. Their dependencies will be pulled in as wheels also.
264
265- ``include_tests`` - If true, copy Python package tests to a ``tests`` subdir.
266
267- ``extra_files`` - A list of extra files that should be included in the output.
268 The format of each item in this list follows this convention:
269
270 .. code-block:: text
271
272 //some/nested/source_file > nested/destination_file
273
274 - Source and destination file should be separated by ``>``.
275
276 - The source file should be a GN target label (starting with ``//``).
277
278 - The destination file will be relative to the generated output
279 directory. Parent directories are automatically created for each file. If a
280 file would be overwritten an error is raised.
281
282
283Example
284-------
285
286:octicon:`file;1em` ./pw_env_setup/BUILD.gn
287
288.. code-block::
289
290 import("//build_overrides/pigweed.gni")
291
292 import("$dir_pw_build/python_dist.gni")
293
294 pw_create_python_source_tree("build_python_source_tree") {
295 packages = [
296 ":some_python_package",
297 ":another_python_package",
298 ]
299 include_tests = true
300 extra_files = [
301 "//README.md > ./README.md",
302 "//some_python_package/py/BUILD.bazel > some_python_package/BUILD.bazel",
303 "//another_python_package/py/BUILD.bazel > another_python_package/BUILD.bazel",
304 ]
305 }
306
307:octicon:`file-directory;1em` ./out/obj/pw_env_setup/build_python_source_tree/
308
309.. code-block:: text
310
311 $ tree ./out/obj/pw_env_setup/build_python_source_tree/
312 ├── README.md
313 ├── some_python_package
314 │ ├── BUILD.bazel
315 │ ├── __init__.py
316 │ ├── py.typed
317 │ ├── some_source_file.py
318 │ └── tests
319 │ └── some_source_test.py
320 └── another_python_package
321 ├── BUILD.bazel
322 ├── __init__.py
323 ├── another_source_file.py
324 ├── py.typed
325 └── tests
326 └── another_source_test.py