blob: 2ae6567c401246dbee19248eb8eb6b015e1523eb [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
Joe Ethierb3ba70f2021-10-18 14:52:01 -0700173the .gni file for complete documentation on building distributables.
Joe Ethierfbe66152021-03-31 16:02:36 -0700174
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
Joe Ethierfbe66152021-03-31 16:02:36 -0700197pw_python_zip_with_setup
198========================
199Generates a ``.zip`` archive suitable for deployment outside of the project's
200developer environment. The generated ``.zip`` contains Python wheels
201(``.whl`` files) for one or more ``pw_python_package`` targets, plus wheels for
202any additional ``pw_python_package`` targets in the GN build they depend on,
203directly or indirectly. Dependencies from outside the GN build, such as packages
Joe Ethierb3ba70f2021-10-18 14:52:01 -0700204from PyPI, must be listed in packages' ``setup.py`` or ``setup.cfg`` files as
205usual.
Joe Ethierfbe66152021-03-31 16:02:36 -0700206
207The ``.zip`` also includes simple setup scripts for Linux,
208MacOS, and Windows. The setup scripts automatically create a Python virtual
209environment and install the whole collection of wheels into it using ``pip``.
210
211Optionally, additional files and directories can be included in the archive.
Joe Ethierb3ba70f2021-10-18 14:52:01 -0700212One common example of an additional file to include is a README file with setup
213and usage instructions for the distributable. A simple ready-to-use README file
214is available at ``pw_build/py_dist/README.md``.
Joe Ethierfbe66152021-03-31 16:02:36 -0700215
216Arguments
217---------
218- ``packages`` - A list of `pw_python_package` targets whose wheels should be
219 included; their dependencies will be pulled in as wheels also.
220- ``inputs`` - An optional list of extra files to include in the generated
221 ``.zip``, formatted the same way as the ``inputs`` argument to ``pw_zip``
222 targets.
223- ``dirs`` - An optional list of directories to include in the generated
224 ``.zip``, formatted the same was as the ``dirs`` argument to ``pw_zip``
225 targets.
226
227Example
228-------
229
230.. code-block::
231
232 import("//build_overrides/pigweed.gni")
233
234 import("$dir_pw_build/python_dist.gni")
235
236 pw_python_zip_with_setup("my_tools") {
237 packages = [ ":some_python_package" ]
238 inputs = [ "$dir_pw_build/python_dist/README.md > /${target_name}/" ]
239 }
Anthony DiGirolamo211dce42021-08-12 16:48:43 -0700240
241pw_create_python_source_tree
242============================
243
244Generates a directory of Python packages from source files suitable for
245deployment outside of the project developer environment. The resulting directory
246contains only files mentioned in each package's ``setup.cfg`` file. This is
247useful for bundling multiple Python packages up into a single package for
248distribution to other locations like `<http://pypi.org>`_.
249
250Arguments
251---------
252
253- ``packages`` - A list of :ref:`module-pw_build-pw_python_package` targets to be installed into
254 the build directory. Their dependencies will be pulled in as wheels also.
255
256- ``include_tests`` - If true, copy Python package tests to a ``tests`` subdir.
257
258- ``extra_files`` - A list of extra files that should be included in the output.
259 The format of each item in this list follows this convention:
260
261 .. code-block:: text
262
263 //some/nested/source_file > nested/destination_file
264
265 - Source and destination file should be separated by ``>``.
266
267 - The source file should be a GN target label (starting with ``//``).
268
269 - The destination file will be relative to the generated output
270 directory. Parent directories are automatically created for each file. If a
271 file would be overwritten an error is raised.
272
Anthony DiGirolamob4517c32021-09-20 15:49:55 -0700273- ``generate_setup_cfg`` - If included, create a merged ``setup.cfg`` for all
274 python Packages using a ``common_config_file`` as a base. That file should
275 contain the required fields in the ``metadata`` and ``options`` sections as
276 shown in
277 `Configuring setup() using setup.cfg files <https://setuptools.pypa.io/en/latest/userguide/declarative_config.html>`_.
278 ``append_git_sha_to_version`` and ``append_date_to_version`` will optionally
279 append the current git SHA or date to the package version string after a ``+``
280 sign.
281
282 .. code-block::
283
284 generate_setup_cfg = {
285 common_config_file = "pypi_common_setup.cfg"
286 append_git_sha_to_version = true
287 append_date_to_version = true
288 }
Anthony DiGirolamo211dce42021-08-12 16:48:43 -0700289
290Example
291-------
292
293:octicon:`file;1em` ./pw_env_setup/BUILD.gn
294
295.. code-block::
296
297 import("//build_overrides/pigweed.gni")
298
299 import("$dir_pw_build/python_dist.gni")
300
301 pw_create_python_source_tree("build_python_source_tree") {
302 packages = [
303 ":some_python_package",
304 ":another_python_package",
305 ]
306 include_tests = true
307 extra_files = [
308 "//README.md > ./README.md",
309 "//some_python_package/py/BUILD.bazel > some_python_package/BUILD.bazel",
310 "//another_python_package/py/BUILD.bazel > another_python_package/BUILD.bazel",
311 ]
Anthony DiGirolamob4517c32021-09-20 15:49:55 -0700312 generate_setup_cfg = {
313 common_config_file = "pypi_common_setup.cfg"
314 append_git_sha_to_version = true
315 append_date_to_version = true
316 }
Anthony DiGirolamo211dce42021-08-12 16:48:43 -0700317 }
318
319:octicon:`file-directory;1em` ./out/obj/pw_env_setup/build_python_source_tree/
320
321.. code-block:: text
322
323 $ tree ./out/obj/pw_env_setup/build_python_source_tree/
324 ├── README.md
Anthony DiGirolamob4517c32021-09-20 15:49:55 -0700325 ├── setup.cfg
Anthony DiGirolamo211dce42021-08-12 16:48:43 -0700326 ├── some_python_package
327 │ ├── BUILD.bazel
328 │ ├── __init__.py
329 │ ├── py.typed
330 │ ├── some_source_file.py
331 │ └── tests
332 │ └── some_source_test.py
333 └── another_python_package
334 ├── BUILD.bazel
335 ├── __init__.py
336 ├── another_source_file.py
337 ├── py.typed
338 └── tests
339 └── another_source_test.py