From f18bbdf48c1ecf9a1aa2e6e2068a28d5be0155a7 Mon Sep 17 00:00:00 2001 From: Markus Rosenstihl Date: Sun, 18 Oct 2026 16:24:59 +0200 Subject: [PATCH] replace gtk2/PyGTK and Python 2 idioms in DamarisGUI.py - raise "RuntimeError" -> raise RuntimeError(...) - gobject.timeout_add/idle_add/PRIORITY_* -> GLib equivalents (PyGIDeprecationWarning) - remove no-op gobject.type_register(GtkSource.View) - gtk.HBox -> gtk.Box(orientation=HORIZONTAL) (deprecated since 3.2) - menu.popup(6-arg) -> menu.popup_at_pointer (deprecated since 3.22) - Thread.getName() -> Thread.name (deprecated since 3.10) - rename gtksourceview2 alias to gtksourceview - rename bare iter locals/params to treeiter to avoid shadowing the builtin Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe --- src/damaris/gui/DamarisGUI.py | 130 +++++++++++++++++----------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/src/damaris/gui/DamarisGUI.py b/src/damaris/gui/DamarisGUI.py index 8cb2125..2b4cc15 100644 --- a/src/damaris/gui/DamarisGUI.py +++ b/src/damaris/gui/DamarisGUI.py @@ -24,6 +24,7 @@ from gi.repository import GObject as gobject import sqlite3 import uuid +from gi.repository import GLib as glib from gi.repository import Gtk as gtk gtk_version_missmatch = gtk.check_version( 3, 0, 0 ) @@ -32,8 +33,7 @@ if gtk_version_missmatch: from gi.repository import Gdk as gdk -from gi.repository import GtkSource as gtksourceview2 -gobject.type_register(gtksourceview2.View) +from gi.repository import GtkSource as gtksourceview from gi.repository import Pango as pango @@ -208,7 +208,7 @@ class DamarisGUI: if exp_script and res_script: self.start_immediately = start_immediately else: - raise "RuntimeError" + raise RuntimeError("start_immediately requires both experiment and result script") else: self.start_immediately = False self.statusbar_init( ) @@ -740,7 +740,7 @@ class DamarisGUI: if actual_config[ "data_pool_name" ] != "": self.dump_states( init=True, logtext=self.log.snapshot_since_last_dump( ) ) - gobject.timeout_add( 200, self.observe_running_experiment ) + glib.timeout_add( 200, self.observe_running_experiment ) def observe_running_experiment( self ): """ @@ -875,7 +875,7 @@ class DamarisGUI: self.toolbar_pause_button.set_sensitive( False ) self.toolbar_stop_button.set_sensitive( False ) if len( still_running ) != 0: - logger.warning("Subprocess(es) still running: %s", ', '.join( [s.getName( ) for s in still_running] )) + logger.warning("Subprocess(es) still running: %s", ', '.join( [s.name for s in still_running] )) return True else: if self.save_thread is not None: @@ -1323,7 +1323,7 @@ class LogWindow: """Manages the application log window. Provides a timestamped, scrollable text view for application messages. - Messages are dispatched via ``gobject.idle_add`` to keep the GTK main + Messages are dispatched via ``glib.idle_add`` to keep the GTK main loop responsive. Args: @@ -1353,7 +1353,7 @@ class LogWindow: def __call__( self, message ): timetag = time.time( ) - gobject.idle_add( self.add_message_callback, timetag, message, priority=gobject.PRIORITY_LOW ) + glib.idle_add( self.add_message_callback, timetag, message, priority=glib.PRIORITY_LOW ) def add_message_callback( self, timetag, message ): date_tag = "" @@ -1418,9 +1418,9 @@ class ScriptWidgets: experiment script file. res_script_filename (str or None): Path to the currently loaded result script file. - experiment_script_textview (:class:`gtksourceview2.View`): Text view + experiment_script_textview (:class:`gtksourceview.View`): Text view for the experiment script. - data_handling_textview (:class:`gtksourceview2.View`): Text view for + data_handling_textview (:class:`gtksourceview.View`): Text view for the result script. Public Methods: @@ -1441,7 +1441,7 @@ class ScriptWidgets: def __init__( self, xml_gui, outer_space ): """Initialize text widgets with syntax highlighting and completion. - Sets up two :class:`gtksourceview2.View` instances with Python + Sets up two :class:`gtksourceview.View` instances with Python syntax highlighting, keyword auto-completion, line numbers, and smart indentation. Connects text buffer signals to toolbar and status bar update handlers. @@ -1468,10 +1468,10 @@ class ScriptWidgets: self.data_handling_textview = self.xml_gui.get_object( "data_handling_textview" ) # create and set syntax-highlighting text-buffers as textview backends - self.experiment_script_textbuffer = gtksourceview2.Buffer() - self.data_handling_textbuffer = gtksourceview2.Buffer() + self.experiment_script_textbuffer = gtksourceview.Buffer() + self.data_handling_textbuffer = gtksourceview.Buffer() - lm = gtksourceview2.LanguageManager() + lm = gtksourceview.LanguageManager() langpython = lm.get_language("python") self.experiment_script_textbuffer.set_language(langpython) @@ -1505,7 +1505,7 @@ set_pfg set_dac set_phase set_pts_local get_length set_title get_title add_linep add_errorplotdata get_number_of_channels get_style set_style get_xlabel set_xlabel get_ylabel set_ylabel""" - self.keywordsbuffer = gtksourceview2.Buffer() + self.keywordsbuffer = gtksourceview.Buffer() self.keywordsbuffer.set_text(keywords) compexp = self.experiment_script_textview.get_completion() @@ -1514,15 +1514,15 @@ get_ylabel set_ylabel""" compexp.set_property("show-headers", True) compres.set_property("show-headers", True) - self.compwgen = gtksourceview2.CompletionWords.new("Keywords", None) + self.compwgen = gtksourceview.CompletionWords.new("Keywords", None) self.compwgen.register(self.keywordsbuffer) self.compwgen.set_property("minimum-word-size", 2) - self.compwexp = gtksourceview2.CompletionWords.new("Words", None) + self.compwexp = gtksourceview.CompletionWords.new("Words", None) self.compwexp.register(self.experiment_script_textbuffer) self.compwexp.set_property("minimum-word-size", 2) - self.compwres = gtksourceview2.CompletionWords.new("Words", None) + self.compwres = gtksourceview.CompletionWords.new("Words", None) self.compwres.register(self.data_handling_textbuffer) self.compwres.set_property("minimum-word-size", 2) @@ -1754,7 +1754,7 @@ get_ylabel set_ylabel""" def textviews_modified( self, widget = None, event=None ): # mix into toolbar affairs - if type(widget) is gtksourceview2.View: + if type(widget) is gtksourceview.View: return self.textviews_moved( widget ) else: return False @@ -2395,7 +2395,7 @@ class ConfigTab: self.config_data_pool_write_interval_entry.connect("key-press-event", self.config_keypress) # ADC bit depth setting - self.config_adc_bit_depth_hbox = gtk.HBox(homogeneous=False, spacing=6) + self.config_adc_bit_depth_hbox = gtk.Box(orientation=gtk.Orientation.HORIZONTAL, spacing=6) self.config_adc_bit_depth_label = gtk.Label(label="ADC bit depth:") self.config_adc_bit_depth_spinbutton = gtk.SpinButton.new_with_range(8, 32, 1) self.config_adc_bit_depth_spinbutton.set_value(ADC_Result.default_bit_depth) @@ -2410,7 +2410,7 @@ class ConfigTab: self.config_adc_bit_depth_hbox.show_all() # Temperature monitoring settings - single line layout - self.config_temp_hbox = gtk.HBox(homogeneous=False, spacing=6) + self.config_temp_hbox = gtk.Box(orientation=gtk.Orientation.HORIZONTAL, spacing=6) # Controller type selector self.config_temp_controller_type_label = gtk.Label(label="Controller:") @@ -2421,7 +2421,7 @@ class ConfigTab: self.config_temp_controller_type_combobox.set_tooltip_text("Select temperature controller type") self.config_temp_controller_type_combobox.connect("changed", self.on_temp_controller_type_changed) - self.config_temp_controller_type_hbox = gtk.HBox(homogeneous=False, spacing=0) + self.config_temp_controller_type_hbox = gtk.Box(orientation=gtk.Orientation.HORIZONTAL, spacing=0) self.config_temp_controller_type_hbox.pack_start(self.config_temp_controller_type_label, False, False, 0) self.config_temp_controller_type_hbox.pack_start(self.config_temp_controller_type_combobox, False, False, 0) self.config_temp_hbox.pack_start(self.config_temp_controller_type_hbox, False, False, 0) @@ -2440,7 +2440,7 @@ class ConfigTab: self.config_temp_device_button.set_tooltip_text("Browse for temperature controller device") self.config_temp_device_button.connect("clicked", self.on_temp_device_browse_clicked) - self.config_temp_device_hbox = gtk.HBox(homogeneous=False, spacing=0) + self.config_temp_device_hbox = gtk.Box(orientation=gtk.Orientation.HORIZONTAL, spacing=0) self.config_temp_device_hbox.pack_start(self.config_temp_device_entry, True, True, 0) self.config_temp_device_hbox.pack_start(self.config_temp_device_button, False, False, 0) self.config_temp_hbox.pack_start(self.config_temp_device_hbox, True, True, 0) @@ -2452,7 +2452,7 @@ class ConfigTab: self.config_temp_interval_spinbutton.set_tooltip_text("Time between temperature readings in seconds") self.config_temp_interval_spinbutton.connect("key-press-event", self.config_keypress) - self.config_temp_interval_hbox = gtk.HBox(homogeneous=False, spacing=6) + self.config_temp_interval_hbox = gtk.Box(orientation=gtk.Orientation.HORIZONTAL, spacing=6) self.config_temp_interval_hbox.pack_start(self.config_temp_interval_label, False, False, 0) self.config_temp_interval_hbox.pack_start(self.config_temp_interval_spinbutton, False, False, 0) self.config_temp_hbox.pack_start(self.config_temp_interval_hbox, False, False, 0) @@ -2466,7 +2466,7 @@ class ConfigTab: self.config_temp_baudrate_combobox.append_text("115200") self.config_temp_baudrate_combobox.set_active(0) self.config_temp_baudrate_combobox.set_tooltip_text("Serial baud rate for temperature controller") - self.config_temp_baudrate_hbox = gtk.HBox(homogeneous=False, spacing=6) + self.config_temp_baudrate_hbox = gtk.Box(orientation=gtk.Orientation.HORIZONTAL, spacing=6) self.config_temp_baudrate_hbox.pack_start(self.config_temp_baudrate_combobox, False, False, 0) self.config_temp_hbox.pack_start(self.config_temp_baudrate_hbox, False, False, 0) # Note: baud rate is shown for eurotherm, hidden for simulated @@ -2675,14 +2675,14 @@ pygobject version %(pygobject)s if "data_pool_complib" in config: # find combo-box entry and make it active... model = self.config_data_pool_complib.get_model( ) - iter = model.get_iter_first( ) - while iter is not None: - if model.get( iter, 0 )[ 0 ] == config[ "data_pool_complib" ]: - self.config_data_pool_complib.set_active_iter( iter ) + treeiter = model.get_iter_first( ) + while treeiter is not None: + if model.get( treeiter, 0 )[ 0 ] == config[ "data_pool_complib" ]: + self.config_data_pool_complib.set_active_iter( treeiter ) break - iter = model.iter_next( iter ) + treeiter = model.iter_next( treeiter ) # if this compression method is not supported, warn and do nothing - if iter is None: + if treeiter is None: logger.warning("Compression method %s is not supported", config[ "data_pool_complib" ]) def on_adc_bit_depth_changed(self, widget): @@ -2759,8 +2759,8 @@ pygobject version %(pygobject)s if model is None: return for i in range(model.iter_n_children(None)): - iter = model.iter_nth_child(None, i) - if iter and model.get(iter, 0)[0] == text: + treeiter = model.iter_nth_child(None, i) + if treeiter and model.get(treeiter, 0)[0] == text: combobox.set_active(i) return @@ -3113,13 +3113,13 @@ class MonitorWidgets: if none_iter is not None: self.display_source_combobox.set_active_iter( none_iter ) - def source_list_find_one( self, model, iter, what ): + def source_list_find_one( self, model, treeiter, what ): """find node in subcategory""" - while iter is not None: - if str( model.get( iter, 0 )[ 0 ] ) == what: - return iter - iter = model.iter_next( iter ) - return iter + while treeiter is not None: + if str( model.get( treeiter, 0 )[ 0 ] ) == what: + return treeiter + treeiter = model.iter_next( treeiter ) + return treeiter def source_list_find( self, namelist ): """ @@ -3146,35 +3146,35 @@ class MonitorWidgets: del namelist[:i] # Continue search from here retval = found_iter - iter = self.display_source_treestore.iter_children( retval ) - while iter is not None and len( namelist ) > 0: + treeiter = self.display_source_treestore.iter_children( retval ) + while treeiter is not None and len( namelist ) > 0: name = namelist[ 0 ] - iter = self.source_list_find_one( self.display_source_treestore, iter, name ) - if iter is not None: - retval = iter + treeiter = self.source_list_find_one( self.display_source_treestore, treeiter, name ) + if treeiter is not None: + retval = treeiter namelist.pop( 0 ) # Update cache partial_path += "/" + name self.source_list_cache[partial_path] = retval - iter = self.display_source_treestore.iter_children( retval ) + treeiter = self.display_source_treestore.iter_children( retval ) return retval else: del self.source_list_cache[partial_path] model = self.display_source_treestore retval = None - #iter = model.get_iter_root( ) - iter = model.get_iter_first( ) + #treeiter = model.get_iter_root( ) + treeiter = model.get_iter_first( ) current_path = [] - while iter is not None and len( namelist ) > 0: + while treeiter is not None and len( namelist ) > 0: name = namelist[ 0 ] - iter = self.source_list_find_one( model, iter, name ) - if iter is not None: - retval = iter + treeiter = self.source_list_find_one( model, treeiter, name ) + if treeiter is not None: + retval = treeiter namelist.pop( 0 ) current_path.append(name) self.source_list_cache["/".join(current_path)] = retval - iter = model.iter_children( retval ) + treeiter = model.iter_children( retval ) return retval def source_list_add( self, source_name, parent=None ): @@ -3201,17 +3201,17 @@ class MonitorWidgets: def source_list_remove( self, source_name ): namelist = source_name.split( "/" ) pwd = namelist[ : ] - iter = self.source_list_find( namelist ) - if iter is None or len( namelist ) > 0: + treeiter = self.source_list_find( namelist ) + if treeiter is None or len( namelist ) > 0: logger.warning("source_list_remove: Not found") return model = self.display_source_treestore - if model.iter_has_child( iter ): + if model.iter_has_child( treeiter ): logger.warning("source_list_remove: Request to delete a tree") return while True: - parent = model.iter_parent( iter ) - model.remove( iter ) + parent = model.iter_parent( treeiter ) + model.remove( treeiter ) pwd.pop( ) # We now test, if we want to remove parent too if parent is None: @@ -3222,7 +3222,7 @@ class MonitorWidgets: if "/".join( pwd ) in self.data_pool: # The parent has data connected to it break - iter = parent + treeiter = parent def source_list_current( self ): ai = self.display_source_combobox.get_active_iter( ) @@ -3304,7 +3304,7 @@ class MonitorWidgets: self.update_counter_lock.acquire( ) self.update_counter += 1 self.update_counter_lock.release( ) - gobject.idle_add( self.datapool_idle_listener, event, priority=gobject.PRIORITY_DEFAULT_IDLE ) + glib.idle_add(self.datapool_idle_listener, event, priority=glib.PRIORITY_DEFAULT_IDLE ) else: if event.what == DataPool.Event.updated_value and \ ( @@ -3313,13 +3313,13 @@ class MonitorWidgets: self.update_counter_lock.acquire() self.update_counter += 1 self.update_counter_lock.release() - gobject.idle_add( self.update_display_idle_event, self.displayed_data[ 0 ][ : ], - priority=gobject.PRIORITY_DEFAULT_IDLE ) + glib.idle_add(self.update_display_idle_event, self.displayed_data[ 0 ][ : ], + priority=glib.PRIORITY_DEFAULT_IDLE ) else: self.update_counter_lock.acquire( ) self.update_counter += 1 self.update_counter_lock.release( ) - gobject.idle_add( self.datapool_idle_listener, event, priority=gobject.PRIORITY_DEFAULT_IDLE ) + glib.idle_add(self.datapool_idle_listener, event, priority=glib.PRIORITY_DEFAULT_IDLE ) if event.what in [ DataPool.Event.updated_value, DataPool.Event.new_key ]: #print "Update hdf5 file ..." @@ -3346,8 +3346,8 @@ class MonitorWidgets: self.update_counter_lock.acquire( ) self.update_counter += 1 self.update_counter_lock.release( ) - gobject.idle_add( self.update_display_idle_event, self.displayed_data[ 0 ][ : ], - priority=gobject.PRIORITY_DEFAULT_IDLE ) + glib.idle_add(self.update_display_idle_event, self.displayed_data[ 0 ][ : ], + priority=glib.PRIORITY_DEFAULT_IDLE ) ################### consume idle events @@ -3457,7 +3457,7 @@ class MonitorWidgets: self.update_counter += 1 self.update_counter_lock.release( ) event = DataPool.Event( DataPool.Event.updated_value, new_data_name ) - gobject.idle_add( self.datapool_idle_listener, event, priority=gobject.PRIORITY_DEFAULT_IDLE ) + glib.idle_add(self.datapool_idle_listener, event, priority=glib.PRIORITY_DEFAULT_IDLE ) def display_autoscaling_toggled( self, widget, data=None ): self.matplot_axes.set_autoscale_on( self.display_autoscaling_checkbutton.get_active( ) ) @@ -3600,7 +3600,7 @@ class MonitorWidgets: menu.append(item_copy_svg) menu.show_all() - menu.popup(None, None, None, None, event.button, event.time) + menu.popup_at_pointer(event) def copy_canvas_as_png(self, widget): """Copy canvas to clipboard as PNG"""