Packing GTK+ applications with setuptools

Deutsch   |   Source

The only reason this page exists is to remove the links in my setup.py file.

Dependencies

from setuptools import setup

REQUIRED = ["PyGObject", ...]

setup(
    ...
    install_requires=REQUIRED,
    ...
    )

Pass the PyPI package name, for GTK+ applications you will need at least the GObject Python bindings to successfully run the import gi command.

Non-code files

from setuptools import setup

PACKAGES = ["my_package"]
PACKAGE_DIR = {"my_package": "my_package_dir"}
PACKAGE_DATA = {"my_package": ["ui/*", "logging.yaml"]}

setup(
    ...
    packages=PACKAGES,
    package_dir=PACKAGE_DIR,
    package_data=PACKAGE_DATA,
    ...
    )

The package "my_package" will be built from the files in "my_package_dir" folder into the "my_package" folder.

Non-code files like Glade files are passed as a list to the package_data option. In the example all files of the subfolder "ui" and the file "logging.yaml" are integrated into the package.

Desktop files

The locations of .desktop files and icons are defined by the Freedesktop specifications. Desktop entries for example are located in

/usr/share/applications
/usr/local/share/applications
~/.local/share/applications

While running install the suitable prefix will be identified so only relative paths are required to be passed to the data_files option.

from setuptools import setup

rel_app_path = "share/applications"
rel_icon_path = "share/icons/hicolor/scalable/apps"

DATAFILES = [
            (destination_dir, ["list", "of", "files"]),
            (rel_app_path, ["my_app.desktop"]),
            (rel_icon_path, ["my_appicon.svg"]),
            ]

setup(
    ...
    data_files=DATAFILES,
    ...
    )

This step only copies the files into the specific directories. The correct path declaration WITHIN the .desktop file has to be customized during the install command which will be accomplished by a custom function.

Customizing existing commands

The .desktop file includes information about the program to be executed as well as a corresponding icon, keywords etc. Because the target installation location may vary the file has to be adapted during the installation process.

To run own methods in existing commands you will have to create an instance of the specific command class (install, build, bdist etc.) and customize the "run" method.

In setuptools this information is passed to the cmd_class option.

from setuptools import setup
from setuptools.command.install import install

class CustomInstall(install):

    def run(self):
        self.my_function(args, go, here)
        install.run(self)

    def my_function(self, *args):
        try:
            do_some_shit()
        except:
            pass

setup(
    ...
    cmdclass={"install": CustomInstall}
    ...
    )

A list of available commands can be obtained by

$ python setup.py --help-commands

Creating new commands

Setuptools enables you to simply create your own commands. It may be useful to create an 'uninstall' command to get rid of all the files dumped to the system during installation to avoid to do that manually.

from setuptools import setup, Command

class UnInstall(Command):

    description = "description shown by setup.py --help-commands"
    user_options = [("myoption",
                     "m",
                     "myoption description shown by setup.py cmd --help")]

    def initialize_options(self):
        # method must exist
        # define all options with default value
        self.myoption = None

    def finalize_options(self):
        # method must exist
        pass

    def run(self):
        # method must exist
        # code to be executed goes here
        print("This is a custom command.")

setup(
    ...
    cmdclass={"uninstall": UnInstall}
    ...
    )
Comments powered by Disqus