We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
mpd_status 'max_width' ineffective
- **Archlinux**
- **py3status version 3.15**
- **python-mpd2 version 1.0.0-2**
- **window manager 'sway-git' (same with i3)**

New to py3status, coming from i3blocks where I had a script to limit the output of characters to a set length.  Using mpd_status module in py3status, I see there is an option for max_width.  I have set this to 50, yet this has no effect on the artist/track name displayed.  Here is the mpd_status block I'm using...

```
mpd_status {
        name = ""
	format = "{name} [[[{artist} - ]{title}]|[{file}]]"
        on_click 1 = "exec mpc prev"
        on_click 2 = "exec mpc toggle"
        on_click 3 = "exec mpc next"
        color_play = "#ffffff"
        color_stop = "#ffffff"
        color_pause = "#676E7D"
	max_width = 50
}
```

- **What I expect to see**
Artist and song info printed in py3status that is longer than 50 chars, cut to 50 with "..." appended.

- **What I actually see**
Artist and song info is printed in full regardless of the max_width setting.
mpd_status 'max_width' ineffective
- **Archlinux**
- **py3status version 3.15**
- **python-mpd2 version 1.0.0-2**
- **window manager 'sway-git' (same with i3)**

New to py3status, coming from i3blocks where I had a script to limit the output of characters to a set length.  Using mpd_status module in py3status, I see there is an option for max_width.  I have set this to 50, yet this has no effect on the artist/track name displayed.  Here is the mpd_status block I'm using...

```
mpd_status {
        name = ""
	format = "{name} [[[{artist} - ]{title}]|[{file}]]"
        on_click 1 = "exec mpc prev"
        on_click 2 = "exec mpc toggle"
        on_click 3 = "exec mpc next"
        color_play = "#ffffff"
        color_stop = "#ffffff"
        color_pause = "#676E7D"
	max_width = 50
}
```

- **What I expect to see**
Artist and song info printed in py3status that is longer than 50 chars, cut to 50 with "..." appended.

- **What I actually see**
Artist and song info is printed in full regardless of the max_width setting.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `py3status/modules/mpd_status.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 """
3 Display song currently playing in mpd.
4 
5 Configuration parameters:
6     cache_timeout: how often we refresh this module in seconds (default 2)
7     format: template string (see below)
8         (default '{state} [[[{artist}] - {title}]|[{file}]]')
9     hide_on_error: hide the status if an error has occurred (default False)
10     hide_when_paused: hide the status if state is paused (default False)
11     hide_when_stopped: hide the status if state is stopped (default True)
12     host: mpd host (default 'localhost')
13     max_width: maximum status length (default 120)
14     password: mpd password (default None)
15     port: mpd port (default '6600')
16     state_pause: label to display for "paused" state (default '[pause]')
17     state_play: label to display for "playing" state (default '[play]')
18     state_stop: label to display for "stopped" state (default '[stop]')
19 
20 Color options:
21     color_pause: Paused, default color_degraded
22     color_play: Playing, default color_good
23     color_stop: Stopped, default color_bad
24 
25 Format placeholders:
26     {state} state (paused, playing. stopped) can be defined via `state_..`
27         configuration parameters
28     Refer to the mpc(1) manual page for the list of available placeholders to
29     be used in the format.  Placeholders should use braces `{}` rather than
30     percent `%%` eg `{artist}`.
31     Every placeholder can also be prefixed with
32     `next_` to retrieve the data for the song following the one currently
33     playing.
34 
35 Requires:
36     python-mpd2: (NOT python2-mpd2)
37 ```
38 # pip install python-mpd2
39 ```
40 
41 Note: previously formats using %field% where allowed for this module, but
42 standard placeholders should be used.
43 
44 Examples of `format`
45 ```
46 # Show state and (artist -) title, if no title fallback to file:
47 {state} [[[{artist} - ]{title}]|[{file}]]
48 
49 # Show state, [duration], title (or file) and next song title (or file):
50 {state} \[{time}\] [{title}|{file}] → [{next_title}|{next_file}]
51 ```
52 
53 @author shadowprince, zopieux
54 @license Eclipse Public License
55 
56 SAMPLE OUTPUT
57 {'color': '#00ff00', 'full_text': '[play] Music For Programming - Idol Eyes'}
58 
59 paused
60 {'color': '#ffff00', 'full_text': '[pause] Music For Programming - Idol Eyes'}
61 
62 stopped
63 {'color': '#ff0000', 'full_text': '[stop] Music For Programming - Idol Eyes'}
64 """
65 
66 import datetime
67 import re
68 import socket
69 from mpd import MPDClient, CommandError, ConnectionError
70 
71 
72 def song_attr(song, attr):
73     def parse_mtime(date_str):
74         return datetime.datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ")
75 
76     if attr == "time":
77         try:
78             duration = int(song["time"])
79             if duration > 0:
80                 minutes, seconds = divmod(duration, 60)
81                 return "{:d}:{:02d}".format(minutes, seconds)
82             raise ValueError
83         except (KeyError, ValueError):
84             return ""
85     elif attr == "position":
86         try:
87             return "{}".format(int(song["pos"]) + 1)
88         except (KeyError, ValueError):
89             return ""
90     elif attr == "mtime":
91         return parse_mtime(song["last-modified"]).strftime("%c")
92     elif attr == "mdate":
93         return parse_mtime(song["last-modified"]).strftime("%x")
94 
95     return song.get(attr, "")
96 
97 
98 class Py3status:
99     """
100     """
101 
102     # available configuration parameters
103     cache_timeout = 2
104     format = "{state} [[[{artist}] - {title}]|[{file}]]"
105     hide_on_error = False
106     hide_when_paused = False
107     hide_when_stopped = True
108     host = "localhost"
109     max_width = 120
110     password = None
111     port = "6600"
112     state_pause = "[pause]"
113     state_play = "[play]"
114     state_stop = "[stop]"
115 
116     def post_config_hook(self):
117         # Convert from %placeholder% to {placeholder}
118         # This is not perfect but should be good enough
119         if not self.py3.get_placeholders_list(self.format) and "%" in self.format:
120             self.format = re.sub("%([a-z]+)%", r"{\1}", self.format)
121             self.py3.log("Old % style format DEPRECATED use { style format")
122         # class variables:
123         self.client = None
124 
125     def _get_mpd(self, disconnect=False):
126         if disconnect:
127             try:
128                 self.client.disconnect()
129             finally:
130                 self.client = None
131             return
132 
133         try:
134             if self.client is None:
135                 self.client = MPDClient()
136                 self.client.connect(host=self.host, port=self.port)
137                 if self.password:
138                     self.client.password(self.password)
139             return self.client
140         except (socket.error, ConnectionError, CommandError) as e:
141             self.client = None
142             raise e
143 
144     def _state_character(self, state):
145         if state == "play":
146             return self.state_play
147         elif state == "pause":
148             return self.state_pause
149         elif state == "stop":
150             return self.state_stop
151         return "?"
152 
153     def current_track(self):
154         try:
155             status = self._get_mpd().status()
156             song = int(status.get("song", 0))
157             next_song = int(status.get("nextsong", 0))
158 
159             state = status.get("state")
160 
161             if (state == "pause" and self.hide_when_paused) or (
162                 state == "stop" and self.hide_when_stopped
163             ):
164                 text = ""
165 
166             else:
167                 playlist_info = self._get_mpd().playlistinfo()
168                 try:
169                     song = playlist_info[song]
170                 except IndexError:
171                     song = {}
172                 try:
173                     next_song = playlist_info[next_song]
174                 except IndexError:
175                     next_song = {}
176 
177                 song["state"] = next_song["state"] = self._state_character(state)
178 
179                 def attr_getter(attr):
180                     if attr.startswith("next_"):
181                         return song_attr(next_song, attr[5:])
182                     return song_attr(song, attr)
183 
184                 text = self.py3.safe_format(self.format, attr_getter=attr_getter)
185 
186         except ValueError:
187             # when status.get(...) returns None; e.g. during reversal of playlist
188             text = "No song information!"
189             state = None
190         except socket.error:
191             text = "Failed to connect to mpd!"
192             state = None
193         except ConnectionError:
194             text = "Error while connecting to mpd!"
195             state = None
196             self._get_mpd(disconnect=True)
197         except CommandError:
198             text = "Failed to authenticate to mpd!"
199             state = None
200             self._get_mpd(disconnect=True)
201 
202         if len(text) > self.max_width:
203             text = u"{}...".format(text[: self.max_width - 3])
204 
205         response = {
206             "cached_until": self.py3.time_in(self.cache_timeout),
207             "full_text": text if state or not self.hide_on_error else "",
208         }
209 
210         if state:
211             if state == "play":
212                 response["color"] = self.py3.COLOR_PLAY or self.py3.COLOR_GOOD
213             elif state == "pause":
214                 response["color"] = self.py3.COLOR_PAUSE or self.py3.COLOR_DEGRADED
215             elif state == "stop":
216                 response["color"] = self.py3.COLOR_STOP or self.py3.COLOR_BAD
217 
218         return response
219 
220     def kill(self):
221         self._get_mpd(disconnect=True)
222 
223 
224 if __name__ == "__main__":
225     """
226     Run module in test mode.
227     """
228     from py3status.module_test import module_test
229 
230     module_test(Py3status)
231
```
--- 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/py3status/modules/mpd_status.py b/py3status/modules/mpd_status.py
--- a/py3status/modules/mpd_status.py
+++ b/py3status/modules/mpd_status.py
@@ -66,6 +66,7 @@
 import datetime
 import re
 import socket
+from py3status.composite import Composite
 from mpd import MPDClient, CommandError, ConnectionError
 
 
@@ -182,6 +183,8 @@
                     return song_attr(song, attr)
 
                 text = self.py3.safe_format(self.format, attr_getter=attr_getter)
+                if isinstance(text, Composite):
+                    text = text.text()
 
         except ValueError:
             # when status.get(...) returns None; e.g. during reversal of playlist

{"golden_diff": "diff --git a/py3status/modules/mpd_status.py b/py3status/modules/mpd_status.py\n--- a/py3status/modules/mpd_status.py\n+++ b/py3status/modules/mpd_status.py\n@@ -66,6 +66,7 @@\n import datetime\n import re\n import socket\n+from py3status.composite import Composite\n from mpd import MPDClient, CommandError, ConnectionError\n \n \n@@ -182,6 +183,8 @@\n                     return song_attr(song, attr)\n \n                 text = self.py3.safe_format(self.format, attr_getter=attr_getter)\n+                if isinstance(text, Composite):\n+                    text = text.text()\n \n         except ValueError:\n             # when status.get(...) returns None; e.g. during reversal of playlist\n", "issue": "mpd_status 'max_width' ineffective\n- **Archlinux**\r\n- **py3status version 3.15**\r\n- **python-mpd2 version 1.0.0-2**\r\n- **window manager 'sway-git' (same with i3)**\r\n\r\nNew to py3status, coming from i3blocks where I had a script to limit the output of characters to a set length.  Using mpd_status module in py3status, I see there is an option for max_width.  I have set this to 50, yet this has no effect on the artist/track name displayed.  Here is the mpd_status block I'm using...\r\n\r\n```\r\nmpd_status {\r\n        name = \"\uf025\"\r\n\tformat = \"{name} [[[{artist} - ]{title}]|[{file}]]\"\r\n        on_click 1 = \"exec mpc prev\"\r\n        on_click 2 = \"exec mpc toggle\"\r\n        on_click 3 = \"exec mpc next\"\r\n        color_play = \"#ffffff\"\r\n        color_stop = \"#ffffff\"\r\n        color_pause = \"#676E7D\"\r\n\tmax_width = 50\r\n}\r\n```\r\n\r\n- **What I expect to see**\r\nArtist and song info printed in py3status that is longer than 50 chars, cut to 50 with \"...\" appended.\r\n\r\n- **What I actually see**\r\nArtist and song info is printed in full regardless of the max_width setting.\nmpd_status 'max_width' ineffective\n- **Archlinux**\r\n- **py3status version 3.15**\r\n- **python-mpd2 version 1.0.0-2**\r\n- **window manager 'sway-git' (same with i3)**\r\n\r\nNew to py3status, coming from i3blocks where I had a script to limit the output of characters to a set length.  Using mpd_status module in py3status, I see there is an option for max_width.  I have set this to 50, yet this has no effect on the artist/track name displayed.  Here is the mpd_status block I'm using...\r\n\r\n```\r\nmpd_status {\r\n        name = \"\uf025\"\r\n\tformat = \"{name} [[[{artist} - ]{title}]|[{file}]]\"\r\n        on_click 1 = \"exec mpc prev\"\r\n        on_click 2 = \"exec mpc toggle\"\r\n        on_click 3 = \"exec mpc next\"\r\n        color_play = \"#ffffff\"\r\n        color_stop = \"#ffffff\"\r\n        color_pause = \"#676E7D\"\r\n\tmax_width = 50\r\n}\r\n```\r\n\r\n- **What I expect to see**\r\nArtist and song info printed in py3status that is longer than 50 chars, cut to 50 with \"...\" appended.\r\n\r\n- **What I actually see**\r\nArtist and song info is printed in full regardless of the max_width setting.\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\nDisplay song currently playing in mpd.\n\nConfiguration parameters:\n    cache_timeout: how often we refresh this module in seconds (default 2)\n    format: template string (see below)\n        (default '{state} [[[{artist}] - {title}]|[{file}]]')\n    hide_on_error: hide the status if an error has occurred (default False)\n    hide_when_paused: hide the status if state is paused (default False)\n    hide_when_stopped: hide the status if state is stopped (default True)\n    host: mpd host (default 'localhost')\n    max_width: maximum status length (default 120)\n    password: mpd password (default None)\n    port: mpd port (default '6600')\n    state_pause: label to display for \"paused\" state (default '[pause]')\n    state_play: label to display for \"playing\" state (default '[play]')\n    state_stop: label to display for \"stopped\" state (default '[stop]')\n\nColor options:\n    color_pause: Paused, default color_degraded\n    color_play: Playing, default color_good\n    color_stop: Stopped, default color_bad\n\nFormat placeholders:\n    {state} state (paused, playing. stopped) can be defined via `state_..`\n        configuration parameters\n    Refer to the mpc(1) manual page for the list of available placeholders to\n    be used in the format.  Placeholders should use braces `{}` rather than\n    percent `%%` eg `{artist}`.\n    Every placeholder can also be prefixed with\n    `next_` to retrieve the data for the song following the one currently\n    playing.\n\nRequires:\n    python-mpd2: (NOT python2-mpd2)\n```\n# pip install python-mpd2\n```\n\nNote: previously formats using %field% where allowed for this module, but\nstandard placeholders should be used.\n\nExamples of `format`\n```\n# Show state and (artist -) title, if no title fallback to file:\n{state} [[[{artist} - ]{title}]|[{file}]]\n\n# Show state, [duration], title (or file) and next song title (or file):\n{state} \\[{time}\\] [{title}|{file}] \u2192 [{next_title}|{next_file}]\n```\n\n@author shadowprince, zopieux\n@license Eclipse Public License\n\nSAMPLE OUTPUT\n{'color': '#00ff00', 'full_text': '[play] Music For Programming - Idol Eyes'}\n\npaused\n{'color': '#ffff00', 'full_text': '[pause] Music For Programming - Idol Eyes'}\n\nstopped\n{'color': '#ff0000', 'full_text': '[stop] Music For Programming - Idol Eyes'}\n\"\"\"\n\nimport datetime\nimport re\nimport socket\nfrom mpd import MPDClient, CommandError, ConnectionError\n\n\ndef song_attr(song, attr):\n    def parse_mtime(date_str):\n        return datetime.datetime.strptime(date_str, \"%Y-%m-%dT%H:%M:%SZ\")\n\n    if attr == \"time\":\n        try:\n            duration = int(song[\"time\"])\n            if duration > 0:\n                minutes, seconds = divmod(duration, 60)\n                return \"{:d}:{:02d}\".format(minutes, seconds)\n            raise ValueError\n        except (KeyError, ValueError):\n            return \"\"\n    elif attr == \"position\":\n        try:\n            return \"{}\".format(int(song[\"pos\"]) + 1)\n        except (KeyError, ValueError):\n            return \"\"\n    elif attr == \"mtime\":\n        return parse_mtime(song[\"last-modified\"]).strftime(\"%c\")\n    elif attr == \"mdate\":\n        return parse_mtime(song[\"last-modified\"]).strftime(\"%x\")\n\n    return song.get(attr, \"\")\n\n\nclass Py3status:\n    \"\"\"\n    \"\"\"\n\n    # available configuration parameters\n    cache_timeout = 2\n    format = \"{state} [[[{artist}] - {title}]|[{file}]]\"\n    hide_on_error = False\n    hide_when_paused = False\n    hide_when_stopped = True\n    host = \"localhost\"\n    max_width = 120\n    password = None\n    port = \"6600\"\n    state_pause = \"[pause]\"\n    state_play = \"[play]\"\n    state_stop = \"[stop]\"\n\n    def post_config_hook(self):\n        # Convert from %placeholder% to {placeholder}\n        # This is not perfect but should be good enough\n        if not self.py3.get_placeholders_list(self.format) and \"%\" in self.format:\n            self.format = re.sub(\"%([a-z]+)%\", r\"{\\1}\", self.format)\n            self.py3.log(\"Old % style format DEPRECATED use { style format\")\n        # class variables:\n        self.client = None\n\n    def _get_mpd(self, disconnect=False):\n        if disconnect:\n            try:\n                self.client.disconnect()\n            finally:\n                self.client = None\n            return\n\n        try:\n            if self.client is None:\n                self.client = MPDClient()\n                self.client.connect(host=self.host, port=self.port)\n                if self.password:\n                    self.client.password(self.password)\n            return self.client\n        except (socket.error, ConnectionError, CommandError) as e:\n            self.client = None\n            raise e\n\n    def _state_character(self, state):\n        if state == \"play\":\n            return self.state_play\n        elif state == \"pause\":\n            return self.state_pause\n        elif state == \"stop\":\n            return self.state_stop\n        return \"?\"\n\n    def current_track(self):\n        try:\n            status = self._get_mpd().status()\n            song = int(status.get(\"song\", 0))\n            next_song = int(status.get(\"nextsong\", 0))\n\n            state = status.get(\"state\")\n\n            if (state == \"pause\" and self.hide_when_paused) or (\n                state == \"stop\" and self.hide_when_stopped\n            ):\n                text = \"\"\n\n            else:\n                playlist_info = self._get_mpd().playlistinfo()\n                try:\n                    song = playlist_info[song]\n                except IndexError:\n                    song = {}\n                try:\n                    next_song = playlist_info[next_song]\n                except IndexError:\n                    next_song = {}\n\n                song[\"state\"] = next_song[\"state\"] = self._state_character(state)\n\n                def attr_getter(attr):\n                    if attr.startswith(\"next_\"):\n                        return song_attr(next_song, attr[5:])\n                    return song_attr(song, attr)\n\n                text = self.py3.safe_format(self.format, attr_getter=attr_getter)\n\n        except ValueError:\n            # when status.get(...) returns None; e.g. during reversal of playlist\n            text = \"No song information!\"\n            state = None\n        except socket.error:\n            text = \"Failed to connect to mpd!\"\n            state = None\n        except ConnectionError:\n            text = \"Error while connecting to mpd!\"\n            state = None\n            self._get_mpd(disconnect=True)\n        except CommandError:\n            text = \"Failed to authenticate to mpd!\"\n            state = None\n            self._get_mpd(disconnect=True)\n\n        if len(text) > self.max_width:\n            text = u\"{}...\".format(text[: self.max_width - 3])\n\n        response = {\n            \"cached_until\": self.py3.time_in(self.cache_timeout),\n            \"full_text\": text if state or not self.hide_on_error else \"\",\n        }\n\n        if state:\n            if state == \"play\":\n                response[\"color\"] = self.py3.COLOR_PLAY or self.py3.COLOR_GOOD\n            elif state == \"pause\":\n                response[\"color\"] = self.py3.COLOR_PAUSE or self.py3.COLOR_DEGRADED\n            elif state == \"stop\":\n                response[\"color\"] = self.py3.COLOR_STOP or self.py3.COLOR_BAD\n\n        return response\n\n    def kill(self):\n        self._get_mpd(disconnect=True)\n\n\nif __name__ == \"__main__\":\n    \"\"\"\n    Run module in test mode.\n    \"\"\"\n    from py3status.module_test import module_test\n\n    module_test(Py3status)\n", "path": "py3status/modules/mpd_status.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\nDisplay song currently playing in mpd.\n\nConfiguration parameters:\n    cache_timeout: how often we refresh this module in seconds (default 2)\n    format: template string (see below)\n        (default '{state} [[[{artist}] - {title}]|[{file}]]')\n    hide_on_error: hide the status if an error has occurred (default False)\n    hide_when_paused: hide the status if state is paused (default False)\n    hide_when_stopped: hide the status if state is stopped (default True)\n    host: mpd host (default 'localhost')\n    max_width: maximum status length (default 120)\n    password: mpd password (default None)\n    port: mpd port (default '6600')\n    state_pause: label to display for \"paused\" state (default '[pause]')\n    state_play: label to display for \"playing\" state (default '[play]')\n    state_stop: label to display for \"stopped\" state (default '[stop]')\n\nColor options:\n    color_pause: Paused, default color_degraded\n    color_play: Playing, default color_good\n    color_stop: Stopped, default color_bad\n\nFormat placeholders:\n    {state} state (paused, playing. stopped) can be defined via `state_..`\n        configuration parameters\n    Refer to the mpc(1) manual page for the list of available placeholders to\n    be used in the format.  Placeholders should use braces `{}` rather than\n    percent `%%` eg `{artist}`.\n    Every placeholder can also be prefixed with\n    `next_` to retrieve the data for the song following the one currently\n    playing.\n\nRequires:\n    python-mpd2: (NOT python2-mpd2)\n```\n# pip install python-mpd2\n```\n\nNote: previously formats using %field% where allowed for this module, but\nstandard placeholders should be used.\n\nExamples of `format`\n```\n# Show state and (artist -) title, if no title fallback to file:\n{state} [[[{artist} - ]{title}]|[{file}]]\n\n# Show state, [duration], title (or file) and next song title (or file):\n{state} \\[{time}\\] [{title}|{file}] \u2192 [{next_title}|{next_file}]\n```\n\n@author shadowprince, zopieux\n@license Eclipse Public License\n\nSAMPLE OUTPUT\n{'color': '#00ff00', 'full_text': '[play] Music For Programming - Idol Eyes'}\n\npaused\n{'color': '#ffff00', 'full_text': '[pause] Music For Programming - Idol Eyes'}\n\nstopped\n{'color': '#ff0000', 'full_text': '[stop] Music For Programming - Idol Eyes'}\n\"\"\"\n\nimport datetime\nimport re\nimport socket\nfrom py3status.composite import Composite\nfrom mpd import MPDClient, CommandError, ConnectionError\n\n\ndef song_attr(song, attr):\n    def parse_mtime(date_str):\n        return datetime.datetime.strptime(date_str, \"%Y-%m-%dT%H:%M:%SZ\")\n\n    if attr == \"time\":\n        try:\n            duration = int(song[\"time\"])\n            if duration > 0:\n                minutes, seconds = divmod(duration, 60)\n                return \"{:d}:{:02d}\".format(minutes, seconds)\n            raise ValueError\n        except (KeyError, ValueError):\n            return \"\"\n    elif attr == \"position\":\n        try:\n            return \"{}\".format(int(song[\"pos\"]) + 1)\n        except (KeyError, ValueError):\n            return \"\"\n    elif attr == \"mtime\":\n        return parse_mtime(song[\"last-modified\"]).strftime(\"%c\")\n    elif attr == \"mdate\":\n        return parse_mtime(song[\"last-modified\"]).strftime(\"%x\")\n\n    return song.get(attr, \"\")\n\n\nclass Py3status:\n    \"\"\"\n    \"\"\"\n\n    # available configuration parameters\n    cache_timeout = 2\n    format = \"{state} [[[{artist}] - {title}]|[{file}]]\"\n    hide_on_error = False\n    hide_when_paused = False\n    hide_when_stopped = True\n    host = \"localhost\"\n    max_width = 120\n    password = None\n    port = \"6600\"\n    state_pause = \"[pause]\"\n    state_play = \"[play]\"\n    state_stop = \"[stop]\"\n\n    def post_config_hook(self):\n        # Convert from %placeholder% to {placeholder}\n        # This is not perfect but should be good enough\n        if not self.py3.get_placeholders_list(self.format) and \"%\" in self.format:\n            self.format = re.sub(\"%([a-z]+)%\", r\"{\\1}\", self.format)\n            self.py3.log(\"Old % style format DEPRECATED use { style format\")\n        # class variables:\n        self.client = None\n\n    def _get_mpd(self, disconnect=False):\n        if disconnect:\n            try:\n                self.client.disconnect()\n            finally:\n                self.client = None\n            return\n\n        try:\n            if self.client is None:\n                self.client = MPDClient()\n                self.client.connect(host=self.host, port=self.port)\n                if self.password:\n                    self.client.password(self.password)\n            return self.client\n        except (socket.error, ConnectionError, CommandError) as e:\n            self.client = None\n            raise e\n\n    def _state_character(self, state):\n        if state == \"play\":\n            return self.state_play\n        elif state == \"pause\":\n            return self.state_pause\n        elif state == \"stop\":\n            return self.state_stop\n        return \"?\"\n\n    def current_track(self):\n        try:\n            status = self._get_mpd().status()\n            song = int(status.get(\"song\", 0))\n            next_song = int(status.get(\"nextsong\", 0))\n\n            state = status.get(\"state\")\n\n            if (state == \"pause\" and self.hide_when_paused) or (\n                state == \"stop\" and self.hide_when_stopped\n            ):\n                text = \"\"\n\n            else:\n                playlist_info = self._get_mpd().playlistinfo()\n                try:\n                    song = playlist_info[song]\n                except IndexError:\n                    song = {}\n                try:\n                    next_song = playlist_info[next_song]\n                except IndexError:\n                    next_song = {}\n\n                song[\"state\"] = next_song[\"state\"] = self._state_character(state)\n\n                def attr_getter(attr):\n                    if attr.startswith(\"next_\"):\n                        return song_attr(next_song, attr[5:])\n                    return song_attr(song, attr)\n\n                text = self.py3.safe_format(self.format, attr_getter=attr_getter)\n                if isinstance(text, Composite):\n                    text = text.text()\n\n        except ValueError:\n            # when status.get(...) returns None; e.g. during reversal of playlist\n            text = \"No song information!\"\n            state = None\n        except socket.error:\n            text = \"Failed to connect to mpd!\"\n            state = None\n        except ConnectionError:\n            text = \"Error while connecting to mpd!\"\n            state = None\n            self._get_mpd(disconnect=True)\n        except CommandError:\n            text = \"Failed to authenticate to mpd!\"\n            state = None\n            self._get_mpd(disconnect=True)\n\n        if len(text) > self.max_width:\n            text = u\"{}...\".format(text[: self.max_width - 3])\n\n        response = {\n            \"cached_until\": self.py3.time_in(self.cache_timeout),\n            \"full_text\": text if state or not self.hide_on_error else \"\",\n        }\n\n        if state:\n            if state == \"play\":\n                response[\"color\"] = self.py3.COLOR_PLAY or self.py3.COLOR_GOOD\n            elif state == \"pause\":\n                response[\"color\"] = self.py3.COLOR_PAUSE or self.py3.COLOR_DEGRADED\n            elif state == \"stop\":\n                response[\"color\"] = self.py3.COLOR_STOP or self.py3.COLOR_BAD\n\n        return response\n\n    def kill(self):\n        self._get_mpd(disconnect=True)\n\n\nif __name__ == \"__main__\":\n    \"\"\"\n    Run module in test mode.\n    \"\"\"\n    from py3status.module_test import module_test\n\n    module_test(Py3status)\n", "path": "py3status/modules/mpd_status.py"}]}