From 0a8d45ddc4bd246da4a4bfebff1ab73207120792 Mon Sep 17 00:00:00 2001 From: HelioGuilherme66 Date: Wed, 9 Oct 2024 00:39:06 +0100 Subject: [PATCH 1/2] Fix unit tests for upgrade --- README.adoc | 2 +- src/robotide/application/updatenotifier.py | 11 ++--- src/robotide/version.py | 2 +- utest/application/test_updatenotifier.py | 51 ++++++++++++---------- 4 files changed, 37 insertions(+), 29 deletions(-) diff --git a/README.adoc b/README.adoc index 66dc91f27..9d0494f66 100644 --- a/README.adoc +++ b/README.adoc @@ -40,7 +40,7 @@ Likewise, the current version of wxPython, is 4.2.2, but RIDE is known to work w `pip install -U robotframework-ride` -(3.8 <= python <= 3.12) Install current development version (**2.1dev87**) with: +(3.8 <= python <= 3.12) Install current development version (**2.1dev88**) with: `pip install -U https://github.com/robotframework/RIDE/archive/master.zip` diff --git a/src/robotide/application/updatenotifier.py b/src/robotide/application/updatenotifier.py index b91f5cfa3..b0518afad 100644 --- a/src/robotide/application/updatenotifier.py +++ b/src/robotide/application/updatenotifier.py @@ -32,7 +32,7 @@ from ..utils.versioncomparator import cmp_versions, parse_version from ..widgets import ButtonWithHandler, HtmlWindow, RIDEDialog from ..postinstall import MessageDialog -from ..publish import PUBLISHER, RideRunnerStarted, RideRunnerStopped +from ..publish import PUBLISHER, RideRunnerStopped _ = wx.GetTranslation # To keep linter/code analyser happy builtins.__dict__['_'] = wx.GetTranslation @@ -164,7 +164,6 @@ def do_upgrade(command, notebook): config = RunnerCommand('Upgrade RIDE', command, 'Uses pip to upgrade RIDE.') PUBLISHER.subscribe(start_upgraded, RideRunnerStopped) result = ui.Runner(config, notebook).run() - # result = 0 time.sleep(10) if result == -1: _askyesno(_("Failed to Upgrade"), f"{SPC}{_('An error occurred when installing new version')}", @@ -173,15 +172,17 @@ def do_upgrade(command, notebook): def start_upgraded(message): + __ = message command = sys.executable + " -m robotide.__init__ --noupdatecheck" wx.CallLater(500, subprocess.Popen, command.split(' '), start_new_session=True) - pid = psutil.Process.pid + pid = psutil.Process result = _askyesno(_("Completed Upgrade"), f"\n{SPC}{_('You should close this RIDE (Process ID = ')}{pid}){SPC}", wx.GetActiveWindow()) PUBLISHER.unsubscribe(start_upgraded, RideRunnerStopped) if result: time.sleep(10) - wx.App.Get().OnExit() + wx.CallAfter(wx.App.Get().Close) + # wx.App.Get().OnExit() class LocalHtmlWindow(HtmlWindow): @@ -258,5 +259,5 @@ def on_checkbox_change(self, event): def on_upgrade_now(self, event): __ = event _add_content_to_clipboard(self._command) - self.Hide() + self.Close() do_upgrade(self._command, self._notebook) diff --git a/src/robotide/version.py b/src/robotide/version.py index 287eca77c..2e6dba7e3 100644 --- a/src/robotide/version.py +++ b/src/robotide/version.py @@ -15,4 +15,4 @@ # # Automatically generated by `tasks.py`. -VERSION = 'v2.1dev87' +VERSION = 'v2.1dev88' diff --git a/utest/application/test_updatenotifier.py b/utest/application/test_updatenotifier.py index 04b5ee46c..a0dae2f5b 100644 --- a/utest/application/test_updatenotifier.py +++ b/utest/application/test_updatenotifier.py @@ -108,7 +108,7 @@ class UpdateNotifierTestCase(unittest.TestCase): def setUp(self): self._callback_called = False - self._version = None + self._newest_version = None self._url = None self.app = MyApp() settings = self.app.settings @@ -141,9 +141,9 @@ def _callback(self, version, url, settings, notebook): __ = notebook self.assertFalse(self._callback_called) self._callback_called = True - self.assertNotEqual(None, version) - self._version = version - self.assertNotEqual(None, url) + self.assertIsNotNone(version) + self._newest_version = version + self.assertIsNotNone(url) self._url = url self.assertEqual(dict, type(settings)) @@ -151,8 +151,15 @@ def _callback(self, version, url, settings, notebook): def _update_notifier_controller(settings, notebook, current, new, url='some url'): ctrl = UpdateNotifierController(settings, notebook) ctrl.VERSION = current - ctrl._get_newest_version = lambda: new - ctrl._get_download_url = lambda v: url if v == new else None + def _new(): + return new + ctrl._get_newest_version = _new + def _url(): + return url + ctrl._get_download_url = _url + def _null(): + return None + ctrl._get_rf_pypi_data = _null return ctrl @staticmethod @@ -165,11 +172,11 @@ def test_normal_update(self): settings = self.internal_settings() ctrl = self._update_notifier_controller(settings, self.notebook, '0', '1', 'http://xyz.abc.efg.di') ctrl.notify_update_if_needed(self._callback) - self.assertEqual('1', self._version) - self.assertEqual('http://xyz.abc.efg.di', self._url) self.assertTrue(self._callback_called) + self.assertEqual('1', self._newest_version) + self.assertEqual('http://xyz.abc.efg.di', self._url) self.assertTrue(settings[CHECKFORUPDATES]) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 1) + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 1) # Uncomment next lines if you want to see the app # wx.CallLater(5000, self.app.ExitMainLoop) # self.app.MainLoop() @@ -179,9 +186,9 @@ def test_update_when_trunk_version(self): ctrl = self._update_notifier_controller(settings, self.notebook, '2.0', '2.0.1') ctrl.notify_update_if_needed(self._callback) self.assertTrue(self._callback_called) - self.assertEqual('2.0.1', self._version) + self.assertEqual('2.0.1', self._newest_version) self.assertTrue(settings[CHECKFORUPDATES]) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 1) + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 1) def test_last_update_done_less_than_a_week_ago(self): original_time = time.time() - 60 * 60 * 24 * 3 @@ -205,14 +212,14 @@ def test_no_update_found(self): settings = self.internal_settings() ctrl = self._update_notifier_controller(settings, self.notebook, '0.55', '0.55') ctrl.notify_update_if_needed(self._callback) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 1) + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 1) self.assertFalse(self._callback_called) def test_no_update_found_dev(self): settings = self.internal_settings() ctrl = self._update_notifier_controller(settings, self.notebook, '0.56', '0.56') ctrl.notify_update_if_needed(self._callback, ignore_check_condition=False, show_no_update=False) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 1) + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 1) self.assertFalse(self._callback_called) def test_no_update_found_dev_notify(self): @@ -225,7 +232,7 @@ def test_first_run_sets_settings_correctly_and_checks_for_updates(self): settings = self.internal_settings(check_for_updates=None, last_update_check=None) ctrl = self._update_notifier_controller(settings, self.notebook,'1.0.2', '1.0.2') ctrl.notify_update_if_needed(self._callback) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 1) + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 1) self.assertTrue(settings[CHECKFORUPDATES]) self.assertFalse(self._callback_called) @@ -233,7 +240,7 @@ def test_first_run_sets_settings_correctly_and_finds_an_update(self): settings = self.internal_settings(check_for_updates=None, last_update_check=None) ctrl = self._update_notifier_controller(settings, self.notebook, '1.2', '2.0') ctrl.notify_update_if_needed(self._callback) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 1) + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 1) self.assertTrue(settings[CHECKFORUPDATES]) self.assertTrue(self._callback_called) @@ -246,7 +253,7 @@ def throw_timeout_error(): ctrl._get_newest_version = throw_timeout_error ctrl.notify_update_if_needed(self._callback) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 10) # The dialog timeout in 10 seconds + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 10) # The dialog timeout in 10 seconds self.assertFalse(self._callback_called) def test_download_url_checking_timeouts(self): @@ -261,14 +268,14 @@ def throw_timeout_error(*args): ctrl._get_download_url = throw_timeout_error ctrl.notify_update_if_needed(self._callback) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 1) + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 1) self.assertFalse(self._callback_called) def test_server_returns_no_versions(self): settings = self.internal_settings() ctrl = self._update_notifier_controller(settings, self.notebook, '1.2.2', None) ctrl.notify_update_if_needed(self._callback) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 1) + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 1) self.assertTrue(settings[CHECKFORUPDATES]) self.assertFalse(self._callback_called) @@ -276,7 +283,7 @@ def test_server_returns_older_version(self): settings = self.internal_settings() ctrl = self._update_notifier_controller(settings, self.notebook, '0.44', '0.43.1') ctrl.notify_update_if_needed(self._callback) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 1) + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 1) self.assertTrue(settings[CHECKFORUPDATES]) self.assertFalse(self._callback_called) @@ -284,7 +291,7 @@ def test_forced_check_released(self): settings = self.internal_settings() ctrl = self._update_notifier_controller(settings, self.notebook, '0.43.0', '0.43.1') ctrl.notify_update_if_needed(self._callback, ignore_check_condition=True) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 19) # The dialog timeout in 20 seconds + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 19) # The dialog timeout in 20 seconds self.assertTrue(settings[CHECKFORUPDATES]) self.assertTrue(self._callback_called) @@ -292,7 +299,7 @@ def test_forced_check_development(self): settings = self.internal_settings() ctrl = self._update_notifier_controller(settings, self.notebook, '0.44dev12', '0.44.dev14') ctrl.notify_update_if_needed(self._callback, ignore_check_condition=True) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 20) # The dialog timeout in 20 seconds + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 20) # The dialog timeout in 20 seconds self.assertTrue(settings[CHECKFORUPDATES]) self.assertTrue(self._callback_called) @@ -300,7 +307,7 @@ def test_forced_check_development_ok(self): settings = self.internal_settings() ctrl = self._update_notifier_controller(settings, self.notebook, '0.44dev12', '0.44.dev12') ctrl.notify_update_if_needed(self._callback, ignore_check_condition=False) - self.assertTrue(settings[LASTUPDATECHECK] > time.time() - 20) # The dialog timeout in 20 seconds + self.assertGreater(settings[LASTUPDATECHECK], time.time() - 20) # The dialog timeout in 20 seconds self.assertTrue(settings[CHECKFORUPDATES]) self.assertFalse(self._callback_called) From 95868f2d36cd809c9356b0bd884d797c80bae992 Mon Sep 17 00:00:00 2001 From: HelioGuilherme66 Date: Wed, 9 Oct 2024 14:58:51 +0100 Subject: [PATCH 2/2] Improve restart dialogs --- src/robotide/application/application.py | 27 ++++++++++++---------- src/robotide/application/restartutil.py | 24 +++++++++---------- src/robotide/application/updatenotifier.py | 10 ++++---- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/robotide/application/application.py b/src/robotide/application/application.py index 2d51a8812..53d7b5fc8 100644 --- a/src/robotide/application/application.py +++ b/src/robotide/application/application.py @@ -15,6 +15,8 @@ import builtins import os +from csv import excel + import wx from contextlib import contextmanager from pathlib import Path @@ -332,24 +334,25 @@ def change_locale(self, message): self._locale.AddCatalog('RIDE') if len(message.keys) > 1: # Avoid initial setting from multiprocessing import shared_memory - from .restartutil import restart_dialog + from .restartutil import do_restart new_locale = self._locale.GetName() # print(f"DEBUG: application.py RIDE change_locale from {initial_locale} to {new_locale}") if initial_locale != new_locale: - if restart_dialog(): # DEBUG: See the in implementation why we don't restart - # print("DEBUG: application.py RIDE change_locale Restart accepted.") - # Shared memory to store language definition + #if restart_dialog(): # DEBUG: See the in implementation why we don't restart + # print("DEBUG: application.py RIDE change_locale Restart accepted.") + # Shared memory to store language definition + try: + sharemem = shared_memory.ShareableList(['en'], name="language") + except FileExistsError: # Other instance created file + sharemem = shared_memory.ShareableList(name="language") + result = do_restart() + if result: try: - sharemem = shared_memory.ShareableList(['en'], name="language") - except FileExistsError: # Other instance created file - sharemem = shared_memory.ShareableList(name="language") - finally: sharemem.shm.close() sharemem.shm.unlink() - # wx.CallAfter(self.ExitMainLoop) - # wx.CallLater(1000, self.Destroy) - wx.CallLater(1000, self.ExitMainLoop) - # self.DeletePendingEvents() + except FileNotFoundError: + pass + @staticmethod def update_excludes(message): diff --git a/src/robotide/application/restartutil.py b/src/robotide/application/restartutil.py index 7fa4ac495..f8078f723 100644 --- a/src/robotide/application/restartutil.py +++ b/src/robotide/application/restartutil.py @@ -27,8 +27,7 @@ def restart_dialog(): - if not _askyesno( - _("Re-open RIDE for Language Change"), + if not _askyesno(_("Re-open RIDE for Language Change"), f"{SPC}{_('Language change will only be correct after re-opening RIDE.')}" f"{SPC}\n{SPC}{_('Do you want to CLOSE RIDE now?')}\n{SPC}" # f"{_('After restarting RIDE you will see another dialog informing to close this RIDE instance.')}" @@ -41,16 +40,15 @@ def restart_dialog(): def do_restart(): my_pid = psutil.Process() - command = sys.executable + " -m robotide.__init__ --noupdatecheck" # DEBUG: The starting of new RIDE instance with subsequent closing of this instance, # makes problems in editing the current file, and even opening new file. Because of - # this, the restarting is disabled, until someone finds a good way to clean-up memory. - # wx.CallLater(100, subprocess.Popen, command.split(' '), start_new_session=True) - # Wait 10 seconds before trying to kill this process - """ Not working well: - wx.CallLater(10000, psutil.Process.kill, my_pid.pid) - """ - wx.CallLater(5000, _askyesno, _("Completed Language Change"), - f"\n{SPC}{_('You should close this RIDE (Process ID = ')}{my_pid.pid}){SPC}", - wx.GetActiveWindow()) - + # this, the restarting was disabled, until someone finds a good way to clean-up memory. + command = sys.executable + " -m robotide.__init__ --noupdatecheck" + wx.CallLater(500, subprocess.Popen, command.split(' '), start_new_session=True) + result = _askyesno(_("Completed Language Change"), + f"\n{SPC}{_('You should close this RIDE (Process ID = ')}{my_pid.pid}){SPC}" + f"\n{SPC}{_('Do you want to CLOSE RIDE now?')}\n{SPC}", + wx.GetActiveWindow()) + if result: + wx.CallLater(1000, wx.App.Get().GetTopWindow().Close) + return True diff --git a/src/robotide/application/updatenotifier.py b/src/robotide/application/updatenotifier.py index b0518afad..2cf3949ca 100644 --- a/src/robotide/application/updatenotifier.py +++ b/src/robotide/application/updatenotifier.py @@ -175,14 +175,14 @@ def start_upgraded(message): __ = message command = sys.executable + " -m robotide.__init__ --noupdatecheck" wx.CallLater(500, subprocess.Popen, command.split(' '), start_new_session=True) - pid = psutil.Process - result = _askyesno(_("Completed Upgrade"), f"\n{SPC}{_('You should close this RIDE (Process ID = ')}{pid}){SPC}", + p = psutil.Process() + result = _askyesno(_("Completed Upgrade"), f"\n{SPC}{_('You should close this RIDE (Process ID = ')}{p.pid}){SPC}" + f"\n{SPC}{_('Do you want to CLOSE RIDE now?')}\n{SPC}", wx.GetActiveWindow()) PUBLISHER.unsubscribe(start_upgraded, RideRunnerStopped) if result: - time.sleep(10) - wx.CallAfter(wx.App.Get().Close) - # wx.App.Get().OnExit() + wx.CallAfter(wx.App.Get().GetTopWindow().Close) + # wx.CallAfter(p.terminate) class LocalHtmlWindow(HtmlWindow):