Quick search

Extension Support

Sometimes your application requires functionality that is beyond the scope of what Kivy can deliver. In those cases it is necessary to resort to external software libraries. Given the richness of the Python ecosystem, there is already a great number of software libraries that you can simply import and use right away.

For some third-party libraries, it’s not as easy as that though. Some libraries require special wrappers to be written for them in order to be compatible with Kivy. Some libraries might even need to be patched so that they can be used (e.g. if they open their own OpenGL context to draw in and don’t support proper offscreen rendering). On those occasions it is often possible to patch the library in question and provide a Python wrapper around it that is compatible with Kivy. Sticking with this example, you can’t just use the wrapper with a ‘normal’ installation of the library because the patch would be missing.

That is where Kivy extensions come in handy. A Kivy extension represents a single third-party library that is provided in such a way that it can simply be downloaded as a single file, put in a special directory and then offers the functionality of the wrapped library to Kivy applications. These extensions will not pollute the global Python environment (as they might be unusable on their own after potential patches have been applied) because they reside in special directories for Kivy that are not accessed by Python by default.

Naming and versioning

Kivy extensions are provided as *.kex files. They are really just zip files, but you must not unzip them yourself. Kivy will do that for you as soon as it’s appropriate to do so. They follow the following naming convention:

<NAME>-<MAJOR>.<MINOR>[.*].kex

Warning

Again, do not try to unzip *.kex files on your own. While unzipping will work, Kivy will not be able to load the extension and will simply ignore it.

With Kivy’s extension system, your application can use specially packaged third-party libraries in a backwards compatible way (by specifying the version that you require) even if the actual third-party library does not guarantee backwards-compatibility. There will be no breakage if newer versions are installed (as a properly suited old version will still be used). For more information on such behaviour, please refer to the documentation of the load() function.

If you want to provide an extension on your own, there is a helper script that sets up the initial extension folder structure that Kivy requires for extensions. It can be found at kivy/tools/extensions/make-kivyext.py

kivy.ext.load(extname, version)[source]

Use this function to tell Kivy to load a specific version of the given Extension. This is different from kivy’s require() in that it will always use the exact same major version you specify even if a newer (major) version is available. This is because we cannot make the same backwards-compatibility guarantee that we make with Kivy for third-party extensions. You will still get fixes and optimizations that don’t break backwards compatibility via minor version upgrades of the extension.

The function will then return the loaded module as a Python module object and you can bind it to a name of your choosing. This prevents clashes with modules with the same name that might be installed in a system directory.

Usage example for this function:

from kivy.ext import load
myextension = load('myextension', (2, 1))
# You can now use myextension as if you had done ``import myextension``,
# but with the added benefit of using the proper version.
Parameters:
extname: str

The exact name of the extension that you want to use.

version: two-tuple of ints

A tuple of the form (major, minor), where major and minor are ints that specify the major and minor version number for the extension, e.g. (1, 2) would be akin to 1.2. It is important to note that between minor versions, backwards compatibility is guaranteed, but between major versions it is not. I.e. if you change your extension in a backwards incompatible way, increase the major version number (and reset the minor to 0). If you just do a bug fix or add an optional, backwards-compatible feature, you can just increase the minor version number. If the application then requires version (1, 2), every version starting with that version number will be ok and by default the latest version will be choosen. The two ints major and minor can both be in range(0, infinity).

kivy.ext.unzip_extensions()[source]

Unzips Kivy extensions. Internal usage only: don’t use it yourself unless you know what you’re doing and really want to trigger installation of new extensions.

For your file to be recognized as an extension, it has to fulfil a few requirements:

  • We require that the file has the *.kex extension to make the distinction between a Kivy extension and an ordinary zip file clear.

  • We require that the *.kex extension files be put into any of the directories listed in EXTENSION_PATHS which is normally ~/.kivy/extensions and extensions/ inside kivy’s base directory. We do not look for extensions on sys.path or elsewhere in the system.

  • We require that the Kivy extension is zipped in a way so that Python’s zipfile module can extract it properly.

  • We require that the extension internally obeys the common Kivy extension format, which looks like this:

    |-- myextension/
        |-- __init__.py
        |-- data/
    

    The __init__.py file is the main entrypoint to the extension. All names that should be usable when the extension is loaded need to be exported (i.e. made available) in the namespace of that file.

    How the extension accesses the code of the library that it wraps (be it pure Python or binary code) is up to the extension. For example there could be another Python module adjacent to the __init__.py file from which the __init__.py file imports the usable names that it wants to expose.

  • We require that the version of the extension be specified in the setup.py file that is created by the Kivy extension wizard and that the version specification format as explained in load() be used.