Skip to content

Commit

Permalink
Show version info of test installed frameworks and their plugins
Browse files Browse the repository at this point in the history
The corresponding menu item is called Dependencies (and not 'Show versions')
to be consistent with spyder itself.
  • Loading branch information
StefRe committed Apr 14, 2020
1 parent 5736314 commit b6a7b73
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 1 deletion.
14 changes: 14 additions & 0 deletions spyder_unittest/backend/noserunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ class NoseRunner(RunnerBase):
module = 'nose'
name = 'nose'

def get_versions(self):
"""Return versions of framework and its plugins."""
import nose
from pkg_resources import iter_entry_points

versions = ['nose {}'.format(nose.__version__)]

for entry_point, _ in (nose.plugins.manager.EntryPointPluginManager
.entry_points):
for ep in iter_entry_points(entry_point):
versions.append(
" {} {}".format(ep.dist.project_name, ep.dist.version))
return versions

def create_argument_list(self):
"""Create argument list for testing process."""
return [
Expand Down
20 changes: 20 additions & 0 deletions spyder_unittest/backend/pytestrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,26 @@ class PyTestRunner(RunnerBase):
module = 'pytest'
name = 'pytest'

def get_versions(self):
"""Return versions of framework and its plugins."""
import pytest
versions = ['pytest {}'.format(pytest.__version__)]

class GetPluginVersionsPlugin():
def pytest_cmdline_main(self, config):
nonlocal versions
plugininfo = config.pluginmanager.list_plugin_distinfo()
if plugininfo:
for plugin, dist in plugininfo:
versions.append(" {} {}".format(dist.project_name,
dist.version))

# --capture=sys needed on Windows to avoid
# ValueError: saved filedescriptor not valid anymore
pytest.main(['-V', '--capture=sys'],
plugins=[GetPluginVersionsPlugin()])
return versions

def create_argument_list(self):
"""Create argument list for testing process."""
pyfile = os.path.join(os.path.dirname(__file__), 'pytestworker.py')
Expand Down
14 changes: 14 additions & 0 deletions spyder_unittest/backend/runnerbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,20 @@ def is_installed(cls):
"""
return find_spec_or_loader(cls.module) is not None

def get_versions(self):
"""
Return versions of framework and its installed plugins.
This function must only be called for installed frameworks.
Returns
-------
list of str
Strings with framework or plugin name, followed by
its version.
"""
raise NotImplementedError

def create_argument_list(self):
"""
Create argument list for testing process (dummy).
Expand Down
25 changes: 25 additions & 0 deletions spyder_unittest/backend/tests/test_noserunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,28 @@ def test_noserunner_load_data_passing_test_with_stdout(tmpdir):
runner = NoseRunner(None, result_file.strpath)
results = runner.load_data()
assert results[0].extra_text == ['----- Captured stdout -----', 'stdout text']


def test_get_versions_without_plugins(monkeypatch):
import nose
import pkg_resources
monkeypatch.setattr(nose, '__version__', '1.2.3')
monkeypatch.setattr(pkg_resources, 'iter_entry_points', lambda x: ())
runner = NoseRunner(None)
assert runner.get_versions() == ['nose 1.2.3']


def test_get_versions_with_plugins(monkeypatch):
import nose
import pkg_resources
monkeypatch.setattr(nose, '__version__', '1.2.3')
dist = pkg_resources.Distribution(project_name='myPlugin',
version='4.5.6')
ep = pkg_resources.EntryPoint('name', 'module_name', dist=dist)
monkeypatch.setattr(pkg_resources,
'iter_entry_points',
lambda ept: (x for x in (ep,) if ept == nose.plugins
.manager.EntryPointPluginManager
.entry_points[0][0]))
runner = NoseRunner(None)
assert runner.get_versions() == ['nose 1.2.3', ' myPlugin 4.5.6']
29 changes: 29 additions & 0 deletions spyder_unittest/backend/tests/test_pytestrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,32 @@ def test_logreport_to_testresult_with_output():
extra_text=txt, filename=osp.join('ham', 'foo.py'),
lineno=24)
assert logreport_to_testresult(report, Config(wdir='ham')) == expected


def test_get_versions_without_plugins(monkeypatch):
import pytest
monkeypatch.setattr(pytest, '__version__', '1.2.3')
from _pytest.config import PytestPluginManager
monkeypatch.setattr(
PytestPluginManager,
'list_plugin_distinfo', lambda _: ())

runner = PyTestRunner(None)
assert runner.get_versions() == ['pytest 1.2.3']


def test_get_versions_with_plugins(monkeypatch):
import pytest
import pkg_resources
monkeypatch.setattr(pytest, '__version__', '1.2.3')
dist1 = pkg_resources.Distribution(project_name='myPlugin1',
version='4.5.6')
dist2 = pkg_resources.Distribution(project_name='myPlugin2',
version='7.8.9')
from _pytest.config import PytestPluginManager
monkeypatch.setattr(
PytestPluginManager,
'list_plugin_distinfo', lambda _: (('1', dist1), ('2', dist2)))
runner = PyTestRunner(None)
assert runner.get_versions() == ['pytest 1.2.3', ' myPlugin1 4.5.6',
' myPlugin2 7.8.9']
7 changes: 7 additions & 0 deletions spyder_unittest/backend/tests/test_unittestrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,10 @@ def test_try_parse_header_starting_with_digit():
lines = ['0est_isupper (testfoo.TestStringMethods) ... ok']
res = runner.try_parse_result(lines, 0)
assert res is None


def test_get_versions(monkeypatch):
import platform
monkeypatch.setattr(platform, 'python_version', lambda: '1.2.3')
runner = UnittestRunner(None)
assert runner.get_versions() == ['unittest 1.2.3']
9 changes: 9 additions & 0 deletions spyder_unittest/backend/unittestrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ class UnittestRunner(RunnerBase):
module = 'unittest'
name = 'unittest'

def get_versions(self):
"""
Return versions of framework and its plugins.
As 'unittest' is a built-in framework, we return the python version.
"""
import platform
return ['unittest {}'.format(platform.python_version())]

def create_argument_list(self):
"""Create argument list for testing process."""
return ['-m', self.module, 'discover', '-v']
Expand Down
27 changes: 27 additions & 0 deletions spyder_unittest/widgets/tests/test_unittestgui.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,30 @@ def test_stop_running_tests_before_testresult_is_received(qtbot, tmpdir):

assert widget.testdatamodel.rowCount() == 0
assert widget.status_label.text() == ''


def test_show_versions(monkeypatch):
mockQMessageBox = Mock()
monkeypatch.setattr('spyder_unittest.widgets.unittestgui.QMessageBox',
mockQMessageBox)
widget = UnitTestWidget(None)
monkeypatch.setattr(widget.framework_registry.frameworks['nose'],
'is_installed', lambda: False)
monkeypatch.setattr(widget.framework_registry.frameworks['pytest'],
'is_installed', lambda: True)
monkeypatch.setattr(widget.framework_registry.frameworks['unittest'],
'is_installed', lambda: True)
monkeypatch.setattr(widget.framework_registry.frameworks['nose'],
'get_versions', lambda _: [])
monkeypatch.setattr(widget.framework_registry.frameworks['pytest'],
'get_versions',
lambda _: ['pytest 1.2.3', ' plugin1 4.5.6',
' plugin2 7.8.9'])
monkeypatch.setattr(widget.framework_registry.frameworks['unittest'],
'get_versions', lambda _: ['unittest 1.2.3'])
widget.show_versions()
expected = ('Versions of frameworks and their installed plugins:\n\n'
'nose: not available\n\npytest 1.2.3\n plugin1 4.5.6\n '
'plugin2 7.8.9\n\nunittest 1.2.3')
mockQMessageBox.information.assert_called_with(widget, 'Dependencies',
expected)
19 changes: 18 additions & 1 deletion spyder_unittest/widgets/unittestgui.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ def __init__(self, parent, options_button=None, options_menu=None):
self.options_menu.addAction(self.log_action)
self.options_menu.addAction(self.collapse_action)
self.options_menu.addAction(self.expand_action)
self.options_menu.addAction(self.versions_action)

self.options_button = options_button or QToolButton(self)
self.options_button.setIcon(ima.icon('tooloptions'))
Expand Down Expand Up @@ -173,9 +174,14 @@ def create_actions(self):
text=_('Expand all'),
icon=ima.icon('expand'),
triggered=self.testdataview.expandAll)
self.versions_action = create_action(
self,
text=_('Dependencies'),
icon=ima.icon('advanced'),
triggered=self.show_versions)
return [
self.config_action, self.log_action, self.collapse_action,
self.expand_action
self.expand_action, self.versions_action
]

def show_log(self):
Expand All @@ -188,6 +194,17 @@ def show_log(self):
te.show()
te.exec_()

def show_versions(self):
"""Show versions of frameworks and their plugins"""
versions = [_('Versions of frameworks and their installed plugins:')]
for name, runner in sorted(self.framework_registry.frameworks.items()):
version = (runner.get_versions(self) if runner.is_installed()
else None)
versions.append('\n'.join(version) if version else
'{}: {}'.format(name, _('not available')))
QMessageBox.information(self, _('Dependencies'),
_('\n\n'.join(versions)))

def configure(self):
"""Configure tests."""
if self.config:
Expand Down

0 comments on commit b6a7b73

Please sign in to comment.