Merge ~stanley31/checkbox-support:0909_modify_audio_settings into checkbox-support:master
- Git
- lp:~stanley31/checkbox-support
- 0909_modify_audio_settings
- Merge into master
Status: | Merged |
---|---|
Approved by: | Jonathan Cave |
Approved revision: | 319abca420c49214796fc7f4dbd5c658afa5c7b7 |
Merged at revision: | b136d7c36518807fc15cfa8d30c98b84f9ccdfe2 |
Proposed branch: | ~stanley31/checkbox-support:0909_modify_audio_settings |
Merge into: | checkbox-support:master |
Diff against target: |
313 lines (+87/-57) 2 files modified
checkbox_support/scripts/audio_settings.py (+82/-55) checkbox_support/scripts/tests/test_audio_settings.py (+5/-2) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jonathan Cave (community) | Approve | ||
Devices Certification Bot | Needs Fixing | ||
Maciej Kisielewski | Approve | ||
Review via email: mp+408339@code.launchpad.net |
Commit message
A fixed for lp:1940391
Description of the change
I have validated the audio_settings script could parse the volume from mono/stereo audio interface.
Test this script on a system with input (mono) audio and output (stereo) audio.
detail audio information:
{'name': 'bluez_
{'name': 'alsa_output.
I have ran the store_audio_
default_source: bluez_source.
source_muted: no
source_volume: 100%
default_sink: alsa_output.
sink_muted: no
sink_volume: 64%
StanleyHuang (stanley31) wrote : | # |
@Maciej,
May I have your suggestion for the way to format string?
option 1: use .format
option 2: use f"" string
If the script would only run under Python 3.6 up, I think the option 2 is a better solution due to it makes the string more readable.
Thanks.
StanleyHuang (stanley31) wrote : | # |
I think the ".format" might be a option due to we need to replace string for some pattern variables.
StanleyHuang (stanley31) wrote : | # |
Two commits for this MR.
first one is to change the way to parse audio volumes.
second one is to unified the format string method.
And it has been tested on my laptop with stereo and mono audio devices.
the stereo logs:
>>> print(get_
{'name': 'alsa_input.
>>> print(get_
{'name': 'alsa_output.
the mono logs:
>>> print(get_
{'name': 'bluez_
>>> print(get_
{'name': 'bluez_
Maciej Kisielewski (kissiel) wrote : | # |
Great stuff! Thank you for all the patches. As for which string interpolation option, I think .format() is great. One thing to note, though, is for logging calls the %s should be used, as this prevents formatting from happening unless the logging call is on the right level (it's evaluated lazily). You can read more here: https:/
I'm +1 on landing this.
Devices Certification Bot (ce-certification-qa) wrote : | # |
The merge was fine but running tests failed.
"10.38.105.54"
"10.38.105.108"
"10.38.105.197"
[xenial] [14:06:01] starting container
Device project added to xenial-testing
"10.38.105.54"
[xenial] [14:07:16] provisioning container
[xenial] [14:09:26] Starting tests...
[xenial] Found a test script: ./requirements/
[bionic] [14:09:52] starting container
Device project added to bionic-testing
[xenial] [14:10:03] container-
[xenial] output:
[xenial] [14:10:03] Fixing file permissions in source directory
[xenial] [14:10:04] Destroying container
[focal] [14:10:28] starting container
Device project added to focal-testing
"10.38.105.115"
[bionic] [14:10:41] provisioning container
"10.38.105.137"
[focal] [14:10:59] provisioning container
[bionic] [14:11:09] Starting tests...
[bionic] Found a test script: ./requirements/
[focal] [14:11:29] Starting tests...
[focal] Found a test script: ./requirements/
[bionic] [14:11:48] container-
[bionic] output:
[bionic] [14:11:48] Fixing file permissions in source directory
[bionic] [14:11:48] Destroying container
[focal] [14:12:03] container-
[focal] output:
[focal] [14:12:03] Fixing file permissions in source directory
[focal] [14:12:03] Destroying container
Devices Certification Bot (ce-certification-qa) wrote : | # |
The merge was fine but running tests failed.
"10.38.105.54"
"10.38.105.108"
"10.38.105.197"
[xenial] [14:40:43] starting container
[bionic] [14:40:45] starting container
[focal] [14:40:52] starting container
Device project added to xenial-testing
Device project added to bionic-testing
"10.38.105.54"
[xenial] [14:41:02] provisioning container
Device project added to focal-testing
"10.38.105.141"
[bionic] [14:41:06] provisioning container
"10.38.105.142"
[focal] [14:41:13] provisioning container
[bionic] [14:41:44] Starting tests...
[bionic] Found a test script: ./requirements/
[focal] [14:41:51] Starting tests...
[focal] Found a test script: ./requirements/
[bionic] [14:42:17] container-
[bionic] output:
[bionic] [14:42:17] Fixing file permissions in source directory
[bionic] [14:42:18] Destroying container
[xenial] [14:42:18] Starting tests...
[xenial] Found a test script: ./requirements/
[focal] [14:42:21] container-
[focal] output:
[focal] [14:42:21] Fixing file permissions in source directory
[focal] [14:42:22] Destroying container
[xenial] [14:42:50] container-
[xenial] output:
[xenial] [14:42:50] Fixing file permissions in source directory
[xenial] [14:42:50] Destroying container
Devices Certification Bot (ce-certification-qa) wrote : | # |
The merge was fine but running tests failed.
"10.38.105.54"
"10.38.105.108"
"10.38.105.197"
[xenial] [17:35:38] starting container
[focal] [17:35:44] starting container
Device project added to xenial-testing
Device project added to focal-testing
"10.38.105.54"
[xenial] [17:35:56] provisioning container
"10.38.105.151"
[focal] [17:36:06] provisioning container
[bionic] [17:36:07] starting container
Device project added to bionic-testing
"10.38.105.154"
[bionic] [17:36:26] provisioning container
[focal] [17:36:38] Starting tests...
[focal] Found a test script: ./requirements/
[bionic] [17:36:55] Starting tests...
[bionic] Found a test script: ./requirements/
[focal] [17:37:08] container-
[focal] output: https:/
[focal] [17:37:11] Fixing file permissions in source directory
[focal] [17:37:11] Destroying container
[xenial] [17:37:20] Starting tests...
[xenial] Found a test script: ./requirements/
[bionic] [17:37:28] container-
[bionic] output: https:/
[bionic] [17:37:30] Fixing file permissions in source directory
[bionic] [17:37:31] Destroying container
[xenial] [17:37:52] container-
[xenial] output: https:/
[xenial] [17:37:54] Fixing file permissions in source directory
[xenial] [17:37:54] Destroying container
Jonathan Cave (jocave) wrote : | # |
@Stanley the unit tests need updating for this script. See the pastebins above for failure
StanleyHuang (stanley31) wrote : | # |
attached test results of the unit test:
test_volume_
Testing pactl 4.0 output ... ok
test_volume_
Testing pactl 8.0 output ... ok
test_desktop_
Bionic system with a Intel UHD Graphics chipset, it's DMIC system. ... ok
test_desktop_
Home-made system running Precise with a Radeon card. ... ok
test_desktop_
Home-made system running Precise with a Radeon card. ... ok
test_desktop_
Precise system with a Nvidia chipset. ... ok
test_desktop_
Raring system with a Mini-DisplayPort. ... ok
test_desktop_
Raring system with a Mini-DisplayPort. ... ok
-------
Ran 8 tests in 7.784s
OK
Jonathan Cave (jocave) wrote : | # |
Hmmm I'm wondering why they are passing for you because I'm seeing:
=======
ERROR: test_volume_
Testing pactl 4.0 output
-------
Traceback (most recent call last):
File "/home/
volume_regex = re.compile(
TypeError: not all arguments converted during string formatting
=======
ERROR: test_volume_
Testing pactl 8.0 output
-------
Traceback (most recent call last):
File "/home/
volume_regex = re.compile(
TypeError: not all arguments converted during string formatting
StanleyHuang (stanley31) wrote : | # |
Interesting, I guess it related to the python version.
I am going to take a look how does the audio_settings scripts works in trusty and xenial (with default python environment.
> Hmmm I'm wondering why they are passing for you because I'm seeing:
>
> =======
> ERROR: test_volume_
> (checkbox_
> Testing pactl 4.0 output
> -------
> Traceback (most recent call last):
> File "/home/
> support/
> test_volume_
> volume_regex = re.compile(
> TypeError: not all arguments converted during string formatting
>
> =======
> ERROR: test_volume_
> (checkbox_
> Testing pactl 8.0 output
> -------
> Traceback (most recent call last):
> File "/home/
> support/
> test_volume_
> volume_regex = re.compile(
> TypeError: not all arguments converted during string formatting
StanleyHuang (stanley31) wrote : | # |
I have modified the way to format string, and run the unittest on focal and impish.
@jocave, please give it a try on your test environment. Thanks.
Jonathan Cave (jocave) wrote : | # |
Yep, this works for me now. Attempting to land...
Preview Diff
1 | diff --git a/checkbox_support/scripts/audio_settings.py b/checkbox_support/scripts/audio_settings.py | |||
2 | index 6c00743..2cf6a3f 100644 | |||
3 | --- a/checkbox_support/scripts/audio_settings.py | |||
4 | +++ b/checkbox_support/scripts/audio_settings.py | |||
5 | @@ -36,13 +36,16 @@ from checkbox_support.snap_utils.system import in_classic_snap | |||
6 | 36 | TYPES = ("source", "sink") | 36 | TYPES = ("source", "sink") |
7 | 37 | DIRECTIONS = {"source": "input", "sink": "output"} | 37 | DIRECTIONS = {"source": "input", "sink": "output"} |
8 | 38 | 38 | ||
9 | 39 | # use %s string format to compatible with other python version | ||
10 | 39 | default_pattern = "(?<=Default %s: ).*" | 40 | default_pattern = "(?<=Default %s: ).*" |
11 | 40 | index_regex = re.compile("(?<=Sink Input #)[0-9]*") | 41 | index_regex = re.compile("(?<=Sink Input #)[0-9]*") |
12 | 41 | muted_regex = re.compile("(?<=Mute: ).*") | 42 | muted_regex = re.compile("(?<=Mute: ).*") |
13 | 42 | volume_regex = re.compile("Volume: (?:0|front-left):[\s\/0-9]*\s([0-9]*)") | ||
14 | 43 | name_regex = re.compile("(?<=Name:).*") | 43 | name_regex = re.compile("(?<=Name:).*") |
15 | 44 | channel_map_regex = re.compile("(?<=Channel Map: ).*") | ||
16 | 44 | 45 | ||
17 | 46 | # use %s string format to compatible with other python version | ||
18 | 45 | entry_pattern = "Name: %s.*?(?=Properties)" | 47 | entry_pattern = "Name: %s.*?(?=Properties)" |
19 | 48 | volume_pattern = r"Volume: .*(?:%s):[\w\/0-9 ]* ([0-9]*)%%" | ||
20 | 46 | 49 | ||
21 | 47 | 50 | ||
22 | 48 | def unlocalized_env(reset={"LANG": "POSIX.UTF-8"}): | 51 | def unlocalized_env(reset={"LANG": "POSIX.UTF-8"}): |
23 | @@ -144,8 +147,8 @@ def set_profile_hdmi(): | |||
24 | 144 | try: | 147 | try: |
25 | 145 | check_call(["pactl", "set-card-profile", card, profile]) | 148 | check_call(["pactl", "set-card-profile", card, profile]) |
26 | 146 | except CalledProcessError as error: | 149 | except CalledProcessError as error: |
29 | 147 | logging.error("Failed setting audio output to:%s: %s" % | 150 | logging.error("Failed setting audio output to:{}: {}".format( |
30 | 148 | (profile, error)) | 151 | profile, error)) |
31 | 149 | 152 | ||
32 | 150 | 153 | ||
33 | 151 | def get_current_profiles_settings(profiles_file): | 154 | def get_current_profiles_settings(profiles_file): |
34 | @@ -156,8 +159,8 @@ def get_current_profiles_settings(profiles_file): | |||
35 | 156 | config = configparser.ConfigParser() | 159 | config = configparser.ConfigParser() |
36 | 157 | 160 | ||
37 | 158 | for match in re.finditer( | 161 | for match in re.finditer( |
40 | 159 | "(?P<card_id>Card #\d+)\n\tName:\s+(?P<card_name>.*?)\n.*?" | 162 | r"(?P<card_id>Card #\d+)\n\tName:\s+(?P<card_name>.*?)\n.*?" |
41 | 160 | "Active\sProfile:\s+(?P<profile>.*?)\n", pactl_list, re.M | re.S | 163 | r"Active\sProfile:\s+(?P<profile>.*?)\n", pactl_list, re.M | re.S |
42 | 161 | ): | 164 | ): |
43 | 162 | config[match.group('card_id')] = { | 165 | config[match.group('card_id')] = { |
44 | 163 | 'name': match.group('card_name'), | 166 | 'name': match.group('card_name'), |
45 | @@ -168,8 +171,8 @@ def get_current_profiles_settings(profiles_file): | |||
46 | 168 | with open(profiles_file, 'w') as active_profiles: | 171 | with open(profiles_file, 'w') as active_profiles: |
47 | 169 | config.write(active_profiles) | 172 | config.write(active_profiles) |
48 | 170 | except IOError: | 173 | except IOError: |
51 | 171 | logging.error("Failed to save active profiles information: %s" % | 174 | logging.error("Failed to save active profiles information: {}".format( |
52 | 172 | sys.exc_info()[1]) | 175 | sys.exc_info()[1])) |
53 | 173 | 176 | ||
54 | 174 | 177 | ||
55 | 175 | def restore_profiles_settings(profiles_file): | 178 | def restore_profiles_settings(profiles_file): |
56 | @@ -184,9 +187,9 @@ def restore_profiles_settings(profiles_file): | |||
57 | 184 | check_call(["pactl", "set-card-profile", config[card]['name'], | 187 | check_call(["pactl", "set-card-profile", config[card]['name'], |
58 | 185 | config[card]['profile']]) | 188 | config[card]['profile']]) |
59 | 186 | except CalledProcessError as error: | 189 | except CalledProcessError as error: |
63 | 187 | logging.error("Failed setting card <%s> profile to <%s>: %s" % | 190 | logging.error( |
64 | 188 | (config[card]['name'], | 191 | "Failed setting card <{}> profile to <{}>: {}".format( |
65 | 189 | config[card]['profile'], error)) | 192 | config[card]['name'], config[card]['profile'], error)) |
66 | 190 | 193 | ||
67 | 191 | 194 | ||
68 | 192 | def move_sinks(name): | 195 | def move_sinks(name): |
69 | @@ -201,49 +204,68 @@ def move_sinks(name): | |||
70 | 201 | check_call(["pactl", "move-sink-input", input_index, name], | 204 | check_call(["pactl", "move-sink-input", input_index, name], |
71 | 202 | stdout=DEVNULL) | 205 | stdout=DEVNULL) |
72 | 203 | except CalledProcessError: | 206 | except CalledProcessError: |
75 | 204 | logging.error("Failed to move input %d to sink %d" % | 207 | logging.error("Failed to move input {} to sink {}".format( |
76 | 205 | (input_index, name)) | 208 | input_index, name)) |
77 | 206 | sys.exit(1) | 209 | sys.exit(1) |
78 | 207 | 210 | ||
79 | 208 | 211 | ||
80 | 212 | def get_audio_settings(type, name="default"): | ||
81 | 213 | if name == "default": | ||
82 | 214 | pactl_status = check_output(["pactl", "info"], | ||
83 | 215 | universal_newlines=True, | ||
84 | 216 | env=unlocalized_env()) | ||
85 | 217 | default_regex = re.compile(default_pattern % type.title()) | ||
86 | 218 | name = default_regex.search(pactl_status).group() | ||
87 | 219 | |||
88 | 220 | pactl_list = check_output(["pactl", "list", "{}s".format(type)], | ||
89 | 221 | universal_newlines=True, | ||
90 | 222 | env=unlocalized_env()) | ||
91 | 223 | entry_regex = re.compile(entry_pattern % name, re.DOTALL) | ||
92 | 224 | entry = entry_regex.search(pactl_list).group() | ||
93 | 225 | |||
94 | 226 | muted = muted_regex.search(entry).group() | ||
95 | 227 | |||
96 | 228 | volumes = {} | ||
97 | 229 | max_volume = 0 | ||
98 | 230 | channels = channel_map_regex.search(entry).group() | ||
99 | 231 | for channel in channels.split(","): | ||
100 | 232 | volume_regex = re.compile(volume_pattern % channel, re.DOTALL) | ||
101 | 233 | _volume = int(volume_regex.search(entry).group(1).strip()) | ||
102 | 234 | volumes.update({channel: _volume}) | ||
103 | 235 | max_volume = max(_volume, max_volume) | ||
104 | 236 | |||
105 | 237 | return { | ||
106 | 238 | "name": name, | ||
107 | 239 | "muted": muted, | ||
108 | 240 | "volumes": volumes, | ||
109 | 241 | "max_volume": max_volume | ||
110 | 242 | } | ||
111 | 243 | |||
112 | 244 | |||
113 | 209 | def store_audio_settings(file): | 245 | def store_audio_settings(file): |
114 | 210 | logging.info("[ Saving audio settings ]".center(80, '=')) | 246 | logging.info("[ Saving audio settings ]".center(80, '=')) |
115 | 211 | try: | 247 | try: |
116 | 212 | settings_file = open(file, 'w') | 248 | settings_file = open(file, 'w') |
117 | 213 | except IOError: | 249 | except IOError: |
119 | 214 | logging.error("Failed to save settings: %s" % sys.exc_info()[1]) | 250 | logging.error("Failed to save settings: {}".format(sys.exc_info()[1])) |
120 | 215 | sys.exit(1) | 251 | sys.exit(1) |
121 | 216 | 252 | ||
122 | 217 | for type in TYPES: | 253 | for type in TYPES: |
140 | 218 | pactl_status = check_output(["pactl", "info"], | 254 | audio_settings = get_audio_settings(type) |
141 | 219 | universal_newlines=True, | 255 | print("default_{}: {}".format(type, audio_settings["name"]), |
125 | 220 | env=unlocalized_env()) | ||
126 | 221 | default_regex = re.compile(default_pattern % type.title()) | ||
127 | 222 | default = default_regex.search(pactl_status).group() | ||
128 | 223 | |||
129 | 224 | print("default_%s: %s" % (type, default), file=settings_file) | ||
130 | 225 | |||
131 | 226 | pactl_list = check_output(["pactl", "list", type + 's'], | ||
132 | 227 | universal_newlines=True, | ||
133 | 228 | env=unlocalized_env()) | ||
134 | 229 | |||
135 | 230 | entry_regex = re.compile(entry_pattern % default, re.DOTALL) | ||
136 | 231 | entry = entry_regex.search(pactl_list).group() | ||
137 | 232 | |||
138 | 233 | muted = muted_regex.search(entry) | ||
139 | 234 | print("%s_muted: %s" % (type, muted.group().strip()), | ||
142 | 235 | file=settings_file) | 256 | file=settings_file) |
147 | 236 | 257 | print("{}_muted: {}".format(type, audio_settings["muted"].strip()), | |
144 | 237 | volume = int(volume_regex.search(entry).group(1).strip()) | ||
145 | 238 | |||
146 | 239 | print("%s_volume: %s%%" % (type, str(volume)), | ||
148 | 240 | file=settings_file) | 258 | file=settings_file) |
149 | 259 | print("{}_volume: {}%".format( | ||
150 | 260 | type, str(audio_settings["max_volume"])), | ||
151 | 261 | file=settings_file) | ||
152 | 262 | |||
153 | 241 | settings_file.close() | 263 | settings_file.close() |
154 | 242 | 264 | ||
155 | 243 | 265 | ||
156 | 244 | def set_audio_settings(device, mute, volume): | 266 | def set_audio_settings(device, mute, volume): |
157 | 245 | for type in TYPES: | 267 | for type in TYPES: |
159 | 246 | pactl_entries = check_output(["pactl", "list", type + 's'], | 268 | pactl_entries = check_output(["pactl", "list", "{}s".format(type)], |
160 | 247 | universal_newlines=True, | 269 | universal_newlines=True, |
161 | 248 | env=unlocalized_env()) | 270 | env=unlocalized_env()) |
162 | 249 | 271 | ||
163 | @@ -257,10 +279,12 @@ def set_audio_settings(device, mute, volume): | |||
164 | 257 | logging.info("[ Fallback sink ]".center(80, '=')) | 279 | logging.info("[ Fallback sink ]".center(80, '=')) |
165 | 258 | logging.info("Name: {}".format(name)) | 280 | logging.info("Name: {}".format(name)) |
166 | 259 | with open(os.devnull, 'wb') as DEVNULL: | 281 | with open(os.devnull, 'wb') as DEVNULL: |
168 | 260 | check_call(["pactl", "set-default-%s" % type, name], | 282 | check_call(["pactl", |
169 | 283 | "set-default-{}".format(type), | ||
170 | 284 | name], | ||
171 | 261 | stdout=DEVNULL) | 285 | stdout=DEVNULL) |
172 | 262 | except CalledProcessError: | 286 | except CalledProcessError: |
174 | 263 | logging.error("Failed to set default %s" % type) | 287 | logging.error("Failed to set default {}".format(type)) |
175 | 264 | sys.exit(1) | 288 | sys.exit(1) |
176 | 265 | 289 | ||
177 | 266 | if type == "sink": | 290 | if type == "sink": |
178 | @@ -268,16 +292,18 @@ def set_audio_settings(device, mute, volume): | |||
179 | 268 | 292 | ||
180 | 269 | try: | 293 | try: |
181 | 270 | check_call(["pactl", | 294 | check_call(["pactl", |
183 | 271 | "set-%s-mute" % type, name, str(int(mute))]) | 295 | "set-{}-mute".format(type), |
184 | 296 | name, | ||
185 | 297 | str(int(mute))]) | ||
186 | 272 | except: | 298 | except: |
188 | 273 | logging.error("Failed to set mute for %s" % name) | 299 | logging.error("Failed to set mute for {}".format(name)) |
189 | 274 | sys.exit(1) | 300 | sys.exit(1) |
190 | 275 | 301 | ||
191 | 276 | try: | 302 | try: |
194 | 277 | check_call(["pactl", "set-%s-volume" % type, | 303 | check_call(["pactl", "set-{}-volume".format(type), |
195 | 278 | name, str(volume) + '%']) | 304 | name, "{}%".format(str(volume))]) |
196 | 279 | except: | 305 | except: |
198 | 280 | logging.error("Failed to set volume for %s" % name) | 306 | logging.error("Failed to set volume for {}".format(name)) |
199 | 281 | sys.exit(1) | 307 | sys.exit(1) |
200 | 282 | 308 | ||
201 | 283 | 309 | ||
202 | @@ -287,8 +313,8 @@ def restore_audio_settings(file): | |||
203 | 287 | with open(file) as f: | 313 | with open(file) as f: |
204 | 288 | settings_file = f.read().split() | 314 | settings_file = f.read().split() |
205 | 289 | except IOError: | 315 | except IOError: |
208 | 290 | logging.error("Unable to open existing settings file: %s" % | 316 | logging.error("Unable to open existing settings file: {}".format( |
209 | 291 | sys.exc_info()[1]) | 317 | sys.exc_info()[1])) |
210 | 292 | return 1 | 318 | return 1 |
211 | 293 | 319 | ||
212 | 294 | for type in TYPES: | 320 | for type in TYPES: |
213 | @@ -297,10 +323,11 @@ def restore_audio_settings(file): | |||
214 | 297 | # is incorrect, so we just abort. | 323 | # is incorrect, so we just abort. |
215 | 298 | try: | 324 | try: |
216 | 299 | name = settings_file[ | 325 | name = settings_file[ |
219 | 300 | settings_file.index("default_%s:" % type) + 1] | 326 | settings_file.index("default_{}:".format(type)) + 1] |
220 | 301 | muted = settings_file[settings_file.index("%s_muted:" % type) + 1] | 327 | muted = settings_file[ |
221 | 328 | settings_file.index("{}_muted:".format(type)) + 1] | ||
222 | 302 | volume = settings_file[ | 329 | volume = settings_file[ |
224 | 303 | settings_file.index("%s_volume:" % type) + 1] | 330 | settings_file.index("{}_volume:".format(type)) + 1] |
225 | 304 | except ValueError: | 331 | except ValueError: |
226 | 305 | logging.error("Unable to restore settings because settings " | 332 | logging.error("Unable to restore settings because settings " |
227 | 306 | "file is invalid") | 333 | "file is invalid") |
228 | @@ -308,25 +335,25 @@ def restore_audio_settings(file): | |||
229 | 308 | 335 | ||
230 | 309 | try: | 336 | try: |
231 | 310 | with open(os.devnull, 'wb') as DEVNULL: | 337 | with open(os.devnull, 'wb') as DEVNULL: |
233 | 311 | check_call(["pactl", "set-default-%s" % type, name], | 338 | check_call(["pactl", "set-default-{}".format(type), name], |
234 | 312 | stdout=DEVNULL) | 339 | stdout=DEVNULL) |
235 | 313 | except CalledProcessError: | 340 | except CalledProcessError: |
237 | 314 | logging.error("Failed to restore default %s" % name) | 341 | logging.error("Failed to restore default {}".format(name)) |
238 | 315 | return 1 | 342 | return 1 |
239 | 316 | 343 | ||
240 | 317 | if type == "sink": | 344 | if type == "sink": |
241 | 318 | move_sinks(name) | 345 | move_sinks(name) |
242 | 319 | 346 | ||
243 | 320 | try: | 347 | try: |
245 | 321 | check_call(["pactl", "set-%s-mute" % type, name, muted]) | 348 | check_call(["pactl", "set-{}-mute".format(type), name, muted]) |
246 | 322 | except: | 349 | except: |
248 | 323 | logging.error("Failed to restore mute for %s" % name) | 350 | logging.error("Failed to restore mute for {}".format(name)) |
249 | 324 | return 1 | 351 | return 1 |
250 | 325 | 352 | ||
251 | 326 | try: | 353 | try: |
253 | 327 | check_call(["pactl", "set-%s-volume" % type, name, volume]) | 354 | check_call(["pactl", "set-{}-volume".format(type), name, volume]) |
254 | 328 | except: | 355 | except: |
256 | 329 | logging.error("Failed to restore volume for %s" % name) | 356 | logging.error("Failed to restore volume for {}".format(name)) |
257 | 330 | return 1 | 357 | return 1 |
258 | 331 | 358 | ||
259 | 332 | 359 | ||
260 | @@ -359,7 +386,7 @@ def main(): | |||
261 | 359 | logging.error("No file specified to store audio settings!") | 386 | logging.error("No file specified to store audio settings!") |
262 | 360 | return 1 | 387 | return 1 |
263 | 361 | settings_file = args.file | 388 | settings_file = args.file |
265 | 362 | profiles_file = args.file + ".profiles" | 389 | profiles_file = "{}.profiles".format(args.file) |
266 | 363 | 390 | ||
267 | 364 | if args.verbose: | 391 | if args.verbose: |
268 | 365 | logging.basicConfig(format='%(levelname)s:%(message)s', | 392 | logging.basicConfig(format='%(levelname)s:%(message)s', |
269 | @@ -383,7 +410,7 @@ def main(): | |||
270 | 383 | set_profile_hdmi() | 410 | set_profile_hdmi() |
271 | 384 | set_audio_settings(args.device, args.mute, args.volume) | 411 | set_audio_settings(args.device, args.mute, args.volume) |
272 | 385 | else: | 412 | else: |
274 | 386 | logging.error(args.action + "is not a valid action") | 413 | logging.error("{} is not a valid action".format(args.action)) |
275 | 387 | return 1 | 414 | return 1 |
276 | 388 | 415 | ||
277 | 389 | return 0 | 416 | return 0 |
278 | diff --git a/checkbox_support/scripts/tests/test_audio_settings.py b/checkbox_support/scripts/tests/test_audio_settings.py | |||
279 | index 9f81f97..6a6b0ba 100644 | |||
280 | --- a/checkbox_support/scripts/tests/test_audio_settings.py | |||
281 | +++ b/checkbox_support/scripts/tests/test_audio_settings.py | |||
282 | @@ -22,9 +22,10 @@ from __future__ import print_function | |||
283 | 22 | from __future__ import unicode_literals | 22 | from __future__ import unicode_literals |
284 | 23 | 23 | ||
285 | 24 | import os | 24 | import os |
286 | 25 | import re | ||
287 | 25 | import unittest | 26 | import unittest |
288 | 26 | 27 | ||
290 | 27 | from checkbox_support.scripts.audio_settings import _guess_hdmi_profile, volume_regex | 28 | from checkbox_support.scripts.audio_settings import _guess_hdmi_profile, volume_pattern |
291 | 28 | from checkbox_support.parsers.tests.test_pactl import PactlDataMixIn | 29 | from checkbox_support.parsers.tests.test_pactl import PactlDataMixIn |
292 | 29 | 30 | ||
293 | 30 | 31 | ||
294 | @@ -171,10 +172,11 @@ class SetProfileTest(unittest.TestCase, PactlDataMixIn): | |||
295 | 171 | ('0', 'Hdmi2')) | 172 | ('0', 'Hdmi2')) |
296 | 172 | 173 | ||
297 | 173 | class RegexTest(unittest.TestCase): | 174 | class RegexTest(unittest.TestCase): |
299 | 174 | 175 | ||
300 | 175 | def test_volume_regex_trusty(self): | 176 | def test_volume_regex_trusty(self): |
301 | 176 | """Testing pactl 4.0 output""" | 177 | """Testing pactl 4.0 output""" |
302 | 177 | pactl_volume = " Volume: 0: 47% 1: 47%" | 178 | pactl_volume = " Volume: 0: 47% 1: 47%" |
303 | 179 | volume_regex = re.compile(volume_pattern % "0", re.DOTALL) | ||
304 | 178 | volume = int(volume_regex.search(pactl_volume).group(1).strip()) | 180 | volume = int(volume_regex.search(pactl_volume).group(1).strip()) |
305 | 179 | self.assertEqual(volume, 47) | 181 | self.assertEqual(volume, 47) |
306 | 180 | 182 | ||
307 | @@ -182,5 +184,6 @@ class RegexTest(unittest.TestCase): | |||
308 | 182 | """Testing pactl 8.0 output""" | 184 | """Testing pactl 8.0 output""" |
309 | 183 | # See lp:1595380 for more info | 185 | # See lp:1595380 for more info |
310 | 184 | pactl_volume = " Volume: front-left: 65536 / 100% / 0.00 dB, front-right: 65536 / 100% / 0.00 dB" | 186 | pactl_volume = " Volume: front-left: 65536 / 100% / 0.00 dB, front-right: 65536 / 100% / 0.00 dB" |
311 | 187 | volume_regex = re.compile(volume_pattern % "front-left", re.DOTALL) | ||
312 | 185 | volume = int(volume_regex.search(pactl_volume).group(1).strip()) | 188 | volume = int(volume_regex.search(pactl_volume).group(1).strip()) |
313 | 186 | self.assertEqual(volume, 100) | 189 | self.assertEqual(volume, 100) |
I found one problem with the regex string, see below.
Nitpicking: There are at least three ways that string interpolation is used in this code (overall audio_settings.py, not just your patch):
+
.format
""%()
And I think it's pretty yucky. I'm not asking anyone to do a small revolution and fix all that, but I would prefer not to cultivate bad habits.