# -*- coding: utf-8 -*- # # Copyright © 2013 Pierre Raybaut # Licensed under the terms of the MIT License # (see spyderlib/__init__.py for details) """Module checking Spyder optional runtime dependencies""" from spyderlib.qt.QtGui import (QDialog, QTableView, QItemDelegate, QColor, QVBoxLayout, QHBoxLayout, QPushButton, QApplication, QLabel, QDialogButtonBox) from spyderlib.qt.QtCore import (Qt, QModelIndex, QAbstractTableModel, SIGNAL, SLOT) from spyderlib.qt.compat import to_qvariant import sys # Local imports from spyderlib.baseconfig import _ from spyderlib.utils.qthelpers import get_icon from spyderlib import __version__ class DependenciesTableModel(QAbstractTableModel): def __init__(self, parent, dependencies): QAbstractTableModel.__init__(self, parent) self.dependencies = None self.set_data(dependencies) def set_data(self, dependencies): """Set model data""" self.dependencies = dependencies self.reset() def rowCount(self, qindex=QModelIndex()): """Array row number""" return len(self.dependencies) def columnCount(self, qindex=QModelIndex()): """Array column count""" return 4 def sort(self, column, order=Qt.DescendingOrder): """Overriding sort method""" if column == 0: self.dependencies.sort(key=lambda dep: getattr(dep, 'modname')) elif column == 1: pass elif column == 2: pass elif column == 3: pass self.reset() def headerData(self, section, orientation, role=Qt.DisplayRole): """Overriding method headerData""" if role != Qt.DisplayRole: return to_qvariant() i_column = int(section) if orientation == Qt.Horizontal: headers = (_("Module"), _(" Required "), _(" Installed "), _("Provided features")) return to_qvariant( headers[i_column] ) else: return to_qvariant() def get_value(self, index): """Return current value""" dep = self.dependencies[index.row()] return (dep.modname, dep.required_version, dep.get_installed_version(), dep.features)[index.column()] def data(self, index, role=Qt.DisplayRole): """Return data at table index""" if not index.isValid(): return to_qvariant() dep = self.dependencies[index.row()] if role == Qt.DisplayRole: if index.column() == 0: value = self.get_value(index) return to_qvariant(value) else: value = self.get_value(index) return to_qvariant(value) elif role == Qt.TextAlignmentRole: return to_qvariant(int(Qt.AlignLeft|Qt.AlignVCenter)) elif role == Qt.BackgroundColorRole: from spyderlib.dependencies import Dependency status = dep.get_status() if status == Dependency.NOK: color = QColor(Qt.red) color.setAlphaF(.25) return to_qvariant(color) class DependenciesDelegate(QItemDelegate): def __init__(self, parent=None): QItemDelegate.__init__(self, parent) class DependenciesTableView(QTableView): def __init__(self, parent, data): QTableView.__init__(self, parent) self.model = DependenciesTableModel(self, data) self.setModel(self.model) self.delegate = DependenciesDelegate(self) self.setItemDelegate(self.delegate) self.setup_table() def setup_table(self): """Setup table""" self.horizontalHeader().setStretchLastSection(True) self.adjust_columns() self.columnAt(0) # Sorting columns self.setSortingEnabled(False) self.sortByColumn(0, Qt.DescendingOrder) def adjust_columns(self): """Resize three first columns to contents""" for col in range(3): self.resizeColumnToContents(col) class DependenciesDialog(QDialog): def __init__(self, parent): QDialog.__init__(self, parent) self.setWindowTitle("Spyder %s: %s" % (__version__, _("Optional Dependencies"))) self.setWindowIcon(get_icon('advanced.png')) self.setModal(True) self.view = DependenciesTableView(self, []) important_mods = ['rope', 'pyflakes', 'IPython', 'matplotlib'] self.label = QLabel(_("Spyder depends on several Python modules to " "provide additional functionality for its " "plugins. The table below shows the required " "and installed versions (if any) of all of " "them.

" "Although Spyder can work without any of these " "modules, it's strongly recommended that at " "least you try to install %s and " "%s to have a much better experience.") % (', '.join(important_mods[:-1]), important_mods[-1])) self.label.setWordWrap(True) self.label.setAlignment(Qt.AlignJustify) self.label.setContentsMargins(5, 8, 12, 10) btn = QPushButton(_("Copy to clipboard"), ) self.connect(btn, SIGNAL('clicked()'), self.copy_to_clipboard) bbox = QDialogButtonBox(QDialogButtonBox.Ok) self.connect(bbox, SIGNAL("accepted()"), SLOT("accept()")) hlayout = QHBoxLayout() hlayout.addWidget(btn) hlayout.addStretch() hlayout.addWidget(bbox) vlayout = QVBoxLayout() vlayout.addWidget(self.label) vlayout.addWidget(self.view) vlayout.addLayout(hlayout) self.setLayout(vlayout) self.resize(630, 420) def set_data(self, dependencies): self.view.model.set_data(dependencies) self.view.adjust_columns() self.view.sortByColumn(0, Qt.DescendingOrder) def copy_to_clipboard(self): from spyderlib.dependencies import status QApplication.clipboard().setText(status()) def test(): """Run dependency widget test""" from spyderlib import dependencies # Test sample dependencies.add("IPython", "Enhanced Python interpreter", ">=0.13") dependencies.add("matplotlib", "Interactive data plotting", ">=1.0") dependencies.add("sympy", "Symbolic Mathematics", ">=10.0") dependencies.add("foo", "Non-existent module", ">=1.0") from spyderlib.utils.qthelpers import qapplication app = qapplication() dlg = DependenciesDialog(None) dlg.set_data(dependencies.DEPENDENCIES) dlg.show() sys.exit(dlg.exec_()) if __name__ == '__main__': test()