From 6b624a72cd13b1960d183c97a9f83f3549e9d8f0 Mon Sep 17 00:00:00 2001 From: Luna Date: Sun, 7 Jun 2026 01:02:33 -0700 Subject: [PATCH] Narrow bare except blocks so real errors aren't swallowed (roadmap A4) Replaced all 46 bare 'except:' across the package with specific exception types, and logged the cases that indicate a real problem: - config load/save: FileNotFoundError is the silent first-run case; other OSError/ValueError/UnicodeDecodeError are logged. - ffprobe/avprobe: JSON parse failures are now logged (previously a media file that ffprobe couldn't read just silently failed to import); decode fallbacks -> UnicodeDecodeError; duration parse -> ValueError/TypeError/ KeyError; install check -> OSError/SubprocessError. - executor: pre_/post_function and progress-polling hooks now use hasattr checks, and a real exception inside a defined hook is logged instead of swallowed; decode fallbacks and numeric parses narrowed. - best-effort filesystem ops (makedirs/unlink) -> OSError. - all backend check_is_installed probes -> OSError/SubprocessError. - shutdown: also fixes a latent NameError ('failure' was only set in the except branch, so a successful logind PowerOff would crash the handler). No bare 'except:' remain. Full suite (51 tests) green; GUI starts clean. Co-Authored-By: Claude Opus 4.8 --- src/devedeng/avbase.py | 4 +-- src/devedeng/avconv.py | 4 +-- src/devedeng/avprobe.py | 12 +++++---- src/devedeng/brasero.py | 2 +- src/devedeng/choose_disc_type.py | 2 +- src/devedeng/configuration_data.py | 11 +++++--- src/devedeng/dvd_menu.py | 4 +-- src/devedeng/dvdauthor_converter.py | 4 +-- src/devedeng/executor.py | 40 ++++++++++++++--------------- src/devedeng/ffmpeg.py | 6 ++--- src/devedeng/ffprobe.py | 12 +++++---- src/devedeng/file_copy.py | 2 +- src/devedeng/genisoimage.py | 2 +- src/devedeng/k3b.py | 2 +- src/devedeng/mkisofs.py | 2 +- src/devedeng/mplayer.py | 2 +- src/devedeng/mpv.py | 2 +- src/devedeng/project.py | 8 +++--- src/devedeng/shutdown.py | 7 ++--- src/devedeng/vlc.py | 2 +- src/devedeng/xfburn.py | 2 +- 21 files changed, 70 insertions(+), 62 deletions(-) diff --git a/src/devedeng/avbase.py b/src/devedeng/avbase.py index d8530ae..7b472a8 100644 --- a/src/devedeng/avbase.py +++ b/src/devedeng/avbase.py @@ -30,7 +30,7 @@ class avbase(devedeng.executor.executor): (stdout, stderr) = handle.communicate() if 0 != handle.wait(): return False - except: + except (OSError, subprocess.SubprocessError): return False self.check_version_txt(stdout) @@ -54,7 +54,7 @@ class avbase(devedeng.executor.executor): else: major = int(line[15:pos1].strip()) minor = int(line[pos1 + 1:pos2].strip()) - except: + except (ValueError, IndexError): return False self.major_version = major self.minor_version = minor diff --git a/src/devedeng/avconv.py b/src/devedeng/avconv.py index af65ba8..1162a61 100644 --- a/src/devedeng/avconv.py +++ b/src/devedeng/avconv.py @@ -103,7 +103,7 @@ class avconv(devedeng.avbase.avbase): return True else: return False - except: + except (OSError, subprocess.SubprocessError): return False def __init__(self): @@ -648,7 +648,7 @@ class avconv(devedeng.avbase.avbase): for e in parts: try: v = float(e) - except: + except ValueError: continue t = t * 60.0 + v t /= self.final_length diff --git a/src/devedeng/avprobe.py b/src/devedeng/avprobe.py index a560e7d..1aa40d3 100644 --- a/src/devedeng/avprobe.py +++ b/src/devedeng/avprobe.py @@ -43,7 +43,7 @@ class avprobe(devedeng.avbase.avbase): return True else: return False - except: + except (OSError, subprocess.SubprocessError): return False def __init__(self): @@ -70,7 +70,7 @@ class avprobe(devedeng.avbase.avbase): try: stdout2 = stdout.decode("utf-8") - except: + except UnicodeDecodeError: stdout2 = stdout.decode("latin1") self.config.append_static_log("AVProbe JSON data: " + str(stdout2)) return self.process_json(stdout2, file_name) @@ -97,7 +97,9 @@ class avprobe(devedeng.avbase.avbase): "Getting data for {:s} with avprobe".format(file_name)) try: video_data = json.loads(stdout2) - except: + except ValueError as e: + self.config.append_static_log( + "avprobe returned unparseable JSON for %s: %s" % (file_name, e)) return True # There was an error reading the JSON data if not("streams" in video_data): @@ -108,7 +110,7 @@ class avprobe(devedeng.avbase.avbase): if (self.original_length == -1) and ("duration" in element): try: self.original_length = int(float(element["duration"])) - except: + except (ValueError, TypeError, KeyError): self.original_length = -1 if (element["codec_type"] == "video"): @@ -173,7 +175,7 @@ class avprobe(devedeng.avbase.avbase): try: stdout2 = stdout.decode("utf-8") + \ "\n" + stderr.decode("utf-8") - except: + except UnicodeDecodeError: stdout2 = stdout.decode("latin1") + \ "\n" + stderr.decode("latin1") self.config.append_static_log( diff --git a/src/devedeng/brasero.py b/src/devedeng/brasero.py index 054434c..1d781df 100644 --- a/src/devedeng/brasero.py +++ b/src/devedeng/brasero.py @@ -39,7 +39,7 @@ class brasero(devedeng.executor.executor): return True else: return False - except: + except (OSError, subprocess.SubprocessError): return False def __init__(self): diff --git a/src/devedeng/choose_disc_type.py b/src/devedeng/choose_disc_type.py index 297fe69..35d484d 100644 --- a/src/devedeng/choose_disc_type.py +++ b/src/devedeng/choose_disc_type.py @@ -103,7 +103,7 @@ class choose_disc_type(GObject.GObject): (stdout, stderr) = handle.communicate() retval = handle.wait() return True - except: + except (OSError, subprocess.SubprocessError): return False def set_type(self, disc_type): diff --git a/src/devedeng/configuration_data.py b/src/devedeng/configuration_data.py index 4ee9047..d7ab38c 100644 --- a/src/devedeng/configuration_data.py +++ b/src/devedeng/configuration_data.py @@ -210,8 +210,11 @@ class configuration(GObject.GObject): pass continue config_data.close() - except: - pass + except FileNotFoundError: + pass # no config file yet (first run) — defaults are used + except (OSError, ValueError, UnicodeDecodeError) as e: + self.append_static_log( + "Error reading config file %s: %s" % (config_path, e)) return False @@ -285,8 +288,8 @@ class configuration(GObject.GObject): config_path = os.path.join(os.environ.get("HOME"), ".devedeng") if os.path.exists(config_path): os.remove(config_path) - except: - pass + except OSError as e: + self.append_static_log("Error writing config file: %s" % e) def append_log(self, data, cr=True): diff --git a/src/devedeng/dvd_menu.py b/src/devedeng/dvd_menu.py index 1209b0b..21503da 100644 --- a/src/devedeng/dvd_menu.py +++ b/src/devedeng/dvd_menu.py @@ -201,7 +201,7 @@ class dvd_menu(devedeng.interface_manager.interface_manager): try: fontsize = float(font_elements[-1]) - except: + except (ValueError, IndexError): fontsize = 12 return fontname, fontstyle, fontslant, fontsize @@ -635,7 +635,7 @@ class dvd_menu(devedeng.interface_manager.interface_manager): menu_folder = os.path.join(base_path, "menu") try: os.makedirs(menu_folder) - except: + except OSError: pass n_page = 0 self.pages = 1 diff --git a/src/devedeng/dvdauthor_converter.py b/src/devedeng/dvdauthor_converter.py index 11dfdb8..fac93fc 100644 --- a/src/devedeng/dvdauthor_converter.py +++ b/src/devedeng/dvdauthor_converter.py @@ -33,7 +33,7 @@ class dvdauthor_converter(devedeng.executor.executor): movie_path = os.path.join(path, "dvd_tree") try: os.makedirs(movie_path) - except: + except OSError: pass xml_file = self.create_dvdauthor_xml(path, file_movies, menu_entries, start_with_menu, play_all_opt, menuWide, segment_lengths) @@ -73,7 +73,7 @@ class dvdauthor_converter(devedeng.executor.executor): datapath = os.path.join(movie_folder, "dvd_tree") try: os.makedirs(xmlpath) - except: + except OSError: pass if (len(file_movies) == 1) and (menu_entries is None): diff --git a/src/devedeng/executor.py b/src/devedeng/executor.py index 6c8af71..d88ccc9 100644 --- a/src/devedeng/executor.py +++ b/src/devedeng/executor.py @@ -120,20 +120,20 @@ class executor(GObject.GObject): self.progress_bar[0].set_label(self.text) self.progress_bar[1].set_fraction(0.0) self.progress_bar[0].show_all() - # call, if it exists, the pre-function - try: - self.pre_function() - except: - pass + # call the pre-function if this process defines one + if hasattr(self, "pre_function"): + try: + self.pre_function() + except Exception as e: + self.config.append_static_log( + "pre_function failed for %s: %s" % (self.text, e)) self.launch_process(self.command_var) if self.use_pulse_mode != self.pulse_mode: self.set_pulse_mode(self.use_pulse_mode) # let subclasses start any timer-based progress polling (e.g. ffmpeg # reads its -progress file on a GLib timer). No-op by default. - try: + if hasattr(self, "start_progress_polling"): self.start_progress_polling() - except AttributeError: - pass def remove_ansi(self, line): @@ -189,11 +189,11 @@ class executor(GObject.GObject): self.config.append_log(self.launch_command) try: self.config.append_log(stdout_r.decode("utf-8")) - except: + except UnicodeDecodeError: self.config.append_log(stdout_r.decode("latin-1")) try: self.config.append_log(stderr_r.decode("utf-8")) - except: + except UnicodeDecodeError: self.config.append_log(stderr_r.decode("latin-1")) return (stdout_r, stderr_r) @@ -396,16 +396,16 @@ class executor(GObject.GObject): self.set_pulse_mode(False) # stop any subclass progress polling timer - try: + if hasattr(self, "stop_progress_polling"): self.stop_progress_polling() - except AttributeError: - pass - # call, if it exists, the post-function - try: - self.post_function(retval, self.killed) - except: - pass + # call the post-function if this process defines one + if hasattr(self, "post_function"): + try: + self.post_function(retval, self.killed) + except Exception as e: + self.config.append_static_log( + "post_function failed for %s: %s" % (self.text, e)) if self.killed: retval = 0 @@ -435,13 +435,13 @@ class executor(GObject.GObject): if (pos == -1): try: return float(data) - except: + except (ValueError, TypeError): return 0 else: try: data1 = float(data[:pos]) data2 = float(data[pos + 1:]) - except: + except (ValueError, TypeError): return 0 if (data2 == 0): return 0 diff --git a/src/devedeng/ffmpeg.py b/src/devedeng/ffmpeg.py index 4fb4453..e3eb0c1 100644 --- a/src/devedeng/ffmpeg.py +++ b/src/devedeng/ffmpeg.py @@ -106,7 +106,7 @@ class ffmpeg(devedeng.executor.executor): return True else: return False - except: + except (OSError, subprocess.SubprocessError): return False def __init__(self): @@ -124,7 +124,7 @@ class ffmpeg(devedeng.executor.executor): if line.startswith("ffmpeg version "): version_number = int(re.search(r"[0-9]+", line).group()) break - except: + except (OSError, subprocess.SubprocessError, ValueError, AttributeError): version_number = 7 pass print(f"Detected ffmpeg version number: {version_number}") @@ -829,7 +829,7 @@ class ffmpeg(devedeng.executor.executor): for e in parts: try: v = float(e) - except: + except ValueError: continue t = t * 60.0 + v t /= self.final_length diff --git a/src/devedeng/ffprobe.py b/src/devedeng/ffprobe.py index a213eb6..29efdb6 100644 --- a/src/devedeng/ffprobe.py +++ b/src/devedeng/ffprobe.py @@ -43,7 +43,7 @@ class ffprobe(devedeng.executor.executor): return True else: return False - except: + except (OSError, subprocess.SubprocessError): return False def __init__(self): @@ -69,7 +69,7 @@ class ffprobe(devedeng.executor.executor): (stdout, stderr) = self.launch_process(command_line, False) try: stdout2 = stdout.decode("utf-8") - except: + except UnicodeDecodeError: stdout2 = stdout.decode("latin1") self.config.append_static_log("FFProbe JSON data: " + str(stdout2)) return self.process_json(file_name, stdout2) @@ -97,7 +97,9 @@ class ffprobe(devedeng.executor.executor): "Getting data for {:s} with ffprobe".format(file_name)) try: video_data = json.loads(stdout2) - except: + except ValueError as e: + self.config.append_static_log( + "ffprobe returned unparseable JSON for %s: %s" % (file_name, e)) return True # There was an error reading the JSON data if not("streams" in video_data): @@ -108,7 +110,7 @@ class ffprobe(devedeng.executor.executor): if (self.original_length == -1) and ("duration" in element): try: self.original_length = int(float(element["duration"])) - except: + except (ValueError, TypeError, KeyError): self.original_length = -1 if (element["codec_type"] == "video"): @@ -176,7 +178,7 @@ class ffprobe(devedeng.executor.executor): try: stdout2 = stdout.decode("utf-8") + \ "\n" + stderr.decode("utf-8") - except: + except UnicodeDecodeError: stdout2 = stdout.decode("latin1") + \ "\n" + stderr.decode("latin1") self.config.append_static_log("Using ffprobe human readable format: " + str(stdout2)) diff --git a/src/devedeng/file_copy.py b/src/devedeng/file_copy.py index 85690d6..41317c8 100644 --- a/src/devedeng/file_copy.py +++ b/src/devedeng/file_copy.py @@ -47,7 +47,7 @@ class file_copy(devedeng.executor.executor): try: copied = float(parts[0]) - except: + except (ValueError, IndexError): return p = copied / self.file_size diff --git a/src/devedeng/genisoimage.py b/src/devedeng/genisoimage.py index a8b79cb..82a46b9 100644 --- a/src/devedeng/genisoimage.py +++ b/src/devedeng/genisoimage.py @@ -42,7 +42,7 @@ class genisoimage(devedeng.executor.executor): return True else: return False - except: + except (OSError, subprocess.SubprocessError): return False def __init__(self): diff --git a/src/devedeng/k3b.py b/src/devedeng/k3b.py index 10f39eb..43e1ce7 100644 --- a/src/devedeng/k3b.py +++ b/src/devedeng/k3b.py @@ -39,7 +39,7 @@ class k3b(devedeng.executor.executor): return True else: return False - except: + except (OSError, subprocess.SubprocessError): return False def __init__(self): diff --git a/src/devedeng/mkisofs.py b/src/devedeng/mkisofs.py index cd4dc38..aea566f 100644 --- a/src/devedeng/mkisofs.py +++ b/src/devedeng/mkisofs.py @@ -42,7 +42,7 @@ class mkisofs(devedeng.executor.executor): return True else: return False - except: + except (OSError, subprocess.SubprocessError): return False def __init__(self): diff --git a/src/devedeng/mplayer.py b/src/devedeng/mplayer.py index fa36292..1b37014 100644 --- a/src/devedeng/mplayer.py +++ b/src/devedeng/mplayer.py @@ -42,7 +42,7 @@ class mplayer(devedeng.executor.executor): return True else: return False - except: + except (OSError, subprocess.SubprocessError): return False def __init__(self): diff --git a/src/devedeng/mpv.py b/src/devedeng/mpv.py index 72917d5..3247954 100644 --- a/src/devedeng/mpv.py +++ b/src/devedeng/mpv.py @@ -41,7 +41,7 @@ class mpv(devedeng.executor.executor): return True else: return False - except: + except (OSError, subprocess.SubprocessError): return False def __init__(self): diff --git a/src/devedeng/project.py b/src/devedeng/project.py index 37689ab..5f91b4d 100644 --- a/src/devedeng/project.py +++ b/src/devedeng/project.py @@ -908,16 +908,16 @@ class devede_project: if self.config.disc_type == "dvd": try: os.unlink(os.path.join(data.path, data.name + ".iso")) - except: + except OSError: pass if (self.config.disc_type == "vcd") or (self.config.disc_type == "svcd") or (self.config.disc_type == "cvd"): try: os.unlink(os.path.join(data.path, data.name + ".bin")) - except: + except OSError: pass try: os.unlink(os.path.join(data.path, data.name + ".cue")) - except: + except OSError: pass else: return @@ -968,7 +968,7 @@ class devede_project: movie_folder = os.path.join(data.path, "movies") try: os.makedirs(movie_folder) - except: + except OSError: pass counter = 0 if self.disc_type == "divx": diff --git a/src/devedeng/shutdown.py b/src/devedeng/shutdown.py index 569f482..4940e84 100644 --- a/src/devedeng/shutdown.py +++ b/src/devedeng/shutdown.py @@ -22,11 +22,12 @@ class shutdown: def __init__(self): # First, try with logind + failure = False try: bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) bus.call_sync("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "PowerOff", GLib.Variant_boolean('(bb)', (False, False)), None, Gio.DBusCallFlags.NONE, -1, None) - except: + except Exception: failure = True if (failure): @@ -37,7 +38,7 @@ class shutdown: bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) bus.call_sync("org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager", "org.freedesktop.ConsoleKit.Manager", "Stop", None, None, Gio.DBusCallFlags.NONE, -1, None) - except: + except Exception: failure = True if (failure): @@ -48,5 +49,5 @@ class shutdown: bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) bus.call_sync("org.freedesktop.Hal", "/org/freedesktop/Hal/devices/computer", "org.freedesktop.Hal.Device.SystemPowerManagement", "Shutdown", None, None, Gio.DBusCallFlags.NONE, -1, None) - except: + except Exception: failure = True diff --git a/src/devedeng/vlc.py b/src/devedeng/vlc.py index 309ebbb..04fbecc 100644 --- a/src/devedeng/vlc.py +++ b/src/devedeng/vlc.py @@ -39,7 +39,7 @@ class vlc(devedeng.executor.executor): return True else: return False - except: + except (OSError, subprocess.SubprocessError): return False def __init__(self): diff --git a/src/devedeng/xfburn.py b/src/devedeng/xfburn.py index 2e44472..ac28faa 100644 --- a/src/devedeng/xfburn.py +++ b/src/devedeng/xfburn.py @@ -38,7 +38,7 @@ class xfburn(devedeng.executor.executor): return True else: return False - except: + except (OSError, subprocess.SubprocessError): return False def __init__(self):