We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
BitcoinTicker migration does not work
```
/tmp/crypto cat config.py 
from libqtile.widget import BitcoinTicker

test = BitcoinTicker()
/tmp/crypto qtile migrate -c config.py 
Config unchanged.
/tmp/crypto cat config.py 
from libqtile.widget import BitcoinTicker

test = BitcoinTicker()
```

/cc @Graeme22

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `libqtile/scripts/migrate.py`
Content:
```
1 # Copyright (c) 2021, Tycho Andersen. All rights reserved.
2 #
3 # Permission is hereby granted, free of charge, to any person obtaining a copy
4 # of this software and associated documentation files (the "Software"), to deal
5 # in the Software without restriction, including without limitation the rights
6 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 # copies of the Software, and to permit persons to whom the Software is
8 # furnished to do so, subject to the following conditions:
9 #
10 # The above copyright notice and this permission notice shall be included in
11 # all copies or substantial portions of the Software.
12 #
13 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 import filecmp
20 import os
21 import os.path
22 import shutil
23 import sys
24 from glob import glob
25 
26 BACKUP_SUFFIX = ".migrate.bak"
27 
28 try:
29     import bowler
30 except ImportError:
31     pass
32 
33 
34 def rename_hook(query, fro, to):
35     # could match on dotted_name< 'hook' '.' 'subscribe' '.' '{name}' >
36     # but the replacement gets more complicated...
37     selector = "'{name}'".format(name=fro)
38     q = query.select_pattern(selector)
39     q.current.kwargs["name"] = fro
40     return q.rename(to)
41 
42 
43 def client_name_updated(query):
44     """ Rename window_name_change -> client_name_updated"""
45     return rename_hook(query, "window_name_change", "client_name_updated")
46 
47 
48 def tile_master_windows_rename(query):
49     return (
50         query
51         .select_function("Tile")
52         .modify_argument("masterWindows", "master_length")
53     )
54 
55 
56 def threaded_poll_text_rename(query):
57     return (
58         query
59         .select_class("ThreadedPollText")
60         .rename("ThreadPoolText")
61     )
62 
63 
64 def pacman_to_checkupdates(query):
65     return (
66         query
67         .select_class("Pacman")
68         .rename("CheckUpdates")
69     )
70 
71 
72 def bitcoin_to_crypto(query):
73     return (
74         query
75         .select_class("BitcoinTicker")
76         .rename("CryptoTicker")
77     )
78 
79 
80 def hook_main_function(query):
81     def modify_main(node, capture, filename):
82         main = capture.get("function_def")
83         if main.prev_sibling:
84             for leaf in main.prev_sibling.leaves():
85                 if "startup" == leaf.value:
86                     return
87         args = capture.get("function_arguments")
88         if args:
89             args[0].remove()
90             main.prefix += "from libqtile import hook, qtile\n"
91             main.prefix += "@hook.subscribe.startup\n"
92 
93     return (
94         query
95         .select_function("main")
96         .is_def()
97         .modify(modify_main)
98     )
99 
100 
101 # Deprecated new_at_current key replaced by new_client_position.
102 # In the node, we want to change the key name
103 # and adapts its value depending of the previous value :
104 #   new_at_current=True => new_client_position=before_current
105 #   new_at_current<>True => new_client_position=after_current
106 def update_node_nac(node, capture, filename):
107     key = capture.get("k")
108     key.value = "new_client_position"
109     val = capture.get("v")
110     if val.value == "True":
111         val.value = "'before_current'"
112     else:
113         val.value = "'after_current'"
114 
115 
116 def new_at_current_to_new_client_position(query):
117     old_pattern = """
118         argument< k="new_at_current" "=" v=any >
119     """
120     return (
121         query
122         .select(old_pattern)
123         .modify(update_node_nac)
124     )
125 
126 
127 MIGRATIONS = [
128     client_name_updated,
129     tile_master_windows_rename,
130     threaded_poll_text_rename,
131     pacman_to_checkupdates,
132     hook_main_function,
133     new_at_current_to_new_client_position,
134 ]
135 
136 
137 MODULE_RENAMES = [
138     ("libqtile.command_graph", "libqtile.command.graph"),
139     ("libqtile.command_client", "libqtile.command.client"),
140     ("libqtile.command_interface", "libqtile.command.interface"),
141     ("libqtile.command_object", "libqtile.command.base"),
142     ("libqtile.window", "libqtile.backend.x11.window"),
143 ]
144 
145 for (fro, to) in MODULE_RENAMES:
146     def f(query, fro=fro, to=to):
147         return (
148             query
149             .select_module(fro)
150             .rename(to)
151         )
152     MIGRATIONS.append(f)
153 
154 
155 def file_and_backup(config_dir):
156     for py in glob(os.path.join(config_dir, "*.py")):
157         backup = py + BACKUP_SUFFIX
158         yield py, backup
159 
160 
161 def do_migrate(args):
162     if "bowler" not in sys.modules:
163         print("bowler can't be found, not migrating config file")
164         print("install it and try again")
165         sys.exit(1)
166 
167     config_dir = os.path.dirname(args.config)
168     for py, backup in file_and_backup(config_dir):
169         shutil.copyfile(py, backup)
170 
171     for m in MIGRATIONS:
172         q = bowler.Query(config_dir)
173         m(q).execute(interactive=not args.yes, write=True)
174 
175     changed = False
176     for py, backup in file_and_backup(config_dir):
177         backup = py + BACKUP_SUFFIX
178         if not filecmp.cmp(py, backup, shallow=False):
179             changed = True
180             break
181 
182     if not changed:
183         print("Config unchanged.")
184         for _, backup in file_and_backup(config_dir):
185             os.remove(backup)
186 
187 
188 def add_subcommand(subparsers, parents):
189     parser = subparsers.add_parser(
190         "migrate",
191         parents=parents,
192         help="Migrate a configuration file to the current API"
193     )
194     parser.add_argument(
195         "-c",
196         "--config",
197         action="store",
198         default=os.path.expanduser(
199             os.path.join(os.getenv("XDG_CONFIG_HOME", "~/.config"), "qtile", "config.py")
200         ),
201         help="Use the specified configuration file (migrates every .py file in this directory)",
202     )
203     parser.add_argument(
204         "--yes",
205         action="store_true",
206         help="Automatically apply diffs with no confirmation",
207     )
208     parser.set_defaults(func=do_migrate)
209
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/libqtile/scripts/migrate.py b/libqtile/scripts/migrate.py
--- a/libqtile/scripts/migrate.py
+++ b/libqtile/scripts/migrate.py
@@ -129,6 +129,7 @@
     tile_master_windows_rename,
     threaded_poll_text_rename,
     pacman_to_checkupdates,
+    bitcoin_to_crypto,
     hook_main_function,
     new_at_current_to_new_client_position,
 ]

{"golden_diff": "diff --git a/libqtile/scripts/migrate.py b/libqtile/scripts/migrate.py\n--- a/libqtile/scripts/migrate.py\n+++ b/libqtile/scripts/migrate.py\n@@ -129,6 +129,7 @@\n     tile_master_windows_rename,\n     threaded_poll_text_rename,\n     pacman_to_checkupdates,\n+    bitcoin_to_crypto,\n     hook_main_function,\n     new_at_current_to_new_client_position,\n ]\n", "issue": "BitcoinTicker migration does not work\n```\r\n/tmp/crypto cat config.py \r\nfrom libqtile.widget import BitcoinTicker\r\n\r\ntest = BitcoinTicker()\r\n/tmp/crypto qtile migrate -c config.py \r\nConfig unchanged.\r\n/tmp/crypto cat config.py \r\nfrom libqtile.widget import BitcoinTicker\r\n\r\ntest = BitcoinTicker()\r\n```\r\n\r\n/cc @Graeme22\n", "before_files": [{"content": "# Copyright (c) 2021, Tycho Andersen. All rights reserved.\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nimport filecmp\nimport os\nimport os.path\nimport shutil\nimport sys\nfrom glob import glob\n\nBACKUP_SUFFIX = \".migrate.bak\"\n\ntry:\n    import bowler\nexcept ImportError:\n    pass\n\n\ndef rename_hook(query, fro, to):\n    # could match on dotted_name< 'hook' '.' 'subscribe' '.' '{name}' >\n    # but the replacement gets more complicated...\n    selector = \"'{name}'\".format(name=fro)\n    q = query.select_pattern(selector)\n    q.current.kwargs[\"name\"] = fro\n    return q.rename(to)\n\n\ndef client_name_updated(query):\n    \"\"\" Rename window_name_change -> client_name_updated\"\"\"\n    return rename_hook(query, \"window_name_change\", \"client_name_updated\")\n\n\ndef tile_master_windows_rename(query):\n    return (\n        query\n        .select_function(\"Tile\")\n        .modify_argument(\"masterWindows\", \"master_length\")\n    )\n\n\ndef threaded_poll_text_rename(query):\n    return (\n        query\n        .select_class(\"ThreadedPollText\")\n        .rename(\"ThreadPoolText\")\n    )\n\n\ndef pacman_to_checkupdates(query):\n    return (\n        query\n        .select_class(\"Pacman\")\n        .rename(\"CheckUpdates\")\n    )\n\n\ndef bitcoin_to_crypto(query):\n    return (\n        query\n        .select_class(\"BitcoinTicker\")\n        .rename(\"CryptoTicker\")\n    )\n\n\ndef hook_main_function(query):\n    def modify_main(node, capture, filename):\n        main = capture.get(\"function_def\")\n        if main.prev_sibling:\n            for leaf in main.prev_sibling.leaves():\n                if \"startup\" == leaf.value:\n                    return\n        args = capture.get(\"function_arguments\")\n        if args:\n            args[0].remove()\n            main.prefix += \"from libqtile import hook, qtile\\n\"\n            main.prefix += \"@hook.subscribe.startup\\n\"\n\n    return (\n        query\n        .select_function(\"main\")\n        .is_def()\n        .modify(modify_main)\n    )\n\n\n# Deprecated new_at_current key replaced by new_client_position.\n# In the node, we want to change the key name\n# and adapts its value depending of the previous value :\n#   new_at_current=True => new_client_position=before_current\n#   new_at_current<>True => new_client_position=after_current\ndef update_node_nac(node, capture, filename):\n    key = capture.get(\"k\")\n    key.value = \"new_client_position\"\n    val = capture.get(\"v\")\n    if val.value == \"True\":\n        val.value = \"'before_current'\"\n    else:\n        val.value = \"'after_current'\"\n\n\ndef new_at_current_to_new_client_position(query):\n    old_pattern = \"\"\"\n        argument< k=\"new_at_current\" \"=\" v=any >\n    \"\"\"\n    return (\n        query\n        .select(old_pattern)\n        .modify(update_node_nac)\n    )\n\n\nMIGRATIONS = [\n    client_name_updated,\n    tile_master_windows_rename,\n    threaded_poll_text_rename,\n    pacman_to_checkupdates,\n    hook_main_function,\n    new_at_current_to_new_client_position,\n]\n\n\nMODULE_RENAMES = [\n    (\"libqtile.command_graph\", \"libqtile.command.graph\"),\n    (\"libqtile.command_client\", \"libqtile.command.client\"),\n    (\"libqtile.command_interface\", \"libqtile.command.interface\"),\n    (\"libqtile.command_object\", \"libqtile.command.base\"),\n    (\"libqtile.window\", \"libqtile.backend.x11.window\"),\n]\n\nfor (fro, to) in MODULE_RENAMES:\n    def f(query, fro=fro, to=to):\n        return (\n            query\n            .select_module(fro)\n            .rename(to)\n        )\n    MIGRATIONS.append(f)\n\n\ndef file_and_backup(config_dir):\n    for py in glob(os.path.join(config_dir, \"*.py\")):\n        backup = py + BACKUP_SUFFIX\n        yield py, backup\n\n\ndef do_migrate(args):\n    if \"bowler\" not in sys.modules:\n        print(\"bowler can't be found, not migrating config file\")\n        print(\"install it and try again\")\n        sys.exit(1)\n\n    config_dir = os.path.dirname(args.config)\n    for py, backup in file_and_backup(config_dir):\n        shutil.copyfile(py, backup)\n\n    for m in MIGRATIONS:\n        q = bowler.Query(config_dir)\n        m(q).execute(interactive=not args.yes, write=True)\n\n    changed = False\n    for py, backup in file_and_backup(config_dir):\n        backup = py + BACKUP_SUFFIX\n        if not filecmp.cmp(py, backup, shallow=False):\n            changed = True\n            break\n\n    if not changed:\n        print(\"Config unchanged.\")\n        for _, backup in file_and_backup(config_dir):\n            os.remove(backup)\n\n\ndef add_subcommand(subparsers, parents):\n    parser = subparsers.add_parser(\n        \"migrate\",\n        parents=parents,\n        help=\"Migrate a configuration file to the current API\"\n    )\n    parser.add_argument(\n        \"-c\",\n        \"--config\",\n        action=\"store\",\n        default=os.path.expanduser(\n            os.path.join(os.getenv(\"XDG_CONFIG_HOME\", \"~/.config\"), \"qtile\", \"config.py\")\n        ),\n        help=\"Use the specified configuration file (migrates every .py file in this directory)\",\n    )\n    parser.add_argument(\n        \"--yes\",\n        action=\"store_true\",\n        help=\"Automatically apply diffs with no confirmation\",\n    )\n    parser.set_defaults(func=do_migrate)\n", "path": "libqtile/scripts/migrate.py"}], "after_files": [{"content": "# Copyright (c) 2021, Tycho Andersen. All rights reserved.\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nimport filecmp\nimport os\nimport os.path\nimport shutil\nimport sys\nfrom glob import glob\n\nBACKUP_SUFFIX = \".migrate.bak\"\n\ntry:\n    import bowler\nexcept ImportError:\n    pass\n\n\ndef rename_hook(query, fro, to):\n    # could match on dotted_name< 'hook' '.' 'subscribe' '.' '{name}' >\n    # but the replacement gets more complicated...\n    selector = \"'{name}'\".format(name=fro)\n    q = query.select_pattern(selector)\n    q.current.kwargs[\"name\"] = fro\n    return q.rename(to)\n\n\ndef client_name_updated(query):\n    \"\"\" Rename window_name_change -> client_name_updated\"\"\"\n    return rename_hook(query, \"window_name_change\", \"client_name_updated\")\n\n\ndef tile_master_windows_rename(query):\n    return (\n        query\n        .select_function(\"Tile\")\n        .modify_argument(\"masterWindows\", \"master_length\")\n    )\n\n\ndef threaded_poll_text_rename(query):\n    return (\n        query\n        .select_class(\"ThreadedPollText\")\n        .rename(\"ThreadPoolText\")\n    )\n\n\ndef pacman_to_checkupdates(query):\n    return (\n        query\n        .select_class(\"Pacman\")\n        .rename(\"CheckUpdates\")\n    )\n\n\ndef bitcoin_to_crypto(query):\n    return (\n        query\n        .select_class(\"BitcoinTicker\")\n        .rename(\"CryptoTicker\")\n    )\n\n\ndef hook_main_function(query):\n    def modify_main(node, capture, filename):\n        main = capture.get(\"function_def\")\n        if main.prev_sibling:\n            for leaf in main.prev_sibling.leaves():\n                if \"startup\" == leaf.value:\n                    return\n        args = capture.get(\"function_arguments\")\n        if args:\n            args[0].remove()\n            main.prefix += \"from libqtile import hook, qtile\\n\"\n            main.prefix += \"@hook.subscribe.startup\\n\"\n\n    return (\n        query\n        .select_function(\"main\")\n        .is_def()\n        .modify(modify_main)\n    )\n\n\n# Deprecated new_at_current key replaced by new_client_position.\n# In the node, we want to change the key name\n# and adapts its value depending of the previous value :\n#   new_at_current=True => new_client_position=before_current\n#   new_at_current<>True => new_client_position=after_current\ndef update_node_nac(node, capture, filename):\n    key = capture.get(\"k\")\n    key.value = \"new_client_position\"\n    val = capture.get(\"v\")\n    if val.value == \"True\":\n        val.value = \"'before_current'\"\n    else:\n        val.value = \"'after_current'\"\n\n\ndef new_at_current_to_new_client_position(query):\n    old_pattern = \"\"\"\n        argument< k=\"new_at_current\" \"=\" v=any >\n    \"\"\"\n    return (\n        query\n        .select(old_pattern)\n        .modify(update_node_nac)\n    )\n\n\nMIGRATIONS = [\n    client_name_updated,\n    tile_master_windows_rename,\n    threaded_poll_text_rename,\n    pacman_to_checkupdates,\n    bitcoin_to_crypto,\n    hook_main_function,\n    new_at_current_to_new_client_position,\n]\n\n\nMODULE_RENAMES = [\n    (\"libqtile.command_graph\", \"libqtile.command.graph\"),\n    (\"libqtile.command_client\", \"libqtile.command.client\"),\n    (\"libqtile.command_interface\", \"libqtile.command.interface\"),\n    (\"libqtile.command_object\", \"libqtile.command.base\"),\n    (\"libqtile.window\", \"libqtile.backend.x11.window\"),\n]\n\nfor (fro, to) in MODULE_RENAMES:\n    def f(query, fro=fro, to=to):\n        return (\n            query\n            .select_module(fro)\n            .rename(to)\n        )\n    MIGRATIONS.append(f)\n\n\ndef file_and_backup(config_dir):\n    for py in glob(os.path.join(config_dir, \"*.py\")):\n        backup = py + BACKUP_SUFFIX\n        yield py, backup\n\n\ndef do_migrate(args):\n    if \"bowler\" not in sys.modules:\n        print(\"bowler can't be found, not migrating config file\")\n        print(\"install it and try again\")\n        sys.exit(1)\n\n    config_dir = os.path.dirname(args.config)\n    for py, backup in file_and_backup(config_dir):\n        shutil.copyfile(py, backup)\n\n    for m in MIGRATIONS:\n        q = bowler.Query(config_dir)\n        m(q).execute(interactive=not args.yes, write=True)\n\n    changed = False\n    for py, backup in file_and_backup(config_dir):\n        backup = py + BACKUP_SUFFIX\n        if not filecmp.cmp(py, backup, shallow=False):\n            changed = True\n            break\n\n    if not changed:\n        print(\"Config unchanged.\")\n        for _, backup in file_and_backup(config_dir):\n            os.remove(backup)\n\n\ndef add_subcommand(subparsers, parents):\n    parser = subparsers.add_parser(\n        \"migrate\",\n        parents=parents,\n        help=\"Migrate a configuration file to the current API\"\n    )\n    parser.add_argument(\n        \"-c\",\n        \"--config\",\n        action=\"store\",\n        default=os.path.expanduser(\n            os.path.join(os.getenv(\"XDG_CONFIG_HOME\", \"~/.config\"), \"qtile\", \"config.py\")\n        ),\n        help=\"Use the specified configuration file (migrates every .py file in this directory)\",\n    )\n    parser.add_argument(\n        \"--yes\",\n        action=\"store_true\",\n        help=\"Automatically apply diffs with no confirmation\",\n    )\n    parser.set_defaults(func=do_migrate)\n", "path": "libqtile/scripts/migrate.py"}]}