From 524aa0e7dc2b27c93534d356ba19963b793f38d8 Mon Sep 17 00:00:00 2001 From: Alfredo Monclus Date: Fri, 24 May 2024 19:13:19 -0300 Subject: [PATCH] drop python 3.7 support (#1271) * drop python 3.7 support start using PEP 572 assignment expressions Update FAQ improve how unsupported versions are informed this should be clearer on why we refuse to continue * add more asign-expressions --- docs/FAQ.md | 2 +- ks_includes/config.py | 3 +- ks_includes/functions.py | 6 +-- ks_includes/widgets/heatergraph.py | 9 ++--- panels/input_shaper.py | 8 ++-- screen.py | 55 ++++++++++++-------------- scripts/KlipperScreen-install.sh | 7 ++-- scripts/KlipperScreen-requirements.txt | 5 --- 8 files changed, 41 insertions(+), 54 deletions(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index 57653f0a..4f3c3b8f 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -2,7 +2,7 @@ ## What is the minimum Python version required? -The minimum version is Python 3.7, this is checked during install. +The minimum version is Python 3.8, this is checked during install. ## OctoPrint? diff --git a/ks_includes/config.py b/ks_includes/config.py index eb93473c..0364464b 100644 --- a/ks_includes/config.py +++ b/ks_includes/config.py @@ -455,8 +455,7 @@ class KlipperScreenConfig: directories = [printer_data_config, xdg_config, klipperscreendir] for directory in directories: - path = self.check_path_exists(directory, self.configfile_name) - if path: + if path := self.check_path_exists(directory, self.configfile_name): return path # fallback diff --git a/ks_includes/functions.py b/ks_includes/functions.py index e3a8dba8..b0075c22 100644 --- a/ks_includes/functions.py +++ b/ks_includes/functions.py @@ -40,8 +40,7 @@ try: onoff_p = ctypes.create_string_buffer(1) state_p = ctypes.create_string_buffer(2) if libXext.DPMSInfo(display, state_p, onoff_p): - onoff = struct.unpack('B', onoff_p.raw)[0] - if onoff: + if onoff := struct.unpack('B', onoff_p.raw)[0]: state = struct.unpack('H', state_p.raw)[0] libXext.XCloseDisplay(display) return state @@ -73,8 +72,7 @@ def get_wireless_interfaces(): return None interfaces = [] for line in result: - match = re.search('^(\\S+)\\s+.*$', line) - if match: + if match := re.search('^(\\S+)\\s+.*$', line): interfaces.append(match[1]) return interfaces diff --git a/ks_includes/widgets/heatergraph.py b/ks_includes/widgets/heatergraph.py index 2c16ce4e..0f660cf5 100644 --- a/ks_includes/widgets/heatergraph.py +++ b/ks_includes/widgets/heatergraph.py @@ -64,11 +64,9 @@ class HeaterGraph(Gtk.DrawingArea): mnum = [0] for device in self.store: if self.store[device]['show']: - temp = self.printer.get_temp_store(device, "temperatures", data_points) - if temp: + if temp := self.printer.get_temp_store(device, "temperatures", data_points): mnum.append(max(temp)) - target = self.printer.get_temp_store(device, "targets", data_points) - if target: + if target := self.printer.get_temp_store(device, "targets", data_points): mnum.append(max(target)) return max(mnum) @@ -105,8 +103,7 @@ class HeaterGraph(Gtk.DrawingArea): if not self.store[name]['show']: continue for dev_type in self.store[name]: - d = self.printer.get_temp_store(name, dev_type, data_points) - if d: + if d := self.printer.get_temp_store(name, dev_type, data_points): self.graph_data( ctx, d, gsize, d_height_scale, d_width, self.store[name][dev_type]["rgb"], self.store[name][dev_type]["dashed"], self.store[name][dev_type]["fill"] diff --git a/panels/input_shaper.py b/panels/input_shaper.py index 917236c5..e152d5ad 100644 --- a/panels/input_shaper.py +++ b/panels/input_shaper.py @@ -162,9 +162,11 @@ class Panel(ScreenPanel): self.save_config() # shaper_type_y:ei shaper_freq_y:48.400 damping_ratio_y:0.100000 if 'shaper_type_' in data: - results = re.search(r'shaper_type_(?P[xy]):(?P.*?) shaper_freq_.:(' - r'?P[0-9.]+)', data) - if results: + if results := re.search( + r'shaper_type_(?P[xy]):(?P.*?) shaper_freq_.:(' + r'?P[0-9.]+)', + data, + ): results = results.groupdict() self.freq_xy_adj['shaper_freq_' + results['axis']].set_value(float(results['shaper_freq'])) self.freq_xy_combo['shaper_type_' + results['axis']].set_active(SHAPERS.index(results['shaper_type'])) diff --git a/screen.py b/screen.py index 3b1acbad..37e81064 100755 --- a/screen.py +++ b/screen.py @@ -137,10 +137,21 @@ class KlipperScreen(Gtk.Window): self.gtk = KlippyGtk(self) self.init_style() self.set_icon_from_file(os.path.join(klipperscreendir, "styles", "icon.svg")) - self.base_panel = BasePanel(self, title="Base Panel") self.add(self.base_panel.main_grid) self.show_all() + min_ver = (3, 8) + if sys.version_info < min_ver: + self.show_error_modal( + "Error", + _("The system doesn't meet the minimum requirement") + "\n" + + _("Minimum:") + f" Python {min_ver[0]}.{min_ver[1]}" + "\n" + + _("System:") + f" Python {sys.version_info.major}.{sys.version_info.minor}" + ) + return + if self._config.errors: + self.show_error_modal("Invalid config file", self._config.get_errors()) + return if self.show_cursor: self.get_window().set_cursor( Gdk.Cursor.new_for_display(Gdk.Display.get_default(), Gdk.CursorType.ARROW)) @@ -150,18 +161,9 @@ class KlipperScreen(Gtk.Window): Gdk.Cursor.new_for_display(Gdk.Display.get_default(), Gdk.CursorType.BLANK_CURSOR)) os.system("xsetroot -cursor ks_includes/emptyCursor.xbm ks_includes/emptyCursor.xbm") self.base_panel.activate() - if self._config.errors: - self.show_error_modal("Invalid config file", self._config.get_errors()) - # Prevent this dialog from being destroyed - self.dialogs = [] self.set_screenblanking_timeout(self._config.get_main_config().get('screen_blanking')) self.log_notification("KlipperScreen Started", 1) self.initial_connection() - if sys.version_info == (3, 7): - GLib.timeout_add_seconds(2, self.show_popup_message, - _("Warning") + f" Python 3.7\n" - + _("Ended official support in June 2023") + "\n" - + _("KlipperScreen will drop support in June 2024"), 2) def state_execute(self, state, callback): self.close_screensaver() @@ -396,15 +398,16 @@ class KlipperScreen(Gtk.Window): self.popup_message = self.popup_timeout = None return False - def show_error_modal(self, err, e=""): - logging.error(f"Showing error modal: {err} {e}") + def show_error_modal(self, title_msg, description="", help_msg=None): + logging.error(f"Showing error modal: {title_msg} {description}") title = Gtk.Label(wrap=True, wrap_mode=Pango.WrapMode.CHAR, hexpand=True, halign=Gtk.Align.START) - title.set_markup(f"{err}\n") + title.set_markup(f"{title_msg}\n") version = Gtk.Label(label=f"{functions.get_software_version()}", halign=Gtk.Align.END) - help_msg = _("Provide KlipperScreen.log when asking for help.\n") - message = Gtk.Label(label=f"{help_msg}\n\n{e}", wrap=True, wrap_mode=Pango.WrapMode.CHAR) + if not help_msg: + help_msg = _("Provide KlipperScreen.log when asking for help.\n") + message = Gtk.Label(label=f"{description}\n\n{help_msg}", wrap=True, wrap_mode=Pango.WrapMode.CHAR) scroll = self.gtk.ScrolledWindow() scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) scroll.add(message) @@ -416,13 +419,13 @@ class KlipperScreen(Gtk.Window): grid.attach(scroll, 0, 2, 2, 1) buttons = [ - {"name": _("Go Back"), "response": Gtk.ResponseType.CANCEL} + {"name": _("Close"), "response": Gtk.ResponseType.CLOSE} ] self.gtk.Dialog(_("Error"), buttons, grid, self.error_modal_response) - def error_modal_response(self, dialog, response_id): - self.gtk.remove_dialog(dialog) - self.restart_ks() + @staticmethod + def error_modal_response(dialog, response_id): + sys.exit(1) def restart_ks(self, *args): logging.debug(f"Restarting {sys.executable} {' '.join(sys.argv)}") @@ -883,8 +886,7 @@ class KlipperScreen(Gtk.Window): if self.connected_printer is None or not devices: return found_devices devices = [str(i.strip()) for i in devices.split(',')] - power_devices = self.printer.get_power_devices() - if power_devices: + if power_devices := self.printer.get_power_devices(): found_devices = [dev for dev in devices if dev in power_devices] logging.info(f"Found {found_devices}", ) return found_devices @@ -1039,8 +1041,7 @@ class KlipperScreen(Gtk.Window): def init_tempstore(self): if len(self.printer.get_temp_devices()) == 0: return - tempstore = self.apiclient.send_request("server/temperature_store") - if tempstore: + if tempstore := self.apiclient.send_request("server/temperature_store"): self.printer.init_temp_store(tempstore) if hasattr(self.panels[self._cur_panels[-1]], "update_graph_visibility"): self.panels[self._cur_panels[-1]].update_graph_visibility() @@ -1051,8 +1052,7 @@ class KlipperScreen(Gtk.Window): if set(self.printer.tempstore) != set(self.printer.get_temp_devices()): GLib.timeout_add_seconds(5, self.init_tempstore) return - server_config = self.apiclient.send_request("server/config") - if server_config: + if server_config := self.apiclient.send_request("server/config"): try: self.printer.tempstore_size = server_config["config"]["data_store"]["temperature_store_size"] logging.info(f"Temperature store size: {self.printer.tempstore_size}") @@ -1138,11 +1138,6 @@ class KlipperScreen(Gtk.Window): def main(): - minimum = (3, 7) - if not sys.version_info >= minimum: - logging.error(f"python {sys.version_info.major}.{sys.version_info.minor} " - f"does not meet the minimum requirement {minimum[0]}.{minimum[1]}") - sys.exit(1) parser = argparse.ArgumentParser(description="KlipperScreen - A GUI for Klipper") homedir = os.path.expanduser("~") diff --git a/scripts/KlipperScreen-install.sh b/scripts/KlipperScreen-install.sh index 3b375cf8..aae1f650 100755 --- a/scripts/KlipperScreen-install.sh +++ b/scripts/KlipperScreen-install.sh @@ -103,10 +103,11 @@ install_packages() check_requirements() { - echo_text "Checking Python version" + VERSION="3,8" + echo_text "Checking Python version > "$VERSION python3 --version - if ! python3 -c 'import sys; exit(1) if sys.version_info <= (3,7) else exit(0)'; then - echo_text 'Not supported' + if ! python3 -c 'import sys; exit(1) if sys.version_info <= ('$VERSION') else exit(0)'; then + echo_error 'Not supported' exit 1 fi } diff --git a/scripts/KlipperScreen-requirements.txt b/scripts/KlipperScreen-requirements.txt index 3f40f592..e19cd0d4 100644 --- a/scripts/KlipperScreen-requirements.txt +++ b/scripts/KlipperScreen-requirements.txt @@ -10,11 +10,6 @@ python-mpv==1.0.6;python_version>="3.10" backports.zoneinfo;python_version<"3.9" -# Python 3.7 (For Buster until June 2024) -PyGObject==3.44.1; python_version == '3.7' -pycairo==1.23.0; python_version == '3.7' -websocket-client==1.6.1; python_version == '3.7' - PyGObject==3.48.1;python_version>="3.8" pycairo==1.26.0;python_version>="3.8" websocket-client==1.8.0;python_version>="3.8"