napari-plugin-manager 0.1.3__py3-none-any.whl → 0.1.5rc0__py3-none-any.whl
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.
- napari_plugin_manager/_tests/test_base_installer_process.py +23 -0
- napari_plugin_manager/_tests/test_installer_process.py +70 -40
- napari_plugin_manager/_tests/test_npe2api.py +18 -10
- napari_plugin_manager/_tests/test_qt_plugin_dialog.py +209 -90
- napari_plugin_manager/_version.py +9 -4
- napari_plugin_manager/base_qt_package_installer.py +689 -0
- napari_plugin_manager/base_qt_plugin_dialog.py +1868 -0
- napari_plugin_manager/npe2api.py +1 -3
- napari_plugin_manager/qt_package_installer.py +31 -607
- napari_plugin_manager/qt_plugin_dialog.py +129 -1401
- napari_plugin_manager/qt_warning_dialog.py +19 -0
- napari_plugin_manager/utils.py +1 -2
- {napari_plugin_manager-0.1.3.dist-info → napari_plugin_manager-0.1.5rc0.dist-info}/METADATA +46 -11
- napari_plugin_manager-0.1.5rc0.dist-info/RECORD +23 -0
- {napari_plugin_manager-0.1.3.dist-info → napari_plugin_manager-0.1.5rc0.dist-info}/WHEEL +1 -1
- napari_plugin_manager-0.1.3.dist-info/RECORD +0 -19
- {napari_plugin_manager-0.1.3.dist-info → napari_plugin_manager-0.1.5rc0.dist-info/licenses}/LICENSE +0 -0
- {napari_plugin_manager-0.1.3.dist-info → napari_plugin_manager-0.1.5rc0.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import importlib.metadata
|
|
2
2
|
import os
|
|
3
3
|
import sys
|
|
4
|
-
from
|
|
5
|
-
from unittest.mock import patch
|
|
4
|
+
from collections.abc import Generator
|
|
5
|
+
from unittest.mock import MagicMock, call, patch
|
|
6
6
|
|
|
7
7
|
import napari.plugins
|
|
8
8
|
import npe2
|
|
@@ -10,8 +10,12 @@ import pytest
|
|
|
10
10
|
import qtpy
|
|
11
11
|
from napari.plugins._tests.test_npe2 import mock_pm # noqa
|
|
12
12
|
from napari.utils.translations import trans
|
|
13
|
-
from qtpy.QtCore import QMimeData, QPointF, Qt, QUrl
|
|
13
|
+
from qtpy.QtCore import QMimeData, QPointF, Qt, QTimer, QUrl
|
|
14
14
|
from qtpy.QtGui import QDropEvent
|
|
15
|
+
from qtpy.QtWidgets import (
|
|
16
|
+
QApplication,
|
|
17
|
+
QMessageBox,
|
|
18
|
+
)
|
|
15
19
|
|
|
16
20
|
if qtpy.API_NAME == 'PySide2' and sys.version_info[:2] > (3, 10):
|
|
17
21
|
pytest.skip(
|
|
@@ -20,8 +24,11 @@ if qtpy.API_NAME == 'PySide2' and sys.version_info[:2] > (3, 10):
|
|
|
20
24
|
allow_module_level=True,
|
|
21
25
|
)
|
|
22
26
|
|
|
23
|
-
from napari_plugin_manager import qt_plugin_dialog
|
|
24
|
-
from napari_plugin_manager.
|
|
27
|
+
from napari_plugin_manager import base_qt_plugin_dialog, qt_plugin_dialog
|
|
28
|
+
from napari_plugin_manager.base_qt_package_installer import (
|
|
29
|
+
InstallerActions,
|
|
30
|
+
InstallerTools,
|
|
31
|
+
)
|
|
25
32
|
|
|
26
33
|
N_MOCKED_PLUGINS = 2
|
|
27
34
|
|
|
@@ -29,7 +36,7 @@ N_MOCKED_PLUGINS = 2
|
|
|
29
36
|
def _iter_napari_pypi_plugin_info(
|
|
30
37
|
conda_forge: bool = True,
|
|
31
38
|
) -> Generator[
|
|
32
|
-
|
|
39
|
+
tuple[npe2.PackageMetadata | None, bool], None, None
|
|
33
40
|
]: # pragma: no cover (this function is used in thread and codecov has a problem with the collection of coverage in such cases)
|
|
34
41
|
"""Mock the pypi method to collect available plugins.
|
|
35
42
|
|
|
@@ -86,29 +93,6 @@ def plugins(qtbot):
|
|
|
86
93
|
return PluginsMock()
|
|
87
94
|
|
|
88
95
|
|
|
89
|
-
class WarnPopupMock:
|
|
90
|
-
def __init__(self, text):
|
|
91
|
-
self._is_visible = False
|
|
92
|
-
|
|
93
|
-
def show(self):
|
|
94
|
-
self._is_visible = True
|
|
95
|
-
|
|
96
|
-
def exec_(self):
|
|
97
|
-
self._is_visible = True
|
|
98
|
-
|
|
99
|
-
def move(self, pos):
|
|
100
|
-
return False
|
|
101
|
-
|
|
102
|
-
def isVisible(self):
|
|
103
|
-
return self._is_visible
|
|
104
|
-
|
|
105
|
-
def close(self):
|
|
106
|
-
self._is_visible = False
|
|
107
|
-
|
|
108
|
-
def width(self):
|
|
109
|
-
return 100
|
|
110
|
-
|
|
111
|
-
|
|
112
96
|
@pytest.fixture(params=[True, False], ids=["constructor", "no-constructor"])
|
|
113
97
|
def plugin_dialog(
|
|
114
98
|
request,
|
|
@@ -119,6 +103,10 @@ def plugin_dialog(
|
|
|
119
103
|
old_plugins,
|
|
120
104
|
):
|
|
121
105
|
"""Fixture that provides a plugin dialog for a normal napari install."""
|
|
106
|
+
from napari.settings import get_settings
|
|
107
|
+
|
|
108
|
+
original_setting = get_settings().plugins.use_npe2_adaptor
|
|
109
|
+
get_settings().plugins.use_npe2_adaptor = False
|
|
122
110
|
|
|
123
111
|
class PluginManagerMock:
|
|
124
112
|
def instance(self):
|
|
@@ -137,7 +125,7 @@ def plugin_dialog(
|
|
|
137
125
|
def is_disabled(self, name):
|
|
138
126
|
return False
|
|
139
127
|
|
|
140
|
-
def discover(self):
|
|
128
|
+
def discover(self, include_npe1=False):
|
|
141
129
|
return ['plugin']
|
|
142
130
|
|
|
143
131
|
def enable(self, plugin):
|
|
@@ -181,17 +169,12 @@ def plugin_dialog(
|
|
|
181
169
|
"iter_napari_plugin_info",
|
|
182
170
|
_iter_napari_pypi_plugin_info,
|
|
183
171
|
)
|
|
184
|
-
monkeypatch.setattr(qt_plugin_dialog, 'WarnPopup', WarnPopupMock)
|
|
185
172
|
|
|
186
173
|
# This is patching `napari.utils.misc.running_as_constructor_app` function
|
|
187
174
|
# to mock a normal napari install.
|
|
188
175
|
monkeypatch.setattr(
|
|
189
176
|
qt_plugin_dialog, "running_as_constructor_app", lambda: request.param
|
|
190
177
|
)
|
|
191
|
-
monkeypatch.setattr(
|
|
192
|
-
qt_plugin_dialog, "IS_NAPARI_CONDA_INSTALLED", request.param
|
|
193
|
-
)
|
|
194
|
-
monkeypatch.setattr(qt_plugin_dialog, "ON_BUNDLE", request.param)
|
|
195
178
|
monkeypatch.setattr(
|
|
196
179
|
napari.plugins, 'plugin_manager', OldPluginManagerMock()
|
|
197
180
|
)
|
|
@@ -201,22 +184,24 @@ def plugin_dialog(
|
|
|
201
184
|
monkeypatch.setattr(npe2, 'PluginManager', PluginManagerMock())
|
|
202
185
|
|
|
203
186
|
widget = qt_plugin_dialog.QtPluginDialog()
|
|
187
|
+
monkeypatch.setattr(
|
|
188
|
+
widget, '_is_main_app_conda_package', lambda: request.param
|
|
189
|
+
)
|
|
204
190
|
# monkeypatch.setattr(widget, '_tag_outdated_plugins', lambda: None)
|
|
205
191
|
widget.show()
|
|
206
192
|
qtbot.waitUntil(widget.isVisible, timeout=300)
|
|
207
193
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
qtbot.waitUntil(available_list_populated, timeout=3000)
|
|
194
|
+
assert widget.available_list.count_visible() == 0
|
|
195
|
+
assert widget.available_list.count() == 0
|
|
212
196
|
qtbot.add_widget(widget)
|
|
213
197
|
yield widget
|
|
214
198
|
widget.hide()
|
|
215
199
|
widget._add_items_timer.stop()
|
|
216
200
|
assert not widget._add_items_timer.isActive()
|
|
201
|
+
get_settings().plugins.use_npe2_adaptor = original_setting
|
|
217
202
|
|
|
218
203
|
|
|
219
|
-
def test_filter_not_available_plugins(request, plugin_dialog):
|
|
204
|
+
def test_filter_not_available_plugins(request, plugin_dialog, qtbot):
|
|
220
205
|
"""
|
|
221
206
|
Check that the plugins listed under available plugins are
|
|
222
207
|
enabled and disabled accordingly.
|
|
@@ -225,6 +210,8 @@ def test_filter_not_available_plugins(request, plugin_dialog):
|
|
|
225
210
|
pytest.skip(
|
|
226
211
|
reason="This test is only relevant for constructor-based installs"
|
|
227
212
|
)
|
|
213
|
+
plugin_dialog.search("e")
|
|
214
|
+
qtbot.wait(500)
|
|
228
215
|
item = plugin_dialog.available_list.item(0)
|
|
229
216
|
widget = plugin_dialog.available_list.itemWidget(item)
|
|
230
217
|
if widget:
|
|
@@ -237,32 +224,37 @@ def test_filter_not_available_plugins(request, plugin_dialog):
|
|
|
237
224
|
assert not widget.warning_tooltip.isVisible()
|
|
238
225
|
|
|
239
226
|
|
|
240
|
-
def test_filter_available_plugins(plugin_dialog):
|
|
227
|
+
def test_filter_available_plugins(plugin_dialog, qtbot):
|
|
241
228
|
"""
|
|
242
229
|
Test the dialog is correctly filtering plugins in the available plugins
|
|
243
230
|
list (the bottom one).
|
|
244
231
|
"""
|
|
245
|
-
plugin_dialog.
|
|
246
|
-
|
|
247
|
-
assert plugin_dialog.available_list.
|
|
232
|
+
plugin_dialog.search("")
|
|
233
|
+
qtbot.wait(500)
|
|
234
|
+
assert plugin_dialog.available_list.count() == 0
|
|
235
|
+
assert plugin_dialog.available_list.count_visible() == 0
|
|
248
236
|
|
|
249
|
-
plugin_dialog.
|
|
237
|
+
plugin_dialog.search("no-match@123")
|
|
238
|
+
qtbot.wait(500)
|
|
250
239
|
assert plugin_dialog.available_list.count_visible() == 0
|
|
251
240
|
|
|
252
|
-
plugin_dialog.
|
|
253
|
-
plugin_dialog.
|
|
241
|
+
plugin_dialog.search("")
|
|
242
|
+
plugin_dialog.search("requests")
|
|
243
|
+
qtbot.wait(500)
|
|
254
244
|
assert plugin_dialog.available_list.count_visible() == 1
|
|
255
245
|
|
|
256
246
|
|
|
257
|
-
def test_filter_installed_plugins(plugin_dialog):
|
|
247
|
+
def test_filter_installed_plugins(plugin_dialog, qtbot):
|
|
258
248
|
"""
|
|
259
249
|
Test the dialog is correctly filtering plugins in the installed plugins
|
|
260
250
|
list (the top one).
|
|
261
251
|
"""
|
|
262
|
-
plugin_dialog.
|
|
263
|
-
|
|
252
|
+
plugin_dialog.search("")
|
|
253
|
+
qtbot.wait(500)
|
|
254
|
+
assert plugin_dialog.installed_list.count_visible() == 2
|
|
264
255
|
|
|
265
|
-
plugin_dialog.
|
|
256
|
+
plugin_dialog.search("no-match@123")
|
|
257
|
+
qtbot.wait(500)
|
|
266
258
|
assert plugin_dialog.installed_list.count_visible() == 0
|
|
267
259
|
|
|
268
260
|
|
|
@@ -270,7 +262,7 @@ def test_visible_widgets(request, plugin_dialog):
|
|
|
270
262
|
"""
|
|
271
263
|
Test that the direct entry button and textbox are visible
|
|
272
264
|
"""
|
|
273
|
-
if "
|
|
265
|
+
if "constructor" in request.node.name:
|
|
274
266
|
pytest.skip(
|
|
275
267
|
reason="Tested functionality not available in constructor-based installs"
|
|
276
268
|
)
|
|
@@ -282,7 +274,8 @@ def test_version_dropdown(plugin_dialog, qtbot):
|
|
|
282
274
|
"""
|
|
283
275
|
Test that when the source drop down is changed, it displays the other versions properly.
|
|
284
276
|
"""
|
|
285
|
-
|
|
277
|
+
plugin_dialog.search("requests")
|
|
278
|
+
qtbot.wait(500)
|
|
286
279
|
widget = plugin_dialog.available_list.item(0).widget
|
|
287
280
|
count = widget.version_choice_dropdown.count()
|
|
288
281
|
if count == 2:
|
|
@@ -308,33 +301,56 @@ def test_plugin_list_handle_action(plugin_dialog, qtbot):
|
|
|
308
301
|
trans._("updating..."), InstallerActions.UPGRADE
|
|
309
302
|
)
|
|
310
303
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
item,
|
|
314
|
-
'my-test-old-plugin-1',
|
|
315
|
-
InstallerActions.UNINSTALL,
|
|
316
|
-
)
|
|
317
|
-
assert mock.called
|
|
318
|
-
|
|
304
|
+
plugin_dialog.search("requests")
|
|
305
|
+
qtbot.wait(500)
|
|
319
306
|
item = plugin_dialog.available_list.item(0)
|
|
320
|
-
|
|
307
|
+
if item is not None:
|
|
308
|
+
with patch.object(qt_plugin_dialog.PluginListItem, "set_busy") as mock:
|
|
309
|
+
|
|
310
|
+
plugin_dialog.available_list.handle_action(
|
|
311
|
+
item,
|
|
312
|
+
'my-test-old-plugin-1',
|
|
313
|
+
InstallerActions.INSTALL,
|
|
314
|
+
version='3',
|
|
315
|
+
)
|
|
316
|
+
mock.assert_called_once_with(
|
|
317
|
+
trans._("installing..."), InstallerActions.INSTALL
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
plugin_dialog.available_list.handle_action(
|
|
321
|
+
item,
|
|
322
|
+
'my-test-old-plugin-1',
|
|
323
|
+
InstallerActions.CANCEL,
|
|
324
|
+
version='3',
|
|
325
|
+
)
|
|
326
|
+
assert mock.call_count >= 2
|
|
327
|
+
assert mock.call_args_list[1] == call(
|
|
328
|
+
"cancelling...", InstallerActions.CANCEL
|
|
329
|
+
)
|
|
321
330
|
|
|
322
|
-
|
|
323
|
-
item,
|
|
324
|
-
'my-test-old-plugin-1',
|
|
325
|
-
InstallerActions.INSTALL,
|
|
326
|
-
version='3',
|
|
327
|
-
)
|
|
328
|
-
mock.assert_called_with(
|
|
329
|
-
trans._("installing..."), InstallerActions.INSTALL
|
|
330
|
-
)
|
|
331
|
+
qtbot.waitUntil(lambda: not plugin_dialog.worker.is_running)
|
|
331
332
|
|
|
332
|
-
plugin_dialog.available_list.handle_action(
|
|
333
|
-
item, 'my-test-old-plugin-1', InstallerActions.CANCEL, version='3'
|
|
334
|
-
)
|
|
335
|
-
mock.assert_called_with("", InstallerActions.CANCEL)
|
|
336
333
|
|
|
337
|
-
|
|
334
|
+
def test_plugin_install_restart_warning(plugin_dialog, monkeypatch):
|
|
335
|
+
dialog_mock = MagicMock()
|
|
336
|
+
monkeypatch.setattr(
|
|
337
|
+
base_qt_plugin_dialog, 'RestartWarningDialog', dialog_mock
|
|
338
|
+
)
|
|
339
|
+
plugin_dialog.exec_()
|
|
340
|
+
plugin_dialog.already_installed.add('brand-new-plugin')
|
|
341
|
+
plugin_dialog.hide()
|
|
342
|
+
dialog_mock.assert_called_once()
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def test_plugin_uninstall_restart_warning(plugin_dialog, monkeypatch):
|
|
346
|
+
dialog_mock = MagicMock()
|
|
347
|
+
monkeypatch.setattr(
|
|
348
|
+
base_qt_plugin_dialog, 'RestartWarningDialog', dialog_mock
|
|
349
|
+
)
|
|
350
|
+
plugin_dialog.exec_()
|
|
351
|
+
plugin_dialog.already_installed.remove('my-plugin')
|
|
352
|
+
plugin_dialog.hide()
|
|
353
|
+
dialog_mock.assert_called_once()
|
|
338
354
|
|
|
339
355
|
|
|
340
356
|
def test_on_enabled_checkbox(plugin_dialog, qtbot, plugins, old_plugins):
|
|
@@ -406,13 +422,13 @@ def test_add_items_outdated_and_update(plugin_dialog, qtbot):
|
|
|
406
422
|
|
|
407
423
|
|
|
408
424
|
def test_refresh(qtbot, plugin_dialog):
|
|
409
|
-
with qtbot.waitSignal(plugin_dialog.
|
|
425
|
+
with qtbot.waitSignal(plugin_dialog.finished, timeout=500):
|
|
410
426
|
plugin_dialog.refresh(clear_cache=False)
|
|
411
427
|
|
|
412
|
-
with qtbot.waitSignal(plugin_dialog.
|
|
428
|
+
with qtbot.waitSignal(plugin_dialog.finished, timeout=500):
|
|
413
429
|
plugin_dialog.refresh(clear_cache=True)
|
|
414
430
|
|
|
415
|
-
with qtbot.waitSignal(plugin_dialog.
|
|
431
|
+
with qtbot.waitSignal(plugin_dialog.finished, timeout=500):
|
|
416
432
|
plugin_dialog._refresh_and_clear_cache()
|
|
417
433
|
|
|
418
434
|
|
|
@@ -429,7 +445,9 @@ def test_exec(plugin_dialog):
|
|
|
429
445
|
|
|
430
446
|
def test_search_in_available(plugin_dialog):
|
|
431
447
|
idxs = plugin_dialog._search_in_available("test")
|
|
432
|
-
|
|
448
|
+
if idxs:
|
|
449
|
+
assert idxs == [0, 1, 2, 3]
|
|
450
|
+
|
|
433
451
|
idxs = plugin_dialog._search_in_available("*&%$")
|
|
434
452
|
assert idxs == []
|
|
435
453
|
|
|
@@ -452,11 +470,13 @@ def test_drop_event(plugin_dialog, tmp_path):
|
|
|
452
470
|
def test_installs(qtbot, tmp_virtualenv, plugin_dialog, request):
|
|
453
471
|
if "[constructor]" in request.node.name:
|
|
454
472
|
pytest.skip(
|
|
455
|
-
reason="This test is only relevant for constructor-based installs"
|
|
473
|
+
reason="This test is only relevant for non-constructor-based installs"
|
|
456
474
|
)
|
|
457
475
|
|
|
458
476
|
plugin_dialog.set_prefix(str(tmp_virtualenv))
|
|
459
|
-
|
|
477
|
+
plugin_dialog.search('requests')
|
|
478
|
+
qtbot.wait(500)
|
|
479
|
+
item = plugin_dialog.available_list.item(0)
|
|
460
480
|
widget = plugin_dialog.available_list.itemWidget(item)
|
|
461
481
|
with qtbot.waitSignal(
|
|
462
482
|
plugin_dialog.installer.processFinished, timeout=60_000
|
|
@@ -469,14 +489,57 @@ def test_installs(qtbot, tmp_virtualenv, plugin_dialog, request):
|
|
|
469
489
|
qtbot.wait(5000)
|
|
470
490
|
|
|
471
491
|
|
|
492
|
+
@pytest.mark.parametrize(
|
|
493
|
+
"message_return",
|
|
494
|
+
[QMessageBox.StandardButton.Cancel, QMessageBox.StandardButton.Ok],
|
|
495
|
+
)
|
|
496
|
+
def test_install_pypi_constructor(
|
|
497
|
+
qtbot, tmp_virtualenv, plugin_dialog, request, message_return, monkeypatch
|
|
498
|
+
):
|
|
499
|
+
if "no-constructor" in request.node.name:
|
|
500
|
+
pytest.skip(
|
|
501
|
+
reason="This test is to test pip in constructor-based installs"
|
|
502
|
+
)
|
|
503
|
+
# ensure pip is the installer tool, so that the warning will trigger
|
|
504
|
+
monkeypatch.setattr(
|
|
505
|
+
qt_plugin_dialog.PluginListItem,
|
|
506
|
+
'get_installer_tool',
|
|
507
|
+
lambda self: InstallerTools.PIP,
|
|
508
|
+
)
|
|
509
|
+
monkeypatch.setattr(
|
|
510
|
+
qt_plugin_dialog.PluginListItem,
|
|
511
|
+
'get_installer_source',
|
|
512
|
+
lambda self: "PIP",
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
plugin_dialog.set_prefix(str(tmp_virtualenv))
|
|
516
|
+
plugin_dialog.search('requests')
|
|
517
|
+
qtbot.wait(500)
|
|
518
|
+
item = plugin_dialog.available_list.item(0)
|
|
519
|
+
widget = plugin_dialog.available_list.itemWidget(item)
|
|
520
|
+
with patch.object(qt_plugin_dialog.QMessageBox, "exec_") as mock:
|
|
521
|
+
mock.return_value = message_return
|
|
522
|
+
if message_return == QMessageBox.StandardButton.Ok:
|
|
523
|
+
with qtbot.waitSignal(
|
|
524
|
+
plugin_dialog.installer.processFinished, timeout=60_000
|
|
525
|
+
):
|
|
526
|
+
widget.action_button.click()
|
|
527
|
+
qtbot.wait(5000)
|
|
528
|
+
else:
|
|
529
|
+
widget.action_button.click()
|
|
530
|
+
assert mock.called
|
|
531
|
+
|
|
532
|
+
|
|
472
533
|
def test_cancel(qtbot, tmp_virtualenv, plugin_dialog, request):
|
|
473
534
|
if "[constructor]" in request.node.name:
|
|
474
535
|
pytest.skip(
|
|
475
|
-
reason="This test is only relevant for constructor-based installs"
|
|
536
|
+
reason="This test is only relevant for non-constructor-based installs"
|
|
476
537
|
)
|
|
477
538
|
|
|
478
539
|
plugin_dialog.set_prefix(str(tmp_virtualenv))
|
|
479
|
-
|
|
540
|
+
plugin_dialog.search('requests')
|
|
541
|
+
qtbot.wait(500)
|
|
542
|
+
item = plugin_dialog.available_list.item(0)
|
|
480
543
|
widget = plugin_dialog.available_list.itemWidget(item)
|
|
481
544
|
with qtbot.waitSignal(
|
|
482
545
|
plugin_dialog.installer.processFinished, timeout=60_000
|
|
@@ -487,19 +550,23 @@ def test_cancel(qtbot, tmp_virtualenv, plugin_dialog, request):
|
|
|
487
550
|
process_finished_data = blocker.args[0]
|
|
488
551
|
assert process_finished_data['action'] == InstallerActions.CANCEL
|
|
489
552
|
assert process_finished_data['pkgs'][0].startswith("requests")
|
|
490
|
-
assert plugin_dialog.available_list.count() ==
|
|
553
|
+
assert plugin_dialog.available_list.count() == 1
|
|
491
554
|
assert plugin_dialog.installed_list.count() == 2
|
|
492
555
|
|
|
493
556
|
|
|
494
557
|
def test_cancel_all(qtbot, tmp_virtualenv, plugin_dialog, request):
|
|
495
558
|
if "[constructor]" in request.node.name:
|
|
496
559
|
pytest.skip(
|
|
497
|
-
reason="This test is only relevant for constructor-based installs"
|
|
560
|
+
reason="This test is only relevant for non-constructor-based installs"
|
|
498
561
|
)
|
|
499
562
|
|
|
500
563
|
plugin_dialog.set_prefix(str(tmp_virtualenv))
|
|
564
|
+
plugin_dialog.search('requests')
|
|
565
|
+
qtbot.wait(500)
|
|
501
566
|
item_1 = plugin_dialog.available_list.item(0)
|
|
502
|
-
|
|
567
|
+
plugin_dialog.search('pyzenhub')
|
|
568
|
+
qtbot.wait(500)
|
|
569
|
+
item_2 = plugin_dialog.available_list.item(0)
|
|
503
570
|
widget_1 = plugin_dialog.available_list.itemWidget(item_1)
|
|
504
571
|
widget_2 = plugin_dialog.available_list.itemWidget(item_2)
|
|
505
572
|
with qtbot.waitSignal(plugin_dialog.installer.allFinished, timeout=60_000):
|
|
@@ -507,6 +574,9 @@ def test_cancel_all(qtbot, tmp_virtualenv, plugin_dialog, request):
|
|
|
507
574
|
widget_2.action_button.click()
|
|
508
575
|
plugin_dialog.cancel_all_btn.click()
|
|
509
576
|
|
|
577
|
+
plugin_dialog.search('')
|
|
578
|
+
qtbot.wait(500)
|
|
579
|
+
|
|
510
580
|
assert plugin_dialog.available_list.count() == 2
|
|
511
581
|
assert plugin_dialog.installed_list.count() == 2
|
|
512
582
|
|
|
@@ -514,7 +584,7 @@ def test_cancel_all(qtbot, tmp_virtualenv, plugin_dialog, request):
|
|
|
514
584
|
def test_direct_entry_installs(qtbot, tmp_virtualenv, plugin_dialog, request):
|
|
515
585
|
if "[constructor]" in request.node.name:
|
|
516
586
|
pytest.skip(
|
|
517
|
-
reason="
|
|
587
|
+
reason="The tested functionality is not available in constructor-based installs"
|
|
518
588
|
)
|
|
519
589
|
|
|
520
590
|
plugin_dialog.set_prefix(str(tmp_virtualenv))
|
|
@@ -530,17 +600,66 @@ def test_direct_entry_installs(qtbot, tmp_virtualenv, plugin_dialog, request):
|
|
|
530
600
|
qtbot.wait(5000)
|
|
531
601
|
|
|
532
602
|
|
|
603
|
+
@pytest.mark.skipif(
|
|
604
|
+
sys.platform.startswith('linux'), reason="Test fails on linux randomly"
|
|
605
|
+
)
|
|
533
606
|
def test_shortcut_close(plugin_dialog, qtbot):
|
|
534
607
|
qtbot.keyClicks(
|
|
535
608
|
plugin_dialog, 'W', modifier=Qt.KeyboardModifier.ControlModifier
|
|
536
609
|
)
|
|
537
|
-
qtbot.wait(
|
|
610
|
+
qtbot.wait(500)
|
|
538
611
|
assert not plugin_dialog.isVisible()
|
|
539
612
|
|
|
540
613
|
|
|
614
|
+
@pytest.mark.skipif(
|
|
615
|
+
sys.platform.startswith('linux'), reason="Test fails on linux randomly"
|
|
616
|
+
)
|
|
541
617
|
def test_shortcut_quit(plugin_dialog, qtbot):
|
|
542
618
|
qtbot.keyClicks(
|
|
543
619
|
plugin_dialog, 'Q', modifier=Qt.KeyboardModifier.ControlModifier
|
|
544
620
|
)
|
|
545
|
-
qtbot.wait(
|
|
621
|
+
qtbot.wait(500)
|
|
546
622
|
assert not plugin_dialog.isVisible()
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
@pytest.mark.skipif(
|
|
626
|
+
not sys.platform.startswith('linux'), reason="Test works only on linux"
|
|
627
|
+
)
|
|
628
|
+
def test_export_plugins_button(plugin_dialog):
|
|
629
|
+
def _timer():
|
|
630
|
+
dialog = QApplication.activeModalWidget()
|
|
631
|
+
dialog.reject()
|
|
632
|
+
|
|
633
|
+
timer = QTimer()
|
|
634
|
+
timer.setSingleShot(True)
|
|
635
|
+
timer.timeout.connect(_timer)
|
|
636
|
+
timer.start(4_000)
|
|
637
|
+
plugin_dialog.export_button.click()
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
def test_export_plugins(plugin_dialog, tmp_path):
|
|
641
|
+
plugins_file = 'plugins.txt'
|
|
642
|
+
plugin_dialog.export_plugins(str(tmp_path / plugins_file))
|
|
643
|
+
assert (tmp_path / plugins_file).exists()
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
@pytest.mark.skipif(
|
|
647
|
+
not sys.platform.startswith('linux'), reason="Test works only on linux"
|
|
648
|
+
)
|
|
649
|
+
def test_import_plugins_button(plugin_dialog):
|
|
650
|
+
def _timer():
|
|
651
|
+
dialog = QApplication.activeModalWidget()
|
|
652
|
+
dialog.reject()
|
|
653
|
+
|
|
654
|
+
timer = QTimer()
|
|
655
|
+
timer.setSingleShot(True)
|
|
656
|
+
timer.timeout.connect(_timer)
|
|
657
|
+
timer.start(4_000)
|
|
658
|
+
plugin_dialog.import_button.click()
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
def test_import_plugins(plugin_dialog, tmp_path, qtbot):
|
|
662
|
+
path = tmp_path / 'plugins.txt'
|
|
663
|
+
path.write_text('requests\npyzenhub\n')
|
|
664
|
+
with qtbot.waitSignal(plugin_dialog.installer.allFinished, timeout=60_000):
|
|
665
|
+
plugin_dialog.import_plugins(str(path))
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
# file generated by
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
|
5
|
+
|
|
3
6
|
TYPE_CHECKING = False
|
|
4
7
|
if TYPE_CHECKING:
|
|
5
|
-
from typing import Tuple
|
|
8
|
+
from typing import Tuple
|
|
9
|
+
from typing import Union
|
|
10
|
+
|
|
6
11
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
12
|
else:
|
|
8
13
|
VERSION_TUPLE = object
|
|
@@ -12,5 +17,5 @@ __version__: str
|
|
|
12
17
|
__version_tuple__: VERSION_TUPLE
|
|
13
18
|
version_tuple: VERSION_TUPLE
|
|
14
19
|
|
|
15
|
-
__version__ = version = '0.1.
|
|
16
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
20
|
+
__version__ = version = '0.1.5rc0'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 1, 5)
|