Skip to content
This repository was archived by the owner on Jul 23, 2024. It is now read-only.

Commit db124a2

Browse files
authored
Refactor shell theming module (#806)
## Description This PR refactors a few operations to make the code handle edge cases efficiently with marginal performance improvements. ## Type of change - [ ] Bugfix (Change which fixes an issue) - [ ] New feature (Change which adds new functionality) - [x] Enhancement (Change which slightly improves existing code) - [ ] Breaking change (This change will introduce incompatibility with existing functionality) ## Changelog <!-- This is optional, but highly appreciated. --> - Stores the comma separated string representation of valid versions for later use in raising exceptions. - Uses tuple for `async_data` in `ShellTheme` since its members are immutable. - Uses tuple decomposition to assign theme variant and preset from `async_data` later. - Replaces `Gio.File.make_directory_with_parents` with Python's builtin `os.makedirs` with `exist_ok` as True to implicitly create directories when nonexistent. - Instead of relying on `KeyError`s when accessing dictionary values, the `get` method is used to supply a default value. - When a key might exist in one dictionary, the `get` method (which may return `None`) is coupled with the nullish `or` operator to use the value that is not `None`. - Uses predefined `main_source` attribute as argument to the `_compile_sass` function. - Uses the walrus operator to scope a template match to the condition when it is not `None`. - Removes unnecessary implicit `.close()`s on file handles when using context managers. ## Testing - [x] I have tested my changes and verified that they work as expected <!-- Make sure you did this step before marking your PR as ready for merge. --> ### How to test the changes <!-- Optional, it can speed up review process if you provide the information on how to test your changes. --> Just run `./local.sh`
2 parents 7d2c082 + f234ac3 commit db124a2

File tree

1 file changed

+34
-82
lines changed

1 file changed

+34
-82
lines changed

gradience/backend/theming/shell.py

Lines changed: 34 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
class ShellTheme:
4141
# Supported GNOME Shell versions: 42, 43, 44
4242
shell_versions = [42, 43, 44]
43-
shell_versions_str = [str(version) for version in shell_versions]
43+
shell_versions_str = ", ".join(map(str, shell_versions))
4444
version_target = None
4545

4646
theme_variant = None
@@ -61,7 +61,7 @@ def __init__(self, shell_version=None):
6161
self.version_target = shell_version
6262
else:
6363
raise UnsupportedShellVersion(
64-
f"GNOME Shell version {shell_version} is not supported. (Supported versions: {', '.join(self.shell_versions_str)})")
64+
f"GNOME Shell version {shell_version} is not supported. (Supported versions: {self.shell_versions_str})")
6565

6666
self.THEME_GSETTINGS_SCHEMA_ID = "org.gnome.shell.extensions.user-theme"
6767
self.THEME_GSETTINGS_SCHEMA_PATH = "/org/gnome/shell/extensions/user-theme/"
@@ -72,31 +72,24 @@ def __init__(self, shell_version=None):
7272
"gnome-shell", "extensions", self.THEME_EXT_NAME, "schemas")
7373

7474
try:
75-
if os.path.exists(self.THEME_GSETTINGS_DIR):
76-
if not is_sandboxed():
77-
self.settings = GSettingsSetting(self.THEME_GSETTINGS_SCHEMA_ID,
78-
schema_dir=self.THEME_GSETTINGS_DIR)
79-
else:
80-
self.settings = FlatpakGSettings(self.THEME_GSETTINGS_SCHEMA_ID,
81-
schema_dir=self.THEME_GSETTINGS_DIR)
82-
else:
83-
if not is_sandboxed():
84-
self.settings = GSettingsSetting(self.THEME_GSETTINGS_SCHEMA_ID)
85-
else:
86-
self.settings = FlatpakGSettings(self.THEME_GSETTINGS_SCHEMA_ID)
75+
settings_retriever = FlatpakGSettings if is_sandboxed() else GSettingsSetting
76+
schema_dir = self.THEME_GSETTINGS_DIR if os.path.exists(self.THEME_GSETTINGS_DIR) else None
77+
self.settings = settings_retriever(self.THEME_GSETTINGS_SCHEMA_ID, schema_dir=schema_dir)
8778
except (GSettingsMissingError, GLib.GError):
8879
raise
8980

81+
version_target_str = str(self.version_target)
9082
# Theme source/output paths
91-
self.templates_dir = os.path.join(datadir, "gradience", "shell", "templates", str(self.version_target))
92-
self.source_dir = os.path.join(GLib.get_home_dir(), ".cache", "gradience", "gradience-shell", str(self.version_target))
83+
self.templates_dir = os.path.join(datadir, "gradience", "shell", "templates", version_target_str)
84+
self.source_dir = os.path.join(GLib.get_home_dir(), ".cache", "gradience", "gradience-shell", version_target_str)
9385

9486
if os.path.exists(self.source_dir):
9587
shutil.rmtree(self.source_dir)
9688

9789
# Copy shell theme source directories to ~/.cache/gradience/gradience-shell
98-
shutil.copytree(os.path.join(datadir, "gradience", "shell",
99-
str(self.version_target)), self.source_dir, dirs_exist_ok=True
90+
shutil.copytree(
91+
os.path.join(datadir, "gradience", "shell", version_target_str),
92+
self.source_dir, dirs_exist_ok=True
10093
)
10194

10295
# TODO: Allow user to use different name than "gradience-shell" (also, with default name, we should append "-light" suffix when generated from light preset)
@@ -121,7 +114,7 @@ def apply_theme_async(self, caller:GObject.Object, callback:callable,
121114
theme_variant:str,
122115
preset: Preset):
123116
task = Gio.Task.new(caller, None, callback, self._cancellable)
124-
self.async_data = [theme_variant, preset]
117+
self.async_data = (theme_variant, preset)
125118

126119
task.set_return_on_cancel(True)
127120
task.run_in_thread(self._apply_theme_thread)
@@ -132,8 +125,7 @@ def _apply_theme_thread(self, task:Gio.Task, source_object:GObject.Object,
132125
if task.return_error_if_cancelled():
133126
return
134127

135-
theme_variant = self.async_data[0]
136-
preset = self.async_data[1]
128+
theme_variant, preset = self.async_data
137129

138130
output = self.apply_theme(source_object, theme_variant, preset)
139131
task.return_value(output)
@@ -163,15 +155,9 @@ def _create_theme(self, parent: callable, preset: Preset):
163155
self._insert_variables()
164156
self._recolor_assets()
165157

166-
if not os.path.exists(self.output_dir):
167-
try:
168-
dirs = Gio.File.new_for_path(self.output_dir)
169-
dirs.make_directory_with_parents(None)
170-
except GLib.GError as e:
171-
logging.error(f"Unable to create directories.", exc=e)
172-
raise
158+
os.makedirs(self.output_dir, exist_ok=True)
173159

174-
self._compile_sass(os.path.join(self.source_dir, "gnome-shell.scss"),
160+
self._compile_sass(self.main_source,
175161
os.path.join(self.output_dir, "gnome-shell.css"))
176162

177163
self._set_shell_theme()
@@ -184,47 +170,29 @@ def _insert_variables(self):
184170

185171
with open(self.palette_template, "r", encoding="utf-8") as template:
186172
for line in template:
187-
template_match = re.search(template_regex, line)
188-
if template_match != None:
173+
if template_match := template_regex.search(line):
189174
_key = template_match.__getitem__(1)
190-
prefix = _key.split("_")[0] + "_"
191-
key = _key.split("_")[1]
192-
inserted = line.replace("{{" + _key + "}}", self.preset_palette[prefix][key])
193-
palette_content += inserted
194-
else:
195-
palette_content += line
196-
template.close()
175+
prefix, key = _key.split("_")[:2]
176+
line = line.replace("{{" + _key + "}}", self.preset_palette[prefix + '_'][key])
177+
palette_content += line
197178

198179
with open(self.palette_source, "w", encoding="utf-8") as sheet:
199180
sheet.write(palette_content)
200-
sheet.close()
201181

202182
colors_content = ""
203183

204184
with open(self.colors_template, "r", encoding="utf-8") as template:
205185
for line in template:
206-
template_match = re.search(template_regex, line)
207-
if template_match != None:
186+
if template_match := template_regex.search(line):
208187
key = template_match.__getitem__(1)
209-
shell_colors = get_shell_colors(self.preset_variables)
210-
try:
211-
if self.shell_colors:
212-
inserted = line.replace(
213-
"{{" + key + "}}", self.shell_colors[key])
214-
else:
215-
inserted = line.replace(
216-
"{{" + key + "}}", shell_colors[key])
217-
except KeyError:
218-
inserted = line.replace(
219-
"{{" + key + "}}", self.preset_variables[key])
220-
colors_content += inserted
221-
else:
222-
colors_content += line
223-
template.close()
188+
shell_colors = self.shell_colors or get_shell_colors(self.preset_variables)
189+
value = shell_colors.get(key) or self.preset_variables.get(key)
190+
if value:
191+
line = line.replace("{{" + key + "}}", value)
192+
colors_content += line
224193

225194
with open(self.colors_source, "w", encoding="utf-8") as sheet:
226195
sheet.write(colors_content)
227-
sheet.close()
228196

229197
main_content = ""
230198

@@ -233,24 +201,17 @@ def _insert_variables(self):
233201

234202
for line in template:
235203
if key in line:
236-
inserted = line.replace(
237-
"{{" + key + "}}", f"'{self.theme_variant}'")
238-
main_content += inserted
204+
value = f"'{self.theme_variant}'"
205+
line = line.replace("{{" + key + "}}", value)
239206
elif "custom_css" in line:
240207
key = "custom_css"
241-
try:
242-
inserted = line.replace(
243-
"{{" + key + "}}", self.custom_css['shell'])
244-
except KeyError: # No custom CSS
245-
inserted = line.replace("{{" + key + "}}", "")
246-
main_content += inserted
247-
else:
248-
main_content += line
249-
template.close()
208+
# Empty string when there is no custom CSS
209+
value = self.custom_css.get('shell', "")
210+
line = line.replace("{{" + key + "}}", value)
211+
main_content += line
250212

251213
with open(self.main_source, "w", encoding="utf-8") as sheet:
252214
sheet.write(main_content)
253-
sheet.close()
254215

255216
def _compile_sass(self, sass_path, output_path):
256217
try:
@@ -261,7 +222,6 @@ def _compile_sass(self, sass_path, output_path):
261222
else:
262223
with open(output_path, "w", encoding="utf-8") as css_file:
263224
css_file.write(compiled)
264-
css_file.close()
265225

266226
# TODO: Add recoloring for other assets
267227
def _recolor_assets(self):
@@ -278,19 +238,11 @@ def _recolor_assets(self):
278238
switch_on_svg = svg_data.read()
279239
switch_on_svg = switch_on_svg.replace(
280240
"fill:#3584e4", f"fill:{accent_bg}")
281-
svg_data.close()
282241

283242
with open(switch_on_source, "w", encoding="utf-8") as svg_data:
284243
svg_data.write(switch_on_svg)
285-
svg_data.close()
286244

287-
if not os.path.exists(self.assets_output):
288-
try:
289-
dirs = Gio.File.new_for_path(self.assets_output)
290-
dirs.make_directory_with_parents(None)
291-
except GLib.GError as e:
292-
logging.error(f"Unable to create directories.", exc=e)
293-
raise
245+
os.makedirs(self.assets_output, exist_ok=True)
294246

295247
shutil.copy(
296248
switch_on_source,
@@ -315,7 +267,7 @@ def _detect_shell_version(self):
315267

316268
if shell_ver.startswith("3"):
317269
raise UnsupportedShellVersion(
318-
f"GNOME Shell version {shell_ver} is not supported. (Supported versions: {', '.join(self.shell_versions_str)})")
270+
f"GNOME Shell version {shell_ver} is not supported. (Supported versions: {self.shell_versions_str})")
319271

320272
if shell_ver.startswith("4"):
321273
shell_ver = int(shell_ver[:2])
@@ -324,7 +276,7 @@ def _detect_shell_version(self):
324276
self.version_target = shell_ver
325277
else:
326278
raise UnsupportedShellVersion(
327-
f"GNOME Shell version {shell_ver} is not supported. (Supported versions: {', '.join(self.shell_versions_str)})")
279+
f"GNOME Shell version {shell_ver} is not supported. (Supported versions: {self.shell_versions_str})")
328280

329281
def reset_theme_async(self, caller:GObject.Object, callback:callable):
330282
task = Gio.Task.new(caller, None, callback, self._cancellable)

0 commit comments

Comments
 (0)