synodic-client 0.0.1.dev49__tar.gz → 0.0.1.dev51__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/PKG-INFO +1 -1
  2. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/pyproject.toml +1 -1
  3. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/tool_update_controller.py +0 -2
  4. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/update_controller.py +9 -4
  5. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/client.py +4 -3
  6. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/updater.py +22 -23
  7. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/test_update_controller.py +3 -3
  8. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/test_client_updater.py +9 -1
  9. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/test_updater.py +104 -10
  10. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/LICENSE.md +0 -0
  11. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/README.md +0 -0
  12. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/__init__.py +0 -0
  13. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/__main__.py +0 -0
  14. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/__init__.py +0 -0
  15. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/bootstrap.py +0 -0
  16. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/data.py +0 -0
  17. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/icon.py +0 -0
  18. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/init.py +0 -0
  19. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/instance.py +0 -0
  20. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/qt.py +0 -0
  21. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/schema.py +0 -0
  22. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/__init__.py +0 -0
  23. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/action_card.py +0 -0
  24. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/card.py +0 -0
  25. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/install.py +0 -0
  26. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/install_workers.py +0 -0
  27. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/log_panel.py +0 -0
  28. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/plugin_row.py +0 -0
  29. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/projects.py +0 -0
  30. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/schema.py +0 -0
  31. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/screen.py +0 -0
  32. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/settings.py +0 -0
  33. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/sidebar.py +0 -0
  34. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/spinner.py +0 -0
  35. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/tray.py +0 -0
  36. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/screen/update_banner.py +0 -0
  37. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/theme.py +0 -0
  38. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/uri.py +0 -0
  39. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/application/workers.py +0 -0
  40. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/cli.py +0 -0
  41. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/config.py +0 -0
  42. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/logging.py +0 -0
  43. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/protocol.py +0 -0
  44. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/py.typed +0 -0
  45. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/resolution.py +0 -0
  46. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/schema.py +0 -0
  47. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/synodic_client/startup.py +0 -0
  48. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/__init__.py +0 -0
  49. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/conftest.py +0 -0
  50. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/__init__.py +0 -0
  51. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/__init__.py +0 -0
  52. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/conftest.py +0 -0
  53. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/test_action_card.py +0 -0
  54. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/test_gather_packages.py +0 -0
  55. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/test_install_preview.py +0 -0
  56. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/test_log_panel.py +0 -0
  57. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/test_logging.py +0 -0
  58. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/test_preview_model.py +0 -0
  59. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/test_settings.py +0 -0
  60. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/test_sidebar.py +0 -0
  61. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/test_tray_window_show.py +0 -0
  62. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/test_update_banner.py +0 -0
  63. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/qt/test_update_feedback.py +0 -0
  64. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/test_cli.py +0 -0
  65. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/test_client_version.py +0 -0
  66. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/test_config.py +0 -0
  67. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/test_examples.py +0 -0
  68. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/test_init.py +0 -0
  69. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/test_install.py +0 -0
  70. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/test_resolution.py +0 -0
  71. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/test_uri.py +0 -0
  72. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/test_workers.py +0 -0
  73. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/windows/__init__.py +0 -0
  74. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/windows/conftest.py +0 -0
  75. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/windows/test_protocol.py +0 -0
  76. {synodic_client-0.0.1.dev49 → synodic_client-0.0.1.dev51}/tests/unit/windows/test_startup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: synodic_client
3
- Version: 0.0.1.dev49
3
+ Version: 0.0.1.dev51
4
4
  Author-Email: Synodic Software <contact@synodic.software>
5
5
  License: LGPL-3.0-or-later
6
6
  Project-URL: homepage, https://github.com/synodic/synodic-client
@@ -15,7 +15,7 @@ dependencies = [
15
15
  "velopack>=0.0.1444.dev49733",
16
16
  "typer>=0.24.1",
17
17
  ]
18
- version = "0.0.1.dev49"
18
+ version = "0.0.1.dev51"
19
19
 
20
20
  [project.license]
21
21
  text = "LGPL-3.0-or-later"
@@ -389,5 +389,3 @@ class ToolUpdateOrchestrator:
389
389
  tools_view.set_package_removing(plugin_name, package_name, False)
390
390
  tools_view._updates_checked = False
391
391
  tools_view.refresh()
392
-
393
- self._window.show()
@@ -284,7 +284,7 @@ class UpdateController:
284
284
  f'v{version} installing\u2026',
285
285
  UPDATE_STATUS_AVAILABLE_STYLE,
286
286
  )
287
- self._apply_update()
287
+ self._apply_update(silent=True)
288
288
  return
289
289
 
290
290
  # Manual mode — show ready banner and let user choose when to restart
@@ -303,13 +303,18 @@ class UpdateController:
303
303
  # Apply
304
304
  # ------------------------------------------------------------------
305
305
 
306
- def _apply_update(self) -> None:
307
- """Apply the downloaded update and restart."""
306
+ def _apply_update(self, *, silent: bool = False) -> None:
307
+ """Apply the downloaded update and restart.
308
+
309
+ Args:
310
+ silent: When ``True``, suppress the Velopack splash window
311
+ by using ``wait_exit_then_apply_updates``.
312
+ """
308
313
  if self._client.updater is None:
309
314
  return
310
315
 
311
316
  try:
312
- self._client.apply_update_on_exit(restart=True)
317
+ self._client.apply_update_on_exit(restart=True, silent=silent)
313
318
  logger.info('Update scheduled — restarting application')
314
319
  self._app.quit()
315
320
  except Exception as e:
@@ -116,14 +116,15 @@ class Client:
116
116
 
117
117
  return self._updater.download_update(progress_callback)
118
118
 
119
- def apply_update_on_exit(self, restart: bool = True) -> None:
119
+ def apply_update_on_exit(self, restart: bool = True, *, silent: bool = False) -> None:
120
120
  """Schedule the update to apply when the application exits.
121
121
 
122
122
  Args:
123
- restart: Whether to restart after applying
123
+ restart: Whether to restart after applying.
124
+ silent: When ``True``, suppress the Velopack splash window.
124
125
  """
125
126
  if self._updater is None:
126
127
  logger.warning('Updater not initialized')
127
128
  return
128
129
 
129
- self._updater.apply_update_on_exit(restart=restart)
130
+ self._updater.apply_update_on_exit(restart=restart, silent=silent)
@@ -252,16 +252,24 @@ class Updater:
252
252
  self._update_info.error = str(e)
253
253
  return False
254
254
 
255
- def apply_update_on_exit(self, restart: bool = True, restart_args: list[str] | None = None) -> None:
256
- """Apply the downloaded update, optionally restarting the application.
255
+ def apply_update_on_exit(
256
+ self,
257
+ restart: bool = True,
258
+ silent: bool = False,
259
+ restart_args: list[str] | None = None,
260
+ ) -> None:
261
+ """Stage the downloaded update to apply when the process exits.
257
262
 
258
- When *restart* is ``True`` the Velopack runtime applies the update
259
- **and** relaunches the new version (the call does not return).
260
- When ``False`` the update is staged and applied after the process
261
- exits without relaunching.
263
+ Uses ``wait_exit_then_apply_updates`` which returns immediately.
264
+ The Velopack Update.exe runs after the current process exits,
265
+ applies the update, and optionally relaunches the application.
266
+
267
+ The caller is responsible for shutting down the process (e.g.
268
+ ``QApplication.quit()``) after this method returns.
262
269
 
263
270
  Args:
264
271
  restart: Whether to restart the application after applying.
272
+ silent: When ``True``, suppress the Velopack splash window.
265
273
  restart_args: Optional arguments to pass to the restarted application.
266
274
  """
267
275
  if not self.is_installed:
@@ -278,23 +286,14 @@ class Updater:
278
286
  if manager is None:
279
287
  raise RuntimeError('Velopack manager not available')
280
288
 
281
- logger.info('Applying update (restart=%s)', restart)
282
-
283
- if restart:
284
- self._state = UpdateState.APPLYING
285
- if restart_args:
286
- manager.apply_updates_and_restart_with_args(
287
- self._update_info._velopack_info,
288
- restart_args,
289
- )
290
- else:
291
- manager.apply_updates_and_restart(self._update_info._velopack_info)
292
- # apply_updates_and_restart terminates the process;
293
- # fall through only as a safety net.
294
- sys.exit(0)
295
- else:
296
- manager.apply_updates_and_exit(self._update_info._velopack_info)
297
- self._state = UpdateState.APPLIED
289
+ logger.info('Applying update (restart=%s, silent=%s)', restart, silent)
290
+ self._state = UpdateState.APPLYING
291
+ manager.wait_exit_then_apply_updates(
292
+ self._update_info._velopack_info,
293
+ silent=silent,
294
+ restart=restart,
295
+ restart_args=restart_args or [],
296
+ )
298
297
 
299
298
  except Exception as e:
300
299
  logger.exception('Failed to apply update')
@@ -151,13 +151,13 @@ class TestDownloadFinished:
151
151
 
152
152
  @staticmethod
153
153
  def test_auto_apply_calls_apply_update() -> None:
154
- """When auto_apply=True, a successful download should call _apply_update."""
154
+ """When auto_apply=True, a successful download should call _apply_update(silent=True)."""
155
155
  ctrl, app, client, banner, settings = _make_controller(auto_apply=True)
156
156
 
157
157
  with patch.object(ctrl, '_apply_update') as mock_apply:
158
158
  ctrl._on_download_finished(True, '2.0.0')
159
159
 
160
- mock_apply.assert_called_once()
160
+ mock_apply.assert_called_once_with(silent=True)
161
161
 
162
162
  @staticmethod
163
163
  def test_auto_apply_does_not_show_ready_banner() -> None:
@@ -213,7 +213,7 @@ class TestApplyUpdate:
213
213
  ctrl, app, client, banner, settings = _make_controller()
214
214
  ctrl._apply_update()
215
215
 
216
- client.apply_update_on_exit.assert_called_once_with(restart=True)
216
+ client.apply_update_on_exit.assert_called_once_with(restart=True, silent=False)
217
217
  app.quit.assert_called_once()
218
218
 
219
219
  @staticmethod
@@ -105,4 +105,12 @@ class TestClientUpdater:
105
105
  with patch.object(client_with_updater._updater, 'apply_update_on_exit') as mock_apply:
106
106
  client_with_updater.apply_update_on_exit(restart=False)
107
107
 
108
- mock_apply.assert_called_once_with(restart=False)
108
+ mock_apply.assert_called_once_with(restart=False, silent=False)
109
+
110
+ @staticmethod
111
+ def test_apply_update_on_exit_silent(client_with_updater: Client) -> None:
112
+ """Verify apply_update_on_exit forwards silent flag to updater."""
113
+ with patch.object(client_with_updater._updater, 'apply_update_on_exit') as mock_apply:
114
+ client_with_updater.apply_update_on_exit(restart=True, silent=True)
115
+
116
+ mock_apply.assert_called_once_with(restart=True, silent=True)
@@ -337,7 +337,7 @@ class TestUpdaterApplyUpdate:
337
337
 
338
338
  @staticmethod
339
339
  def test_apply_on_exit_with_restart(updater: Updater) -> None:
340
- """Verify apply_update_on_exit(restart=True) uses apply_updates_and_restart."""
340
+ """Verify apply_update_on_exit(restart=True) stages update via wait_exit_then_apply_updates."""
341
341
  mock_velopack_info = MagicMock(spec=velopack.UpdateInfo)
342
342
  updater._update_info = UpdateInfo(
343
343
  available=True,
@@ -352,16 +352,20 @@ class TestUpdaterApplyUpdate:
352
352
  with (
353
353
  patch.object(Updater, 'is_installed', new_callable=PropertyMock, return_value=True),
354
354
  patch.object(updater, '_get_velopack_manager', return_value=mock_manager),
355
- pytest.raises(SystemExit, match='0'),
356
355
  ):
357
356
  updater.apply_update_on_exit(restart=True)
358
357
 
359
358
  assert updater.state == UpdateState.APPLYING
360
- mock_manager.apply_updates_and_restart.assert_called_once_with(mock_velopack_info)
359
+ mock_manager.wait_exit_then_apply_updates.assert_called_once_with(
360
+ mock_velopack_info,
361
+ silent=False,
362
+ restart=True,
363
+ restart_args=[],
364
+ )
361
365
 
362
366
  @staticmethod
363
367
  def test_apply_on_exit_with_restart_args(updater: Updater) -> None:
364
- """Verify restart_args are forwarded to apply_updates_and_restart_with_args."""
368
+ """Verify restart_args are forwarded to wait_exit_then_apply_updates."""
365
369
  mock_velopack_info = MagicMock(spec=velopack.UpdateInfo)
366
370
  updater._update_info = UpdateInfo(
367
371
  available=True,
@@ -376,19 +380,20 @@ class TestUpdaterApplyUpdate:
376
380
  with (
377
381
  patch.object(Updater, 'is_installed', new_callable=PropertyMock, return_value=True),
378
382
  patch.object(updater, '_get_velopack_manager', return_value=mock_manager),
379
- pytest.raises(SystemExit, match='0'),
380
383
  ):
381
384
  updater.apply_update_on_exit(restart=True, restart_args=['--minimized'])
382
385
 
383
386
  assert updater.state == UpdateState.APPLYING
384
- mock_manager.apply_updates_and_restart_with_args.assert_called_once_with(
387
+ mock_manager.wait_exit_then_apply_updates.assert_called_once_with(
385
388
  mock_velopack_info,
386
- ['--minimized'],
389
+ silent=False,
390
+ restart=True,
391
+ restart_args=['--minimized'],
387
392
  )
388
393
 
389
394
  @staticmethod
390
395
  def test_apply_on_exit_no_restart(updater: Updater) -> None:
391
- """Verify apply_update_on_exit(restart=False) uses apply_updates_and_exit."""
396
+ """Verify apply_update_on_exit(restart=False) stages update without restart."""
392
397
  mock_velopack_info = MagicMock(spec=velopack.UpdateInfo)
393
398
  updater._update_info = UpdateInfo(
394
399
  available=True,
@@ -406,8 +411,97 @@ class TestUpdaterApplyUpdate:
406
411
  ):
407
412
  updater.apply_update_on_exit(restart=False)
408
413
 
409
- assert updater.state == UpdateState.APPLIED
410
- mock_manager.apply_updates_and_exit.assert_called_once_with(mock_velopack_info)
414
+ assert updater.state == UpdateState.APPLYING
415
+ mock_manager.wait_exit_then_apply_updates.assert_called_once_with(
416
+ mock_velopack_info,
417
+ silent=False,
418
+ restart=False,
419
+ restart_args=[],
420
+ )
421
+
422
+ @staticmethod
423
+ def test_apply_on_exit_silent_restart(updater: Updater) -> None:
424
+ """Verify silent=True suppresses the splash window."""
425
+ mock_velopack_info = MagicMock(spec=velopack.UpdateInfo)
426
+ updater._update_info = UpdateInfo(
427
+ available=True,
428
+ current_version=Version('1.0.0'),
429
+ latest_version=Version('2.0.0'),
430
+ _velopack_info=mock_velopack_info,
431
+ )
432
+ updater._state = UpdateState.DOWNLOADED
433
+
434
+ mock_manager = MagicMock(spec=velopack.UpdateManager)
435
+
436
+ with (
437
+ patch.object(Updater, 'is_installed', new_callable=PropertyMock, return_value=True),
438
+ patch.object(updater, '_get_velopack_manager', return_value=mock_manager),
439
+ ):
440
+ updater.apply_update_on_exit(restart=True, silent=True)
441
+
442
+ assert updater.state == UpdateState.APPLYING
443
+ mock_manager.wait_exit_then_apply_updates.assert_called_once_with(
444
+ mock_velopack_info,
445
+ silent=True,
446
+ restart=True,
447
+ restart_args=[],
448
+ )
449
+
450
+ @staticmethod
451
+ def test_apply_on_exit_silent_no_restart(updater: Updater) -> None:
452
+ """Verify silent=True, restart=False stages update silently."""
453
+ mock_velopack_info = MagicMock(spec=velopack.UpdateInfo)
454
+ updater._update_info = UpdateInfo(
455
+ available=True,
456
+ current_version=Version('1.0.0'),
457
+ latest_version=Version('2.0.0'),
458
+ _velopack_info=mock_velopack_info,
459
+ )
460
+ updater._state = UpdateState.DOWNLOADED
461
+
462
+ mock_manager = MagicMock(spec=velopack.UpdateManager)
463
+
464
+ with (
465
+ patch.object(Updater, 'is_installed', new_callable=PropertyMock, return_value=True),
466
+ patch.object(updater, '_get_velopack_manager', return_value=mock_manager),
467
+ ):
468
+ updater.apply_update_on_exit(restart=False, silent=True)
469
+
470
+ assert updater.state == UpdateState.APPLYING
471
+ mock_manager.wait_exit_then_apply_updates.assert_called_once_with(
472
+ mock_velopack_info,
473
+ silent=True,
474
+ restart=False,
475
+ restart_args=[],
476
+ )
477
+
478
+ @staticmethod
479
+ def test_apply_on_exit_silent_with_restart_args(updater: Updater) -> None:
480
+ """Verify silent mode forwards restart_args."""
481
+ mock_velopack_info = MagicMock(spec=velopack.UpdateInfo)
482
+ updater._update_info = UpdateInfo(
483
+ available=True,
484
+ current_version=Version('1.0.0'),
485
+ latest_version=Version('2.0.0'),
486
+ _velopack_info=mock_velopack_info,
487
+ )
488
+ updater._state = UpdateState.DOWNLOADED
489
+
490
+ mock_manager = MagicMock(spec=velopack.UpdateManager)
491
+
492
+ with (
493
+ patch.object(Updater, 'is_installed', new_callable=PropertyMock, return_value=True),
494
+ patch.object(updater, '_get_velopack_manager', return_value=mock_manager),
495
+ ):
496
+ updater.apply_update_on_exit(restart=True, silent=True, restart_args=['--minimized'])
497
+
498
+ assert updater.state == UpdateState.APPLYING
499
+ mock_manager.wait_exit_then_apply_updates.assert_called_once_with(
500
+ mock_velopack_info,
501
+ silent=True,
502
+ restart=True,
503
+ restart_args=['--minimized'],
504
+ )
411
505
 
412
506
 
413
507
  class TestInitializeVelopack: