Merge pull request #17303 from CarlosDerSeher/feature_bt_agent
[feed/packages.git] / lang / python / README.md
1 # Python packages folder
2
3 ## Table of contents
4
5 1. [Description](#description)
6 2. [Introduction](#introduction)
7 3. [Python 2 end-of-life](#python-2-end-of-life)
8 4. [Using Python in external/other package feeds](#using-python-in-externalother-package-feeds)
9 5. [Build considerations](#build-considerations)
10 6. [General folder structure](#general-folder-structure)
11 7. [Building a Python package](#building-a-python-package)
12 1. [Include python3-package.mk](#include-python3-packagemk)
13 2. [Add Package/<PKG_NAME> OpenWrt definitions](#add-packagepkg_name-openwrt-definitions)
14 3. [Python package dependencies](#python-package-dependencies)
15 4. [Wrapping things up so that they build](#wrapping-things-up-so-that-they-build)
16 5. [Customizing things](#customizing-things)
17 6. [Host-side Python packages for build](#host-side-python-packages-for-build)
18
19 ## Description
20
21 This section describes specifics for the Python packages that are present in this repo, and how things are structured.
22
23 In terms of license, contributing guide, etc, all of that information is described in the top [README.md](../../README.md) file, and it applies here as well. This document attempts to cover only technical aspects of Python packages, and maybe some explanations about how things are (and why they are as they are).
24
25 ## Introduction
26
27 This sub-tree came to exist after a number of contributions (Python packages) were made to this repo, and the [lang](../) subtree grew to a point where a decision was made to move all Python packages under [lang/python](./).
28
29 It contains the Python 3 interpreter and Python packages. Most of the Python packages are downloaded from [pypi.org](https://pypi.org/). Python packages from pypi.org are typically preferred when adding new packages.
30
31 If more packages (than the ones packaged here) are needed, they can be downloaded via [pip](https://pip.pypa.io). Note that the versions of `pip` & `setuptools` [available in this repo] are the ones that are packaged inside the Python package (yes, Python comes packaged with `pip` & `setuptools`).
32
33 ## Python 2 end-of-life
34
35 Python 2 [will not be maintained past 2020](https://www.python.org/dev/peps/pep-0373/). All Python 2 packages have been removed from the packages feed (this repo) and archived in the [abandoned packages feed](https://github.com/openwrt/packages-abandoned).
36
37 ## Using Python in external/other package feeds
38
39 In the feeds.conf (or feeds.conf.default file, whatever is preferred), the packages repo should be present.
40
41 Example
42 ```
43 src-git packages https://git.openwrt.org/feed/packages.git
44 src-git luci https://git.openwrt.org/project/luci.git
45 src-git routing https://git.openwrt.org/feed/routing.git
46 src-git telephony https://git.openwrt.org/feed/telephony.git
47 #
48 #
49 src-git someotherfeed https://github.com/<github-user>/<some-other-package>
50 ```
51
52 Assuming that there are Python packages in the `<some-other-package>`, they should include `python3-package.mk` like this:
53 ```
54 include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk
55 ```
56
57 Same rules apply for `python3-package.mk` as the Python packages in this repo.
58
59 **One important consideration:**: if the local name is not `packages`, it's something else, like `openwrt-packages`. And in `feeds.conf[.default]` it's:
60 ```
61 src-git openwrt-packages https://git.openwrt.org/feed/packages.git
62 ```
63
64 Then, the inclusions also change:
65 ```
66 include $(TOPDIR)/feeds/openwrt-packages/lang/python/python3-package.mk
67 ```
68
69 Each maintainer[s] of external packages feeds is responsible for the local name, and relative inclusion path back to this feed (which is named `packages` by default).
70
71 In case there is a need/requirement such that the local package feed is named something else than `packages`, one approach to make the package flexible to change is:
72
73 ```
74 PYTHON3_PACKAGE_MK:=$(wildcard $(TOPDIR)/feeds/*/lang/python/python3-package.mk)
75
76 # verify that there is only one single file returned
77 ifneq (1,$(words $(PYTHON3_PACKAGE_MK)))
78 ifeq (0,$(words $(PYTHON3_PACKAGE_MK)))
79 $(error did not find python3-package.mk in any feed)
80 else
81 $(error found multiple python3-package.mk files in the feeds)
82 endif
83 else
84 $(info found python3-package.mk at $(PYTHON3_PACKAGE_MK))
85 endif
86
87 include $(PYTHON3_PACKAGE_MK)
88 ```
89
90 This should solve the corner-case where the `python3-package.mk` can be in some other feed, or if the packages feed will be named something else locally.
91
92 ## Build considerations
93
94 In order to build the Python interpreter, a host Python interpreter needs to be built, in order to process some of the build for the target Python build. The host Python interpreter is also needed so that Python bytecodes are generated, so the host interpreter needs to be the exact version as on the target. And finally, the host Python interpreter also provides pip, so that it may be used to install some Python packages that are required to build other Python packages.
95 That's why you'll also see a Python build & staging directories.
96
97 As you're probably thinking, this sounds [and is] somewhat too much complication [just for packaging], but the status of things is-as-it-is, and it's probably much worse than what's currently visible on the surface [with respect to packaging Python & packages].
98
99 As mentioned earlier, Python packages are shipped with bytecodes, and the reason for this is simply performance & size.
100 The thought/discussion matrix derives a bit like this:
101 * shipping both Python source-code & bytecodes takes too much space on some devices ; Python source code & byte-code take about similar disk-size
102 * shipping only Python source code has a big performance penalty [on some lower end systems] ; something like 500 msecs (Python source-only) -> 70 msecs (Python byte-codes) time reduction for a simple "Hello World" script
103 * shipping only Python byte-codes seems like a good trade-off, and this means that `python3-src` can be provided for people that want the source code
104
105 By default, automatic Python byte-code generation is disabled when running a Python script, in order to prevent a disk from accidentally filling up. Since some disks reside in RAM, this also means not filling up the RAM. If someone wants to convert Python source to byte-code then he/she is free to compile it [directly on the device] manually via the Python interpreter & library.
106
107 ## General folder structure
108
109 The basis of all these packages is:
110 * [lang/python/python3](./python3) - The Python 3.x.y interpreter
111
112 This is a normal OpenWrt package, which will build the Python interpreter. This also provides `python3-pip` & `python3-setuptools`. Each Python package is actually split into multiple sub-packages [e.g. python3-email, python3-sqlite3, etc]. This can be viewed inside [lang/python/python3/files](./python3/files).
113
114 The reason for this splitting, is purely to offer a way for some people to package Python in as-minimal-as-possible-and-still-runable way, and also to be somewhat maintainable when packaging. A standard Python installation can take ~20-30 MBs of disk, which can be somewhat big for some people, so there is the `python3-base` package which brings that down to ~5 MBs. This seems to be good enough (and interesting) for a number of people.
115
116 The Python interpreter is structured like this:
117 * `python3-base`, which is just the minimal package to startup Python and run basic commands
118 * `python3` is a meta-package, which installs almost everything (python3-base [plus] Python library [minus] some unit-tests & some windows-y things)
119 * `python3-light` is `python3` [minus] packages that are in [lang/python/python3/files](./python3/files) ; the size of this package may be sensible (and interesting) to another group of people
120
121 All other Python packages (aside from the intepreter) typically use these files:
122 * **python3-host.mk** - this file contains paths and build rules for running the Python interpreter on the host-side; they also provide paths to host interprete, host Python lib-dir & so on
123 * **python3-package.mk**
124 * includes **python3-host.mk**
125 * contains all the default build rules for Python packages; these will be detailed below in the [Building a Python package](#building-a-python-package) section
126
127 **Note** that Python packages don't need to use these files (i.e. `python3-package.mk` & `python3-host.mk`), but they do provide some ease-of-use & reduction of duplicate code. And they do contain some learned-lessons about packaging Python packages, so it's a good idea to use them.
128
129 ## Building a Python package
130
131 ### Include python3-package.mk
132
133 Add this after `include $(INCLUDE_DIR)/package.mk`
134 ```
135 include ../python3-package.mk
136 ```
137
138 This will make sure that build rules for Python can be specified and picked up for build.
139
140 ### Include pypi.mk (optional)
141
142 `pypi.mk` is an include file that makes downloading package source code from [pypi.org](https://pypi.org/) simpler.
143
144 To use `pypi.mk`, add this **before** `include $(INCLUDE_DIR)/package.mk`:
145 ```
146 include ../pypi.mk
147 ```
148
149 `pypi.mk` has several `PYPI_*` variables that can/must be set (see below); these should be set before `pypi.mk` is included, i.e. before the `include ../pypi.mk` line.
150
151 `pypi.mk` also provides default values for `PKG_SOURCE` and `PKG_SOURCE_URL`, so these variables may be omitted.
152
153 Required variables:
154
155 * `PYPI_NAME`: Package name on pypi.org. This should match the PyPI name exactly.
156
157 For example (from the `python-yaml` package):
158 ```
159 PYPI_NAME:=PyYAML
160 ```
161
162 Optional variables:
163
164 * `PYPI_SOURCE_NAME`: Package name component of the source tarball filename
165 Default: Same value as `PYPI_NAME`
166
167 * `PYPI_SOURCE_EXT`: File extension of the source tarball filename
168 Default: `tar.gz`
169
170 `pypi.mk` constructs the default `PKG_SOURCE` value from these variables (and `PKG_VERSION`):
171 ```
172 PKG_SOURCE?=$(PYPI_SOURCE_NAME)-$(PKG_VERSION).$(PYPI_SOURCE_EXT)
173 ```
174
175 ### Add Package/<PKG_NAME> OpenWrt definitions
176
177 This part is similar to default OpenWrt packages.
178
179 Example:
180 ```
181 define Package/python3-lxml
182 SECTION:=lang
183 CATEGORY:=Languages
184 SUBMENU:=Python
185 TITLE:=Pythonic XML processing library
186 URL:=https://lxml.de
187 DEPENDS:=+python3-light +libxml2 +libxslt +libexslt
188 endef
189
190 define Package/python3-lxml/description
191 The lxml XML toolkit is a Pythonic binding
192 for the C libraries libxml2 and libxslt.
193 endef
194 ```
195
196 Some considerations here (based on the example above):
197 * typically the package is named `Package/python3-<something>` ; this convention makes things easier to follow, though it could work without naming things this way
198 * `TITLE` can be something a bit more verbose/neat ; typically the name is short as seen above
199
200 ### Python package dependencies
201
202 Aside from other libraries and programs, every Python package will depend on at least one of these three types of packages:
203
204 * The Python interpreter: All Python packages should depend on one of these three interpreter packages:
205
206 * `python3-light` is the best default for most Python packages.
207
208 * `python3-base` should only be used as a dependency if you are certain the bare interpreter is sufficient.
209
210 * `python3` is useful if many (more than three) Python standard library packages are needed.
211
212 * Python standard library packages: As noted above, many parts of the Python standard library are packaged separate from the Python interpreter. These packages are defined by the files in [lang/python/python3/files](./python3/files).
213
214 To find out which of these separate standard library packages are necessary, after completing a draft Makefile (including the `$(eval ...)` lines described in the next section), run `make` with the `configure` target and `PY3=stdlib V=s` in the command line. For example:
215
216 ```
217 make package/python-lxml/configure PY3=stdlib V=s
218 ```
219
220 If the package has been built previously, include the `clean` target to trigger configure again:
221
222 ```
223 make package/python-lxml/{clean,configure} PY3=stdlib V=s
224 ```
225
226 This will search the package for module imports and generate a list of suggested dependencies. Some of the found imports may be false positives, e.g. in example or test files, so examine the matches for more information.
227
228 * Other Python packages: The easiest way to find these dependencies is to look for the `install_requires` keyword inside the package's `setup.py` file (it will be a keyword argument to the `setup()` function). This will be a list of run-time dependencies for the package.
229
230 There may already be packages in the packages feed that provide these dependencies. If not, they will need to be packaged for your Python package to function correctly.
231
232 Any packages in a `setup_requires` keyword argument are build-time dependencies that may need to be installed on the host (host Python inside of OpenWrt buildroot, not system Python that is part of the outer computer system). To ensure these build-time dependencies are present, see [Host-side Python packages for build](#host-side-python-packages-for-build). (Note that Setuptools is already installed as part of host Python.)
233
234 ### Wrapping things up so that they build
235
236 If all the above prerequisites have been met, all that's left is:
237
238 ```
239 $(eval $(call Py3Package,python3-lxml))
240 $(eval $(call BuildPackage,python3-lxml))
241 ```
242
243 The `$(eval $(call Py3Package,python3-lxml))` part will instantiate all the default Python build rules so that the final Python package is packaged into an OpenWrt.
244 And `$(eval $(call BuildPackage,python3-lxml))` will bind all the rules generated with `$(eval $(call Py3Package,python3-lxml))` into the OpenWrt build system.
245
246 These packages will contain byte-codes and binaries (shared libs & other stuff).
247
248 If a user wishes to ship source code, adding one more line creates one more package that ship Python source code:
249 ```
250 $(eval $(call Py3Package,python3-lxml))
251 $(eval $(call BuildPackage,python3-lxml))
252 $(eval $(call BuildPackage,python3-lxml-src))
253 ```
254
255 The name `*-src` must be the Python package name; so for `python3-lxml-src` a equivalent `python3-lxml` name must exist.
256
257 ### Customizing things
258
259 Some packages need custom build rules (because they do).
260
261 The default package build and install processes are defined in `python3-package.mk`.
262
263 #### Building
264
265 The default build process calls `setup.py install` inside the directory where the Python source package is extracted (`PKG_BUILD_DIR`). This "installs" the Python package to an intermediate location (`PKG_INSTALL_DIR`) where it is used by the default install process.
266
267 There are several Makefile variables that can be used to customize this process (all optional):
268
269 * `PYTHON3_PKG_SETUP_DIR`: Path where `setup.py` can be found, relative to the package directory (`PKG_BUILD_DIR`).
270 Default: empty value (`setup.py` is in the package directory)
271 * `PYTHON3_PKG_SETUP_VARS`: Additional environment variables to set for the call to `setup.py`. Should be in the form of `VARIABLE1=value VARIABLE2=value ...`.
272 Default: empty value
273 * `PYTHON3_PKG_SETUP_GLOBAL_ARGS`: Additional command line arguments to pass to `setup.py`, before / in front of the `install` command.
274 Default: empty value
275 * `PYTHON3_PKG_SETUP_ARGS`: Additional command line arguments to pass to `setup.py`, after the `install` command.
276 Default: `--single-version-externally-managed`
277
278 Conceptually, these variables are used in this way:
279
280 ```
281 cd $(PKG_BUILD_DIR)/$(PYTHON3_PKG_SETUP_DIR)
282 $(PYTHON3_PKG_SETUP_VARS) python3 setup.py $(PYTHON3_PKG_SETUP_GLOBAL_ARGS) install $(PYTHON3_PKG_SETUP_ARGS)
283 ```
284
285 The default build process can be completely overridden by defining a custom `Py3Build/Compile` rule in the package Makefile.
286
287 #### Installing
288
289 The default install process copies some/all of the files from `PKG_INSTALL_DIR`, placed there by the build process, to a location passed to the install rule as the first argument (`$(1)`). The OpenWrt build system will then take those files and create the actual .ipk package archives.
290
291 This default process uses 2 build rules:
292 * `Py3Package/<package>/filespec` which are Python library files relative to `/usr/lib/pythonX.Y` ; by default this is `/usr/lib/python$(PYTHON3_VERSION)/site-packages` (`PYTHON3_PKG_DIR`) ; most Python packages generate files that get installed in this sub-folder
293 * `Py3Package/<package>/install` is similar to `Package/<package>/install` ; this allows binary (or other files) to be installed on the target
294
295 Both the 2 above rules generate a `Package/<package>/install` build rule, which gets picked up by the build system. Both can be used together (they are not mutually exclusive), and provide a good enough flexibility for specifying Python packages.
296
297 The `Py3Package/<package>/filespec` rule contains one or more lines of the following format (whitespace added for clarity):
298
299 ```
300 <one of: +-=> | <file/directory path> | <file permissions>
301 ```
302
303 The initial character controls the action that will be taken:
304
305 * `+`: Install the given path. If the path is a directory, all files and subdirectories inside are installed.
306 * If file permissions is specified (optional), then the file or directory (and all files and subdirectories) are assigned the given permissions; if omitted, then the file or directory retains its original permissions.
307 * `-`: Remove the given path. Useful when most of a directory should be installed except for a few files or subdirectories.
308 * File permissions is not used / ignored in this case.
309 * `=`: Assign the given file permissions to the given path. File permissions is required in this case.
310
311 As mentioned, the default `Py3Package/<package>/filespec` installs `PYTHON3_PKG_DIR`:
312
313 ```
314 define Py3Package/python3-example/filespec
315 +|$(PYTHON3_PKG_DIR)
316 endef
317 ```
318
319 If the package installs a `example_package` directory inside `PYTHON3_PKG_DIR`, and there is an `examples` directory and `test_*.py` files that can be omitted to save space, this can be specified as:
320
321 ```
322 define Py3Package/python3-example/filespec
323 +|$(PYTHON3_PKG_DIR)
324 -|$(PYTHON3_PKG_DIR)/example_package/examples
325 -|$(PYTHON3_PKG_DIR)/example_package/test_*.py
326 endef
327 ```
328
329 ### Host-side Python packages for build
330
331 These can be installed via pip and ideally they should only be installed like this, because it's a bit simpler than running them through the OpenWrt build system.
332
333 #### Requirements files
334
335 All host-side Python packages are installed with pip using [requirements files](https://pip.pypa.io/en/stable/user_guide/#requirements-files), with [hash-checking mode](https://pip.pypa.io/en/stable/reference/pip_install/#hash-checking-mode) enabled. These requirements files are stored in the [host-pip-requirements](./host-pip-requirements) directory.
336
337 Each requirements file is named after the Python package it installs and contains the package's pinned version and `--hash` option. The `--hash` option value is the SHA256 hash of the package's source tarball; this value can be found on [pypi.org](https://pypi.org/).
338
339 For example, the requirements file for setuptools-scm ([setuptools-scm.txt](./host-pip-requirements/setuptools-scm.txt)) contains:
340
341 ```
342 setuptools-scm==4.1.2 --hash=sha256:a8994582e716ec690f33fec70cca0f85bd23ec974e3f783233e4879090a7faa8
343 ```
344
345 If the Python package to be installed depends on other Python packages, those dependencies, with their pinned versions and `--hash` options, also need to be specified in the requirements file. For instance, [cffi.txt](./host-pip-requirements/cffi.txt) includes information for pycparser because pycparser is a dependency of cffi and will be installed with cffi.
346
347 There are two types of requirements files in [host-pip-requirements](./host-pip-requirements):
348
349 * Installs the latest version of a Python package.
350
351 A requirements file of this type is named with the package name only (for example, [setuptools-scm.txt](./host-pip-requirements/setuptools-scm.txt)) and is used when there is no strict version requirement.
352
353 These files will be updated as newer versions of the Python packages are available.
354
355 * Installs a specific version of a Python package.
356
357 A requirements file of this type is named with the package name and version number (for example, [Django-1.11.txt](./host-pip-requirements/Django-1.11.txt)) and is used when a specific (usually older) version is required.
358
359 Installing the latest versions of packages is preferred over specific versions whenever possible.
360
361 #### Installing host-side Python packages
362
363 Set `HOST_PYTHON3_PACKAGE_BUILD_DEPENDS` to the names of one or more requirements files in [host-pip-requirements](./host-pip-requirements), without the directory path or ".txt" extension.
364
365 For example:
366
367 ```
368 HOST_PYTHON3_PACKAGE_BUILD_DEPENDS:=setuptools-scm
369 ```
370
371 The Python package will be installed in `$(STAGING_DIR_HOSTPKG)/lib/pythonX.Y/site-packages`.
372
373 #### Non-Python packages installing host-side Python packages
374
375 Non-Python packages can also install host-side Python packages using the same mechanism:
376
377 * Set `HOST_PYTHON3_PACKAGE_BUILD_DEPENDS` (see above for details).
378
379 * Include `python3-package.mk` (set `PYTHON3_PKG_BUILD:=0` to avoid using the default Python package build recipes).
380
381 * Call `Py3Build/InstallBuildDepends` to initiate the installation.
382
383 For example:
384
385 ```
386 PYTHON3_PKG_BUILD:=0
387 HOST_PYTHON3_PACKAGE_BUILD_DEPENDS:=setuptools-scm
388
389 include $(INCLUDE_DIR)/package.mk
390 include ../../lang/python/python3-package.mk
391 # If outside of the packages feed:
392 # include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk
393
394 define Build/Compile
395 $(call Py3Build/InstallBuildDepends)
396 $(call Build/Compile/Default)
397 endef
398 ```