qtile migrate

qtile migrate is a tool to help users update their configs to reflect any breaking changes/deprecations introduced in later versions.

The tool can automatically apply updates but it can also be used to highlight impacted lines, allowing users to update their configs manually.

The tool can take a number of options when running:

Argument

Description

Default

-c, --config

Sets the path to the config file

~/.config/qtile/config.py

--list-migrations

Lists all the available migrations that can be run by the tool.

n/a

--info ID

Show more detail about the migration implement by ID.

n/a

--after-version VERSION

Only runs migrations relating to changes implemented after release VERSION.

Not set (i.e. runs all migrations).

-r ID, --run-migrations ID

Run selected migrations identified by ID. Comma separated list if using multiple values.

Not set (i.e. runs all migrations).

--yes

Automatically apply changes without asking user for confirmation.

Not set (i.e. users will need to confirm application of changes).

--show-diff

When used with --yes will cause diffs to still be shown for information purposes only.

Not set.

--no-colour

Disables colour output for diff.

Not set

--lint

Outputs linting lines showing location of changes. No changes are made to the config.

Not set.

Available migrations

The following migrations are currently available.

ID

Changes introduced after version

Summary

UpdateBitcoin

0.18.0

Updates BitcoinTicker to CryptoTicker.

UpdateBluetoothArgs

0.23.0

Updates Bluetooth argument signature.

UpdateKeychordArgs

0.21.0

Updates KeyChord argument signature.

UpdateStocktickerArgs

0.22.1

Updates StockTicker argument signature.

UpdateWidgetboxArgs

0.20.0

Updates WidgetBox argument signature.

MatchListRegex

0.23.0

Updates Match objects using lists

ModuleRenames

0.18.1

Updates certain deprecated libqtile. module names.

RemoveCmdPrefix

0.22.1

Removes cmd_ prefix from method calls and definitions.

RenamePacmanWidget

0.16.1

Changes deprecated Pacman widget name to CheckUpdates.

RenameWindowNameHook

0.16.1

Changes window_name_changed hook name.

RenameThreadedPollText

0.16.1

Replaces ThreadedPollText with ThreadPoolText.

RenameTileMaster

0.16.1

Changes masterWindows argument to master_length.

RenameUnspecified

0.25.0

Drops UNSPECIFIED argument

UpdateMonadArgs

0.17.0

Updates new_at_current keyword argument in Monad layouts.

UpdateTogroupArgs

0.18.1

Updates groupName keyword argument to group_name.

Running migrations

Assuming your config file is in the default location, running qtile migrate is sufficent to start the migration process.

Let's say you had a config file with the following contents:

import libqtile.command_client

keys = [
    KeyChord(
        [mod],
        "x",
        [Key([], "Up", lazy.layout.grow()), Key([], "Down", lazy.layout.shrink())],
        mode="Resize layout",
    )
]

qtile.cmd_spawn("alacritty")

Running qtile migrate will run each available migration and, where the migration would result in changes, a diff will be shown and you will be asked whether you wish to apply the changes.

UpdateKeychordArgs: Updates ``KeyChord`` argument signature.

--- original
+++ modified
@@ -5,7 +5,8 @@

        [mod],
        "x",
        [Key([], "Up", lazy.layout.grow()), Key([], "Down", lazy.layout.shrink())],
-        mode="Resize layout",
+        name="Resize layout",
+    mode=True,
    )
]

Apply changes? (y)es, (n)o, (s)kip file, (q)uit.

You will see from the output above that you are shown the name of the migration being applied and its purpose, along with the changes that will be implemented.

If you select quit the migration will be stopped and any applied changes will be reversed.

Once all migrations have been run on a file, you will then be asked whether you want to save changes to the file:

Save all changes to config.py? (y)es, (n)o.

At the end of the migration, backups of your original config will still be in your config folder. NB these will be overwritten if you re-run qtile migrate.

Linting

If you don't want the script to modify your config directly, you can use the --lint option to show you where changes are required.

Running qtile migrate --lint on the same config as shown above will result in the following output:

config.py:
[Ln 1, Col 7]: The 'libqtile.command_*' modules have been moved to 'libqtile.command.*'. (ModuleRenames)
[Ln 8, Col 8]: The use of mode='mode name' for KeyChord is deprecated. Use mode=True and value='mode name'. (UpdateKeychordArgs)
[Ln 12, Col 6]: Use of 'cmd_' prefix is deprecated. 'cmd_spawn' should be replaced with 'spawn' (RemoveCmdPrefix)

Explanations of migrations

The table below provides more detail of the available migrations.

UpdateBitcoin

Migration introduced after version

0.18.0

The BitcoinTicker widget has been renamed CryptoTicker. In addition, the format keyword argument is removed during this migration as the available fields for the format have changed.

The removal only happens on instances of BitcoinTracker. i.e. running qtile migrate on the following code:

BitcoinTicker(format="...")
CryptoTicker(format="...")

will return:

CryptoTicker()
CryptoTicker(format="...")

UpdateBluetoothArgs

Migration introduced after version

0.23.0

The Bluetooth widget previously accepted a hci keyword argument. This has been deprecated following a major overhaul of the widget and should be replaced with a keyword argument named device.

For example:

widget.Bluetooth(hci="/dev_XX_XX_XX_XX_XX_XX")

should be changed to:

widget.Bluetooth(device="/dev_XX_XX_XX_XX_XX_XX")

UpdateKeychordArgs

Migration introduced after version

0.21.0

Previously, users could make a key chord persist by setting the mode to a string representing the name of the mode. For example:

keys = [
    KeyChord(
        [mod],
        "x",
        [
            Key([], "Up", lazy.layout.grow()),
            Key([], "Down", lazy.layout.shrink())
        ],
        mode="Resize layout",
    )
]

This will now result in the following warning message in the log file:

The use of `mode` to set the KeyChord name is deprecated. Please use `name='Resize Layout'` instead.
'mode' should be a boolean value to set whether the chord is persistent (True) or not."

To remove the error, the config should be amended as follows:

keys = [
    KeyChord(
        [mod],
        "x",
        [
            Key([], "Up", lazy.layout.grow()),
            Key([], "Down", lazy.layout.shrink())
        ],
        name="Resize layout",
    mode=True,
    )
]

Note

The formatting of the inserted argument may not correctly match your own formatting. You may this to run a tool like black after applying this migration to tidy up your code.

UpdateStocktickerArgs

Migration introduced after version

0.22.1

The StockTicker widget had a keyword argument called function. This needs to be renamed to func to prevent clashes with the function() method of CommandObject.

For example:

widget.StockTicker(function="TIME_SERIES_INTRADAY")

should be changed to:

widget.StockTicker(func="TIME_SERIES_INTRADAY")

UpdateWidgetboxArgs

Migration introduced after version

0.20.0

The WidgetBox widget allowed a position argument to set the contents of the widget. This behaviour is deprecated and, instead, the contents should be specified with a keyword argument called widgets.

For example:

widget.WidgetBox(
    [
        widget.Systray(),
        widget.Volume(),
    ]
)

should be changed to:

widget.WidgetBox(
    widgets=[
        widget.Systray(),
        widget.Volume(),
    ]
)

MatchListRegex

Migration introduced after version

0.23.0

The use of lists in Match objects is deprecated and should be replaced with a regex.

For example:

Match(wm_class=["one", "two"])

should be changed to:

Match(wm_class=re.compile(r"^(one|two)$"))

ModuleRenames

Migration introduced after version

0.18.1

libqtile.window module was moved to libqtile.backend.x11.window.

RemoveCmdPrefix

Migration introduced after version

0.22.1

The cmd_ prefix was used to identify methods that should be exposed to qtile's command API. This has been deprecated and so calls no longer require the prefix.

For example:

qtile.cmd_spawn("vlc")

would be replaced with:

qtile.spawn("vlc")

Where users have created their own widgets with methods using this prefix, the syntax has also changed:

For example:

class MyWidget(libqtile.widget.base._Widget):
    def cmd_my_command(self):
        pass

Should be updated as follows:

from libqtile.command.base import expose_command

class MyWidget(libqtile.widget.base._Widget):
    @expose_command
    def my_command(self):
        pass

RenamePacmanWidget

Migration introduced after version

0.16.1

The Pacman widget has been renamed to CheckUpdates.

This is because the widget supports multiple package managers.

Example:

screens = [
    Screen(
        top=Bar(
            [
              ...
              widget.Pacman(),
              ...
            ]
        )
    )
]

Should be updated as follows:

screens = [
    Screen(
        top=Bar(
            [
              ...
              widget.CheckUpdates(),
              ...
            ]
        )
    )
]

RenameWindowNameHook

Migration introduced after version

0.16.1

The window_name_changed hook has been replaced with client_name_updated.

Example:

@hook.subscribe.window_name_changed
def my_func(window):
    ...

Should be updated as follows:

@hook.subscribe.client_name_updated
def my_func(window):
    ...

RenameThreadedPollText

Migration introduced after version

0.16.1

The ThreadedPollText class needs to replced with ThreadPoolText.

This is because the ThreadPoolText class can do everything that the ThreadedPollText does so the redundant code was removed.

Example:

from libqtile import widget

class MyPollingWidget(widget.base.ThreadedPollText):
    ...

Should be updated as follows:

from libqtile import widget

class MyPollingWidget(widget.base.ThreadPoolText):
    ...

RenameTileMaster

Migration introduced after version

0.16.1

To be consistent with other layouts, the masterWindows property of the Tile layout was renamed to master_length. Configs using the masterWindows argument when configuring the layout should replace this.

RenameUnspecified

Migration introduced after version

0.25.0

The UNSPECIFIED object was removed in favor of using the zero values (or None) to leave behavior unspecified. That is:

font=UNSPECIFIED -> font=None fontsize=UNSPECIFIED -> fontsize=0 fontshadow=UNSPECIFIED -> fontshadow=""

UpdateMonadArgs

Migration introduced after version

0.17.0

Replaces the new_at_current=True|False argument in Monad* layouts with new_client_position to be consistent with other layouts.

new_at_current=True is replaced with new_client_position="before_current and new_at_current=False is replaced with new_client_position="after_current".

UpdateTogroupArgs

Migration introduced after version

0.18.1

To be consistent with codestyle, the groupName argument in the togroup command needs to be changed to group_name.

The following code:

lazy.window.togroup(groupName="1")

will result in a warning in your logfile: Window.togroup's groupName is deprecated; use group_name.

The code should be updated to:

lazy.window.togroup(group_name="1")