Version 2.2.2 Released 2022-08-08 Fix router to restore the 2.1 strict_slashes == False behaviour whereby leaf-requests match branch rules and vice versa. pallets/werkzeug#2489 Fix router to identify invalid rules rather than hang parsing them, and to correctly parse / within converter arguments. pallets/werkzeug#2489 Update subpackage imports in werkzeug.routing to use the import as syntax for explicitly re-exporting public attributes. pallets/werkzeug#2493 Parsing of some invalid header characters is more robust. pallets/werkzeug#2494 When starting the development server, a warning not to use it in a production deployment is always shown. pallets/werkzeug#2480 LocalProxy.__wrapped__ is always set to the wrapped object when the proxy is unbound, fixing an issue in doctest that would cause it to fail. pallets/werkzeug#2485 Address one ResourceWarning related to the socket used by run_simple. pallets/werkzeug#2421 Version 2.2.1 Released 2022-07-27 Fix router so that /path/ will match a rule /path if strict slashes mode is disabled for the rule. pallets/werkzeug#2467 Fix router so that partial part matches are not allowed i.e. /2df does not match /<int>. pallets/werkzeug#2470 Fix router static part weighting, so that simpler routes are matched before more complex ones. pallets/werkzeug#2471 Restore ValidationError to be importable from werkzeug.routing. pallets/werkzeug#2465 Version 2.2.0 Released 2022-07-23 Deprecated get_script_name, get_query_string, peek_path_info, pop_path_info, and extract_path_info. pallets/werkzeug#2461 Remove previously deprecated code. pallets/werkzeug#2461 Add MarkupSafe as a dependency and use it to escape values when rendering HTML. pallets/werkzeug#2419 Added the werkzeug.debug.preserve_context mechanism for restoring context-local data for a request when running code in the debug console. pallets/werkzeug#2439 Fix compatibility with Python 3.11 by ensuring that end_lineno and end_col_offset are present on AST nodes. pallets/werkzeug#2425 Add a new faster matching router based on a state machine. pallets/werkzeug#2433 Fix branch leaf path masking branch paths when strict-slashes is disabled. pallets/werkzeug#1074 Names within options headers are always converted to lowercase. This matches RFC 6266 that the case is not relevant. pallets/werkzeug#2442 AnyConverter validates the value passed for it when building URLs. pallets/werkzeug#2388 The debugger shows enhanced error locations in tracebacks in Python 3.11. pallets/werkzeug#2407 Added Sans-IO is_resource_modified and parse_cookie functions based on WSGI versions. pallets/werkzeug#2408 Added Sans-IO get_content_length function. pallets/werkzeug#2415 Don’t assume a mimetype for test responses. pallets/werkzeug#2450 Type checking FileStorage accepts os.PathLike. pallets/werkzeug#2418 Version 2.1.2 Released 2022-04-28 The development server does not set Transfer-Encoding: chunked for 1xx, 204, 304, and HEAD responses. pallets/werkzeug#2375 Response HTML for exceptions and redirects starts with <!doctype html> and <html lang=en>. pallets/werkzeug#2390 Fix ability to set some cache_control attributes to False. pallets/werkzeug#2379 Disable keep-alive connections in the development server, which are not supported sufficiently by Python’s http.server. pallets/werkzeug#2397 Version 2.1.1 Released 2022-04-01 ResponseCacheControl.s_maxage converts its value to an int, like max_age. pallets/werkzeug#2364 Version 2.1.0 Released 2022-03-28 Drop support for Python 3.6. pallets/werkzeug#2277 Using gevent or eventlet requires greenlet>=1.0 or PyPy>=7.3.7. werkzeug.locals and contextvars will not work correctly with older versions. pallets/werkzeug#2278 Remove previously deprecated code. pallets/werkzeug#2276 Remove the non-standard shutdown function from the WSGI environ when running the development server. See the docs for alternatives. Request and response mixins have all been merged into the Request and Response classes. The user agent parser and the useragents module is removed. The user_agent module provides an interface that can be subclassed to add a parser, such as ua-parser. By default it only stores the whole string. The test client returns TestResponse instances and can no longer be treated as a tuple. All data is available as properties on the response. Remove locals.get_ident and related thread-local code from locals, it no longer makes sense when moving to a contextvars-based implementation. Remove the python -m werkzeug.serving CLI. The has_key method on some mapping datastructures; use key in data instead. Request.disable_data_descriptor is removed, pass shallow=True instead. Remove the no_etag parameter from Response.freeze(). Remove the HTTPException.wrap class method. Remove the cookie_date function. Use http_date instead. Remove the pbkdf2_hex, pbkdf2_bin, and safe_str_cmp functions. Use equivalents in hashlib and hmac modules instead. Remove the Href class. Remove the HTMLBuilder class. Remove the invalidate_cached_property function. Use del obj.attr instead. Remove bind_arguments and validate_arguments. Use Signature.bind() and inspect.signature() instead. Remove detect_utf_encoding, it’s built-in to json.loads. Remove format_string, use string.Template instead. Remove escape and unescape. Use MarkupSafe instead. The multiple parameter of parse_options_header is deprecated. pallets/werkzeug#2357 Rely on PEP 538 and PEP 540 to handle decoding file names with the correct filesystem encoding. The filesystem module is removed. pallets/werkzeug#1760 Default values passed to Headers are validated the same way values added later are. pallets/werkzeug#1608 Setting CacheControl int properties, such as max_age, will convert the value to an int. pallets/werkzeug#2230 Always use socket.fromfd when restarting the dev server. pallets/werkzeug#2287 When passing a dict of URL values to Map.build, list values do not filter out None or collapse to a single value. Passing a MultiDict does collapse single items. This undoes a previous change that made it difficult to pass a list, or None values in a list, to custom URL converters. pallets/werkzeug#2249 run_simple shows instructions for dealing with “address already in use” errors, including extra instructions for macOS. pallets/werkzeug#2321 Extend list of characters considered always safe in URLs based on RFC 3986. pallets/werkzeug#2319 Optimize the stat reloader to avoid watching unnecessary files in more cases. The watchdog reloader is still recommended for performance and accuracy. pallets/werkzeug#2141 The development server uses Transfer-Encoding: chunked for streaming responses when it is configured for HTTP/1.1. pallets/werkzeug#2090, pallets/werkzeug#1327, pallets/werkzeug#2091 The development server uses HTTP/1.1, which enables keep-alive connections and chunked streaming responses, when threaded or processes is enabled. pallets/werkzeug#2323 cached_property works for classes with __slots__ if a corresponding _cache_{name} slot is added. pallets/werkzeug#2332 Refactor the debugger traceback formatter to use Python’s built-in traceback module as much as possible. pallets/werkzeug#1753 The TestResponse.text property is a shortcut for r.get_data(as_text=True), for convenient testing against text instead of bytes. pallets/werkzeug#2337 safe_join ensures that the path remains relative if the trusted directory is the empty string. pallets/werkzeug#2349 Percent-encoded newlines (%0a), which are decoded by WSGI servers, are considered when routing instead of terminating the match early. pallets/werkzeug#2350 The test client doesn’t set duplicate headers for CONTENT_LENGTH and CONTENT_TYPE. pallets/werkzeug#2348 append_slash_redirect handles PATH_INFO with internal slashes. pallets/werkzeug#1972, pallets/werkzeug#2338 The default status code for append_slash_redirect is 308 instead of 301. This preserves the request body, and matches a previous change to strict_slashes in routing. pallets/werkzeug#2351 Fix ValueError: I/O operation on closed file. with the test client when following more than one redirect. pallets/werkzeug#2353 Response.autocorrect_location_header is disabled by default. The Location header URL will remain relative, and exclude the scheme and domain, by default. pallets/werkzeug#2352 Request.get_json() will raise a 400 BadRequest error if the Content-Type header is not application/json. This makes a very common source of confusion more visible. pallets/werkzeug#2339 Version 2.0.3 Released 2022-02-07 ProxyFix supports IPv6 addresses. pallets/werkzeug#2262 Type annotation for Response.make_conditional, HTTPException.get_response, and Map.bind_to_environ accepts Request in addition to WSGIEnvironment for the first parameter. pallets/werkzeug#2290 Fix type annotation for Request.user_agent_class. pallets/werkzeug#2273 Accessing LocalProxy.__class__ and __doc__ on an unbound proxy returns the fallback value instead of a method object. pallets/werkzeug#2188 Redirects with the test client set RAW_URI and REQUEST_URI correctly. pallets/werkzeug#2151 Signed-off-by: Daniel Golle <daniel@makrotopia.org> |
||
---|---|---|
.. | ||
2to3 | ||
bcrypt | ||
borgbackup | ||
click | ||
click-log | ||
django | ||
django-restframework | ||
Flask | ||
flup | ||
host-pip-requirements | ||
itsdangerous | ||
Jinja2 | ||
MarkupSafe | ||
micropython | ||
micropython-lib | ||
numpy | ||
openpyxl | ||
passlib | ||
pillow | ||
pymysql | ||
pyodbc | ||
python-aiohttp | ||
python-aiohttp-cors | ||
python-apipkg | ||
python-appdirs | ||
python-astral | ||
python-async-generator | ||
python-async-timeout | ||
python-atomicwrites | ||
python-attrs | ||
python-augeas | ||
python-automat | ||
python-awesomeversion | ||
python-awscli | ||
python-babel | ||
python-bidict | ||
python-boto3 | ||
python-botocore | ||
python-cached-property | ||
python-cachelib | ||
python-cachetools | ||
python-certifi | ||
python-cffi | ||
python-chardet | ||
python-ciso8601 | ||
python-colorama | ||
python-constantly | ||
python-contextlib2 | ||
python-crcmod | ||
python-cryptodome | ||
python-cryptodomex | ||
python-cryptography | ||
python-curl | ||
python-dateutil | ||
python-decorator | ||
python-defusedxml | ||
python-distro | ||
python-dns | ||
python-docker | ||
python-dockerpty | ||
python-docopt | ||
python-docutils | ||
python-dotenv | ||
python-engineio | ||
python-et_xmlfile | ||
python-evdev | ||
python-eventlet | ||
python-exceptiongroup | ||
python-execnet | ||
python-flask-babel | ||
python-flask-httpauth | ||
python-flask-login | ||
python-flask-seasurf | ||
python-flask-session | ||
python-flask-socketio | ||
python-gmpy2 | ||
python-gnupg | ||
python-greenlet | ||
python-hyperlink | ||
python-idna | ||
python-ifaddr | ||
python-incremental | ||
python-influxdb | ||
python-iniconfig | ||
python-intelhex | ||
python-jdcal | ||
python-jmespath | ||
python-jsonpath-ng | ||
python-jsonschema | ||
python-libmodbus | ||
python-lxml | ||
python-markdown | ||
python-more-itertools | ||
python-msgpack | ||
python-multidict | ||
python-netdisco | ||
python-outcome | ||
python-packaging | ||
python-paho-mqtt | ||
python-paramiko | ||
python-parsley | ||
python-pip-conf | ||
python-pluggy | ||
python-ply | ||
python-psutil | ||
python-psycopg2 | ||
python-py | ||
python-pyasn1 | ||
python-pyasn1-modules | ||
python-pycares | ||
python-pycparser | ||
python-pycrate | ||
python-pyfuse3 | ||
python-pynacl | ||
python-pyopenssl | ||
python-pyotp | ||
python-pyparsing | ||
python-pyrsistent | ||
python-pyserial | ||
python-pysocks | ||
python-pytest | ||
python-pytest-forked | ||
python-pytest-xdist | ||
python-pytz | ||
python-requests | ||
python-rsa | ||
python-s3transfer | ||
python-schedule | ||
python-schema | ||
python-sentry-sdk | ||
python-service-identity | ||
python-six | ||
python-slugify | ||
python-sniffio | ||
python-socketio | ||
python-sortedcontainers | ||
python-sqlalchemy | ||
python-stem | ||
python-texttable | ||
python-toml | ||
python-tornado | ||
python-trio | ||
python-twisted | ||
python-typing-extensions | ||
python-ubus | ||
python-uci | ||
python-urllib3 | ||
python-voluptuous | ||
python-voluptuous-serialize | ||
python-wcwidth | ||
python-websocket-client | ||
python-websockets | ||
python-yaml | ||
python-yarl | ||
python-zeroconf | ||
python-zipp | ||
python-zope-interface | ||
python3 | ||
python3-asgiref | ||
python3-bottle | ||
python3-django-cors-headers | ||
python3-django-etesync-journal | ||
python3-drf-nested-routers | ||
python3-iperf3 | ||
python3-libselinux | ||
python3-libsemanage | ||
python3-maxminddb | ||
python3-netifaces | ||
python3-networkx | ||
python3-packages | ||
python3-pyinotify | ||
python3-pyroute2 | ||
python3-speedtest-cli | ||
python3-sqlparse | ||
python3-unidecode | ||
ruamel-yaml | ||
text-unidecode | ||
vobject | ||
Werkzeug | ||
xmltodict | ||
pypi.mk | ||
python-package-install.sh | ||
python3-find-stdlib-depends.sh | ||
python3-host.mk | ||
python3-package.mk | ||
python3-version.mk | ||
README.md |
Python packages folder
Table of contents
- Description
- Introduction
- Python 2 end-of-life
- Using Python in external/other package feeds
- Build considerations
- General folder structure
- Building a Python package
Description
This section describes specifics for the Python packages that are present in this repo, and how things are structured.
In terms of license, contributing guide, etc, all of that information is described in the top 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).
Introduction
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.
It contains the Python 3 interpreter and Python packages. Most of the Python packages are downloaded from pypi.org. Python packages from pypi.org are typically preferred when adding new packages.
If more packages (than the ones packaged here) are needed, they can be downloaded via pip. 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
).
Python 2 end-of-life
Python 2 will not be maintained past 2020. All Python 2 packages have been removed from the packages feed (this repo) and archived in the abandoned packages feed.
Using Python in external/other package feeds
In the feeds.conf (or feeds.conf.default file, whatever is preferred), the packages repo should be present.
Example
src-git packages https://git.openwrt.org/feed/packages.git
src-git luci https://git.openwrt.org/project/luci.git
src-git routing https://git.openwrt.org/feed/routing.git
src-git telephony https://git.openwrt.org/feed/telephony.git
#
#
src-git someotherfeed https://github.com/<github-user>/<some-other-package>
Assuming that there are Python packages in the <some-other-package>
, they should include python3-package.mk
like this:
include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk
Same rules apply for python3-package.mk
as the Python packages in this repo.
One important consideration:: if the local name is not packages
, it's something else, like openwrt-packages
. And in feeds.conf[.default]
it's:
src-git openwrt-packages https://git.openwrt.org/feed/packages.git
Then, the inclusions also change:
include $(TOPDIR)/feeds/openwrt-packages/lang/python/python3-package.mk
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).
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:
PYTHON3_PACKAGE_MK:=$(wildcard $(TOPDIR)/feeds/*/lang/python/python3-package.mk)
# verify that there is only one single file returned
ifneq (1,$(words $(PYTHON3_PACKAGE_MK)))
ifeq (0,$(words $(PYTHON3_PACKAGE_MK)))
$(error did not find python3-package.mk in any feed)
else
$(error found multiple python3-package.mk files in the feeds)
endif
else
$(info found python3-package.mk at $(PYTHON3_PACKAGE_MK))
endif
include $(PYTHON3_PACKAGE_MK)
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.
Build considerations
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. That's why you'll also see a Python build & staging directories.
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].
As mentioned earlier, Python packages are shipped with bytecodes, and the reason for this is simply performance & size. The thought/discussion matrix derives a bit like this:
- shipping both Python source-code & bytecodes takes too much space on some devices ; Python source code & byte-code take about similar disk-size
- 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
- 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
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.
General folder structure
The basis of all these packages is:
- lang/python/python3 - The Python 3.x.y interpreter
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.
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.
The Python interpreter is structured like this:
python3-base
, which is just the minimal package to startup Python and run basic commandspython3
is a meta-package, which installs almost everything (python3-base [plus] Python library [minus] some unit-tests & some windows-y things)python3-light
ispython3
[minus] packages that are in lang/python/python3/files ; the size of this package may be sensible (and interesting) to another group of people
All other Python packages (aside from the intepreter) typically use these files:
- 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
- python3-package.mk
- includes python3-host.mk
- contains all the default build rules for Python packages; these will be detailed below in the Building a Python package section
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.
Building a Python package
Include python3-package.mk
Add this after include $(INCLUDE_DIR)/package.mk
include ../python3-package.mk
This will make sure that build rules for Python can be specified and picked up for build.
Include pypi.mk (optional)
pypi.mk
is an include file that makes downloading package source code from pypi.org simpler.
To use pypi.mk
, add this before include $(INCLUDE_DIR)/package.mk
:
include ../pypi.mk
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.
pypi.mk
also provides default values for PKG_SOURCE
and PKG_SOURCE_URL
, so these variables may be omitted.
Required variables:
-
PYPI_NAME
: Package name on pypi.org. This should match the PyPI name exactly.For example (from the
python-yaml
package):PYPI_NAME:=PyYAML
Optional variables:
-
PYPI_SOURCE_NAME
: Package name component of the source tarball filename
Default: Same value asPYPI_NAME
-
PYPI_SOURCE_EXT
: File extension of the source tarball filename
Default:tar.gz
pypi.mk
constructs the default PKG_SOURCE
value from these variables (and PKG_VERSION
):
PKG_SOURCE?=$(PYPI_SOURCE_NAME)-$(PKG_VERSION).$(PYPI_SOURCE_EXT)
Add Package/<PKG_NAME> OpenWrt definitions
This part is similar to default OpenWrt packages.
Example:
define Package/python3-lxml
SECTION:=lang
CATEGORY:=Languages
SUBMENU:=Python
TITLE:=Pythonic XML processing library
URL:=https://lxml.de
DEPENDS:=+python3-light +libxml2 +libxslt +libexslt
endef
define Package/python3-lxml/description
The lxml XML toolkit is a Pythonic binding
for the C libraries libxml2 and libxslt.
endef
Some considerations here (based on the example above):
- typically the package is named
Package/python3-<something>
; this convention makes things easier to follow, though it could work without naming things this way TITLE
can be something a bit more verbose/neat ; typically the name is short as seen above
Python package dependencies
Aside from other libraries and programs, every Python package will depend on at least one of these three types of packages:
-
The Python interpreter: All Python packages should depend on one of these three interpreter packages:
-
python3-light
is the best default for most Python packages. -
python3-base
should only be used as a dependency if you are certain the bare interpreter is sufficient. -
python3
is useful if many (more than three) Python standard library packages are needed.
-
-
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.
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), runmake
with theconfigure
target andPY3=stdlib V=s
in the command line. For example:make package/python-lxml/configure PY3=stdlib V=s
If the package has been built previously, include the
clean
target to trigger configure again:make package/python-lxml/{clean,configure} PY3=stdlib V=s
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.
-
Other Python packages: The easiest way to find these dependencies is to look for the
install_requires
keyword inside the package'ssetup.py
file (it will be a keyword argument to thesetup()
function). This will be a list of run-time dependencies for the package.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.
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. (Note that Setuptools is already installed as part of host Python.)
Wrapping things up so that they build
If all the above prerequisites have been met, all that's left is:
$(eval $(call Py3Package,python3-lxml))
$(eval $(call BuildPackage,python3-lxml))
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.
And $(eval $(call BuildPackage,python3-lxml))
will bind all the rules generated with $(eval $(call Py3Package,python3-lxml))
into the OpenWrt build system.
These packages will contain byte-codes and binaries (shared libs & other stuff).
If a user wishes to ship source code, adding one more line creates one more package that ship Python source code:
$(eval $(call Py3Package,python3-lxml))
$(eval $(call BuildPackage,python3-lxml))
$(eval $(call BuildPackage,python3-lxml-src))
The name *-src
must be the Python package name; so for python3-lxml-src
a equivalent python3-lxml
name must exist.
Customizing things
Some packages need custom build rules (because they do).
The default package build and install processes are defined in python3-package.mk
.
Building
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.
There are several Makefile variables that can be used to customize this process (all optional):
PYTHON3_PKG_SETUP_DIR
: Path wheresetup.py
can be found, relative to the package directory (PKG_BUILD_DIR
).
Default: empty value (setup.py
is in the package directory)PYTHON3_PKG_SETUP_VARS
: Additional environment variables to set for the call tosetup.py
. Should be in the form ofVARIABLE1=value VARIABLE2=value ...
.
Default: empty valuePYTHON3_PKG_SETUP_GLOBAL_ARGS
: Additional command line arguments to pass tosetup.py
, before / in front of theinstall
command.
Default: empty valuePYTHON3_PKG_SETUP_ARGS
: Additional command line arguments to pass tosetup.py
, after theinstall
command.
Default:--single-version-externally-managed
Conceptually, these variables are used in this way:
cd $(PKG_BUILD_DIR)/$(PYTHON3_PKG_SETUP_DIR)
$(PYTHON3_PKG_SETUP_VARS) python3 setup.py $(PYTHON3_PKG_SETUP_GLOBAL_ARGS) install $(PYTHON3_PKG_SETUP_ARGS)
The default build process can be completely overridden by defining a custom Py3Build/Compile
rule in the package Makefile.
Installing
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.
This default process uses 2 build rules:
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-folderPy3Package/<package>/install
is similar toPackage/<package>/install
; this allows binary (or other files) to be installed on the target
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.
The Py3Package/<package>/filespec
rule contains one or more lines of the following format (whitespace added for clarity):
<one of: +-=> | <file/directory path> | <file permissions>
The initial character controls the action that will be taken:
+
: Install the given path. If the path is a directory, all files and subdirectories inside are installed.- 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.
-
: Remove the given path. Useful when most of a directory should be installed except for a few files or subdirectories.- File permissions is not used / ignored in this case.
=
: Assign the given file permissions to the given path. File permissions is required in this case.
As mentioned, the default Py3Package/<package>/filespec
installs PYTHON3_PKG_DIR
:
define Py3Package/python3-example/filespec
+|$(PYTHON3_PKG_DIR)
endef
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:
define Py3Package/python3-example/filespec
+|$(PYTHON3_PKG_DIR)
-|$(PYTHON3_PKG_DIR)/example_package/examples
-|$(PYTHON3_PKG_DIR)/example_package/test_*.py
endef
Host-side Python packages for build
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.
Requirements files
All host-side Python packages are installed with pip using requirements files, with hash-checking mode enabled. These requirements files are stored in the host-pip-requirements directory.
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.
For example, the requirements file for setuptools-scm (setuptools-scm.txt) contains:
setuptools-scm==4.1.2 --hash=sha256:a8994582e716ec690f33fec70cca0f85bd23ec974e3f783233e4879090a7faa8
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 includes information for pycparser because pycparser is a dependency of cffi and will be installed with cffi.
There are two types of requirements files in host-pip-requirements:
-
Installs the latest version of a Python package.
A requirements file of this type is named with the package name only (for example, setuptools-scm.txt) and is used when there is no strict version requirement.
These files will be updated as newer versions of the Python packages are available.
-
Installs a specific version of a Python package.
A requirements file of this type is named with the package name and version number (for example, Django-1.11.txt) and is used when a specific (usually older) version is required.
Installing the latest versions of packages is preferred over specific versions whenever possible.
Installing host-side Python packages
Set HOST_PYTHON3_PACKAGE_BUILD_DEPENDS
to the names of one or more requirements files in host-pip-requirements, without the directory path or ".txt" extension.
For example:
HOST_PYTHON3_PACKAGE_BUILD_DEPENDS:=setuptools-scm
The Python package will be installed in $(STAGING_DIR_HOSTPKG)/lib/pythonX.Y/site-packages
.
Non-Python packages installing host-side Python packages
Non-Python packages can also install host-side Python packages using the same mechanism:
-
Set
HOST_PYTHON3_PACKAGE_BUILD_DEPENDS
(see above for details). -
Include
python3-package.mk
(setPYTHON3_PKG_BUILD:=0
to avoid using the default Python package build recipes). -
Call
Py3Build/InstallBuildDepends
to initiate the installation.
For example:
PYTHON3_PKG_BUILD:=0
HOST_PYTHON3_PACKAGE_BUILD_DEPENDS:=setuptools-scm
include $(INCLUDE_DIR)/package.mk
include ../../lang/python/python3-package.mk
# If outside of the packages feed:
# include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk
define Build/Compile
$(call Py3Build/InstallBuildDepends)
$(call Build/Compile/Default)
endef