Wyatt Hepler | b3ea980 | 2021-02-23 09:46:09 -0800 | [diff] [blame] | 1 | .. _module-pw_build-python: |
| 2 | |
| 3 | ------------------- |
| 4 | Python GN templates |
| 5 | ------------------- |
| 6 | The Python build is implemented with GN templates defined in |
Joe Ethier | fbe6615 | 2021-03-31 16:02:36 -0700 | [diff] [blame] | 7 | ``pw_build/python.gni``. See the .gni file for complete usage documentation. |
Wyatt Hepler | b3ea980 | 2021-02-23 09:46:09 -0800 | [diff] [blame] | 8 | |
| 9 | .. seealso:: :ref:`docs-python-build` |
| 10 | |
| 11 | pw_python_package |
| 12 | ================= |
| 13 | The main Python template is ``pw_python_package``. Each ``pw_python_package`` |
| 14 | target represents a Python package. As described in |
| 15 | :ref:`module-pw_build-python-target`, each ``pw_python_package`` expands to |
| 16 | several subtargets. In summary, these are: |
| 17 | |
| 18 | - ``<name>`` - Represents the files themselves |
| 19 | - ``<name>.lint`` - Runs static analysis |
| 20 | - ``<name>.tests`` - Runs all tests for this package |
| 21 | - ``<name>.install`` - Installs the package |
| 22 | - ``<name>.wheel`` - Builds a Python wheel |
| 23 | |
Wyatt Hepler | b85cda4 | 2021-04-07 13:13:15 -0700 | [diff] [blame] | 24 | GN permits using abbreviated labels when the target name matches the directory |
| 25 | name (e.g. ``//foo`` for ``//foo:foo``). For consistency with this, Python |
| 26 | package subtargets are aliased to the directory when the target name is the |
| 27 | same as the directory. For example, these two labels are equivalent: |
| 28 | |
| 29 | .. code-block:: |
| 30 | |
| 31 | //path/to/my_python_package:my_python_package.tests |
| 32 | //path/to/my_python_package:tests |
| 33 | |
Wyatt Hepler | f6f74f4 | 2021-04-13 19:26:20 -0700 | [diff] [blame] | 34 | The actions in a ``pw_python_package`` (e.g. installing packages and running |
| 35 | Pylint) are done within a single GN toolchain to avoid duplication in |
| 36 | multi-toolchain builds. This toolchain can be set with the |
Joe Ethier | fbe6615 | 2021-03-31 16:02:36 -0700 | [diff] [blame] | 37 | ``pw_build_PYTHON_TOOLCHAIN`` GN arg, which defaults to |
| 38 | ``$dir_pw_build/python_toolchain:python``. |
Wyatt Hepler | f6f74f4 | 2021-04-13 19:26:20 -0700 | [diff] [blame] | 39 | |
Wyatt Hepler | b3ea980 | 2021-02-23 09:46:09 -0800 | [diff] [blame] | 40 | Arguments |
| 41 | --------- |
| 42 | - ``setup`` - List of setup file paths (setup.py or pyproject.toml & setup.cfg), |
| 43 | which must all be in the same directory. |
Wyatt Hepler | b85cda4 | 2021-04-07 13:13:15 -0700 | [diff] [blame] | 44 | - ``generate_setup``: As an alternative to ``setup``, generate setup files with |
Anthony DiGirolamo | afb861c | 2021-08-12 16:48:04 -0700 | [diff] [blame^] | 45 | the keywords in this scope. ``name`` is required. This follows the same |
| 46 | structure as a ``setup.cfg`` file's `declarative config |
| 47 | <https://setuptools.readthedocs.io/en/latest/userguide/declarative_config.html>`_ |
| 48 | For example: |
Wyatt Hepler | b85cda4 | 2021-04-07 13:13:15 -0700 | [diff] [blame] | 49 | |
| 50 | .. code-block:: |
| 51 | |
| 52 | generate_setup = { |
Anthony DiGirolamo | afb861c | 2021-08-12 16:48:04 -0700 | [diff] [blame^] | 53 | metadata = { |
| 54 | name = "a_nifty_package" |
| 55 | version = "1.2a" |
| 56 | } |
| 57 | options = { |
| 58 | install_requires = [ "a_pip_package" ] |
| 59 | } |
Wyatt Hepler | b85cda4 | 2021-04-07 13:13:15 -0700 | [diff] [blame] | 60 | } |
| 61 | |
Wyatt Hepler | b3ea980 | 2021-02-23 09:46:09 -0800 | [diff] [blame] | 62 | - ``sources`` - Python sources files in the package. |
| 63 | - ``tests`` - Test files for this Python package. |
| 64 | - ``python_deps`` - Dependencies on other pw_python_packages in the GN build. |
| 65 | - ``python_test_deps`` - Test-only pw_python_package dependencies. |
| 66 | - ``other_deps`` - Dependencies on GN targets that are not pw_python_packages. |
| 67 | - ``inputs`` - Other files to track, such as package_data. |
Wyatt Hepler | dcfcecf | 2021-03-01 08:36:19 -0800 | [diff] [blame] | 68 | - ``proto_library`` - A pw_proto_library target to embed in this Python package. |
Wyatt Hepler | b85cda4 | 2021-04-07 13:13:15 -0700 | [diff] [blame] | 69 | ``generate_setup`` is required in place of setup if proto_library is used. See |
Wyatt Hepler | dcfcecf | 2021-03-01 08:36:19 -0800 | [diff] [blame] | 70 | :ref:`module-pw_protobuf_compiler-add-to-python-package`. |
Wyatt Hepler | c2ce524 | 2021-03-17 08:42:14 -0700 | [diff] [blame] | 71 | - ``static_analysis`` List of static analysis tools to run; ``"*"`` (default) |
| 72 | runs all tools. The supported tools are ``"mypy"`` and ``"pylint"``. |
Wyatt Hepler | b3ea980 | 2021-02-23 09:46:09 -0800 | [diff] [blame] | 73 | - ``pylintrc`` - Optional path to a pylintrc configuration file to use. If not |
| 74 | provided, Pylint's default rcfile search is used. Pylint is executed |
| 75 | from the package's setup directory, so pylintrc files in that directory |
| 76 | will take precedence over others. |
| 77 | - ``mypy_ini`` - Optional path to a mypy configuration file to use. If not |
| 78 | provided, mypy's default configuration file search is used. mypy is |
| 79 | executed from the package's setup directory, so mypy.ini files in that |
| 80 | directory will take precedence over others. |
| 81 | |
| 82 | Example |
| 83 | ------- |
| 84 | This is an example Python package declaration for a ``pw_my_module`` module. |
| 85 | |
| 86 | .. code-block:: |
| 87 | |
| 88 | import("//build_overrides/pigweed.gni") |
| 89 | |
| 90 | import("$dir_pw_build/python.gni") |
| 91 | |
| 92 | pw_python_package("py") { |
| 93 | setup = [ "setup.py" ] |
| 94 | sources = [ |
| 95 | "pw_my_module/__init__.py", |
| 96 | "pw_my_module/alfa.py", |
| 97 | "pw_my_module/bravo.py", |
| 98 | "pw_my_module/charlie.py", |
| 99 | ] |
| 100 | tests = [ |
| 101 | "alfa_test.py", |
| 102 | "charlie_test.py", |
| 103 | ] |
| 104 | python_deps = [ |
| 105 | "$dir_pw_status/py", |
| 106 | ":some_protos.python", |
| 107 | ] |
| 108 | python_test_deps = [ "$dir_pw_build/py" ] |
| 109 | pylintrc = "$dir_pigweed/.pylintrc" |
| 110 | } |
| 111 | |
| 112 | pw_python_script |
| 113 | ================ |
| 114 | A ``pw_python_script`` represents a set of standalone Python scripts and/or |
| 115 | tests. These files support all of the arguments of ``pw_python_package`` except |
| 116 | those ``setup``. These targets can be installed, but this only installs their |
| 117 | dependencies. |
| 118 | |
Wyatt Hepler | 473efe0 | 2021-05-04 14:15:16 -0700 | [diff] [blame] | 119 | ``pw_python_script`` allows creating a |
| 120 | :ref:`pw_python_action <module-pw_build-python-action>` associated with the |
| 121 | script. To create an action, pass an ``action`` scope to ``pw_python_script``. |
| 122 | If there is only a single source file, it serves as the action's ``script`` by |
| 123 | default. |
| 124 | |
| 125 | An action in ``pw_python_script`` can always be replaced with a standalone |
| 126 | ``pw_python_action``, but using the embedded action has some advantages: |
| 127 | |
| 128 | - The embedded action target bridges the gap between actions and Python targets. |
| 129 | A Python script can be expressed in a single, concise GN target, rather than |
| 130 | in two overlapping, dependent targets. |
| 131 | - The action automatically depends on the ``pw_python_script``. This ensures |
| 132 | that the script's dependencies are installed and the action automatically |
| 133 | reruns when the script's sources change, without needing to specify a |
| 134 | dependency, a step which is easy to forget. |
| 135 | - Using a ``pw_python_script`` with an embedded action is a simple way to check |
| 136 | an existing action's script with Pylint or Mypy or to add tests. |
| 137 | |
Wyatt Hepler | b3ea980 | 2021-02-23 09:46:09 -0800 | [diff] [blame] | 138 | pw_python_group |
| 139 | =============== |
| 140 | Represents a group of ``pw_python_package`` and ``pw_python_script`` targets. |
| 141 | These targets do not add any files. Their subtargets simply forward to those of |
| 142 | their dependencies. |
| 143 | |
Wyatt Hepler | b3ea980 | 2021-02-23 09:46:09 -0800 | [diff] [blame] | 144 | pw_python_requirements |
| 145 | ====================== |
| 146 | Represents a set of local and PyPI requirements, with no associated source |
| 147 | files. These targets serve the role of a ``requirements.txt`` file. |
Joe Ethier | fbe6615 | 2021-03-31 16:02:36 -0700 | [diff] [blame] | 148 | |
Michael Spang | 01faaf7 | 2021-06-09 22:38:40 -0400 | [diff] [blame] | 149 | When packages are installed by Pigweed, additional version constraints can be |
| 150 | provided using the ``pw_build_PIP_CONSTRAINTS`` GN arg. This option should |
| 151 | contain a list of paths to pass to the ``--constraint`` option of ``pip |
| 152 | install``. This can be used to synchronize dependency upgrades across a project |
| 153 | which facilitates reproducibility of builds. |
| 154 | |
| 155 | Note using multiple ``pw_python_requirements`` that install different versions |
| 156 | of the same package will currently cause unpredictable results, while using |
| 157 | constraints should have correct results (which may be an error indicating a |
| 158 | conflict). |
| 159 | |
Joe Ethier | fbe6615 | 2021-03-31 16:02:36 -0700 | [diff] [blame] | 160 | .. _module-pw_build-python-dist: |
| 161 | |
| 162 | --------------------- |
| 163 | Python distributables |
| 164 | --------------------- |
| 165 | Pigweed also provides some templates to make it easier to bundle Python packages |
| 166 | for deployment. These templates are found in ``pw_build/python_dist.gni``. See |
| 167 | the .gni file for complete usage doclumentation. |
| 168 | |
| 169 | pw_python_wheels |
| 170 | ================ |
| 171 | Collects Python wheels for one or more ``pw_python_package`` targets, plus any |
| 172 | additional ``pw_python_package`` targets they depend on, directly or indirectly. |
| 173 | Note that this does not include Python dependencies that come from outside the |
| 174 | GN build, like packages from PyPI, for example. Those should still be declared |
| 175 | in the package's ``setup.py`` file as usual. |
| 176 | |
| 177 | Arguments |
| 178 | --------- |
| 179 | - ``packages`` - List of ``pw_python_package`` targets whose wheels should be |
| 180 | included; their dependencies will be pulled in as wheels also. |
| 181 | |
| 182 | Wheel collection under the hood |
| 183 | ------------------------------- |
| 184 | The ``.wheel`` subtarget of every ``pw_python_package`` generates a wheel |
| 185 | (``.whl``) for the Python package. The ``pw_python_wheels`` template figures |
| 186 | out which wheels to collect by traversing the ``pw_python_package_wheels`` |
| 187 | `GN metadata |
Rob Mohr | 463700d | 2021-05-22 10:31:03 -0700 | [diff] [blame] | 188 | <https://gn.googlesource.com/gn/+/HEAD/docs/reference.md#var_metadata>`_ key, |
Joe Ethier | fbe6615 | 2021-03-31 16:02:36 -0700 | [diff] [blame] | 189 | which lists the output directory for each wheel. |
| 190 | |
| 191 | The ``pw_mirror_tree`` template is then used to collect wheels in an output |
| 192 | directory: |
| 193 | |
| 194 | .. code-block:: |
| 195 | |
| 196 | import("$dir_pw_build/mirror_tree.gni") |
| 197 | |
| 198 | pw_mirror_tree("my_wheels") { |
| 199 | path_data_keys = [ "pw_python_package_wheels" ] |
| 200 | deps = [ ":python_packages.wheel" ] |
| 201 | directory = "$root_out_dir/the_wheels" |
| 202 | } |
| 203 | |
| 204 | pw_python_zip_with_setup |
| 205 | ======================== |
| 206 | Generates a ``.zip`` archive suitable for deployment outside of the project's |
| 207 | developer environment. The generated ``.zip`` contains Python wheels |
| 208 | (``.whl`` files) for one or more ``pw_python_package`` targets, plus wheels for |
| 209 | any additional ``pw_python_package`` targets in the GN build they depend on, |
| 210 | directly or indirectly. Dependencies from outside the GN build, such as packages |
| 211 | from PyPI, must be listed in packages' ``setup.py`` files as usual. |
| 212 | |
| 213 | The ``.zip`` also includes simple setup scripts for Linux, |
| 214 | MacOS, and Windows. The setup scripts automatically create a Python virtual |
| 215 | environment and install the whole collection of wheels into it using ``pip``. |
| 216 | |
| 217 | Optionally, additional files and directories can be included in the archive. |
| 218 | |
| 219 | Arguments |
| 220 | --------- |
| 221 | - ``packages`` - A list of `pw_python_package` targets whose wheels should be |
| 222 | included; their dependencies will be pulled in as wheels also. |
| 223 | - ``inputs`` - An optional list of extra files to include in the generated |
| 224 | ``.zip``, formatted the same way as the ``inputs`` argument to ``pw_zip`` |
| 225 | targets. |
| 226 | - ``dirs`` - An optional list of directories to include in the generated |
| 227 | ``.zip``, formatted the same was as the ``dirs`` argument to ``pw_zip`` |
| 228 | targets. |
| 229 | |
| 230 | Example |
| 231 | ------- |
| 232 | |
| 233 | .. code-block:: |
| 234 | |
| 235 | import("//build_overrides/pigweed.gni") |
| 236 | |
| 237 | import("$dir_pw_build/python_dist.gni") |
| 238 | |
| 239 | pw_python_zip_with_setup("my_tools") { |
| 240 | packages = [ ":some_python_package" ] |
| 241 | inputs = [ "$dir_pw_build/python_dist/README.md > /${target_name}/" ] |
| 242 | } |