From b2d37bc8bec67c6d4cf666d014f8647836785cc9 Mon Sep 17 00:00:00 2001 From: Alex Schwarz Date: Tue, 11 Dec 2018 16:28:13 +0100 Subject: [PATCH] PEP8 issues and fix of the mercurial version --- spyder/plugins/explorer/widgets.py | 207 +++++++++++++++-------------- spyder/utils/vcs.py | 21 +-- 2 files changed, 121 insertions(+), 107 deletions(-) diff --git a/spyder/plugins/explorer/widgets.py b/spyder/plugins/explorer/widgets.py index e53549eadc6..6ae9a877924 100644 --- a/spyder/plugins/explorer/widgets.py +++ b/spyder/plugins/explorer/widgets.py @@ -53,9 +53,10 @@ def open_file_in_external_explorer(filename): elif os.name == 'nt': subprocess.call(["explorer", "/select,", filename]) else: - filename=os.path.dirname(filename) + filename = os.path.dirname(filename) subprocess.call(["xdg-open", filename]) + def show_in_external_file_explorer(fnames=None): """Show files in external file explorer @@ -67,6 +68,7 @@ def show_in_external_file_explorer(fnames=None): for fname in fnames: open_file_in_external_explorer(fname) + def fixpath(path): """Normalize path fixing case, making absolute and removing symlinks""" norm = osp.normcase if os.name == 'nt' else osp.normpath @@ -84,6 +86,7 @@ def create_script(fname): "

Error message:
%s" ) % (osp.basename(fname), str(error))) + def listdir(path, include=r'.', exclude=r'\.pyc$|^\.', show_all=False, folders_only=False): """List files and directories""" @@ -106,8 +109,8 @@ def has_subdirectories(path, include, exclude, show_all): """Return True if path has subdirectories""" try: # > 1 because of '..' - return len( listdir(path, include, exclude, - show_all, folders_only=True) ) > 1 + return len(listdir(path, include, exclude, + show_all, folders_only=True)) > 1 except (IOError, OSError): return False @@ -182,29 +185,34 @@ def icon(self, icontype_or_qfileinfo): class ColorModel(QFileSystemModel): + """FileSystemModel providing a color-code for different commit-status.""" def __init__(self, *args, **kwargs): super(ColorModel, self).__init__(*args, **kwargs) self.vcs_state = None self.color_array = [QColor("#ff0000"), QColor("#555555"), - QColor("#0000ff"), QColor("#ffffff")] + QColor("#0099ff"), QColor("#00ff00"), + QColor("#ffffff")] self.root_path = None def setVCSState(self, state, root_path): + """Set the vcs state dictionary.""" self.vcs_state = state self.dataChanged.emit(QModelIndex(), QModelIndex()) self.root_path = root_path def relativePath(self, index): + """Return the project-relative path of a file with a given index.""" return str(re.sub('^' + self.root_path + '/', '', self.filePath(index))) def data(self, index, role=Qt.DisplayRole): + """Set the colors of the elements in the Treeview""" if self.vcs_state and role == Qt.TextColorRole: filename = self.relativePath(index) if filename in self.vcs_state and self.vcs_state[filename] <= 3: return self.color_array[self.vcs_state[filename]] else: - return QColor("#ffffff") + return self.color_array[-1] return super(ColorModel, self).data(index, role) @@ -264,33 +272,33 @@ def set_name_filters(self, name_filters): """Set name filters""" self.name_filters = name_filters self.fsmodel.setNameFilters(name_filters) - + def set_show_all(self, state): """Toggle 'show all files' state""" if state: self.fsmodel.setNameFilters([]) else: self.fsmodel.setNameFilters(self.name_filters) - + def get_filename(self, index): """Return filename associated with *index*""" if index: return osp.normpath(to_text_string(self.fsmodel.filePath(index))) - + def get_index(self, filename): """Return index associated with filename""" return self.fsmodel.index(filename) - + def get_selected_filenames(self): """Return selected filenames""" if self.selectionMode() == self.ExtendedSelection: if self.selectionModel() is None: return [] - return [self.get_filename(idx) for idx in + return [self.get_filename(idx) for idx in self.selectionModel().selectedRows()] else: return [self.get_filename(self.currentIndex())] - + def get_dirname(self, index): """Return dirname associated with *index*""" fname = self.get_filename(index) @@ -299,7 +307,7 @@ def get_dirname(self, index): return fname else: return osp.dirname(fname) - + #---- Tree view widget def setup(self, name_filters=['*.py', '*.pyw'], show_all=False): """Setup tree widget""" @@ -307,7 +315,7 @@ def setup(self, name_filters=['*.py', '*.pyw'], show_all=False): self.set_name_filters(name_filters) self.show_all = show_all - + # Setup context menu self.menu = QMenu(self) self.common_actions = self.setup_common_actions() @@ -316,7 +324,7 @@ def reset_icon_provider(self): """Reset file system model icon provider The purpose of this is to refresh files/directories icons""" self.fsmodel.setIconProvider(IconProvider(self)) - + #---- Context menu def setup_common_actions(self): """Setup context menu common actions""" @@ -329,7 +337,7 @@ def setup_common_actions(self): toggled=self.toggle_all) all_action.setChecked(self.show_all) self.toggle_all(self.show_all) - + return [filters_action, all_action] @Slot() @@ -350,30 +358,30 @@ def toggle_all(self, checked): self.parent_widget.sig_option_changed.emit('show_all', checked) self.show_all = checked self.set_show_all(checked) - + def create_file_new_actions(self, fnames): """Return actions for submenu 'New...'""" if not fnames: return [] - new_file_act = create_action(self, _("File..."), + new_file_act = create_action(self, _("File..."), icon=ima.icon('filenew'), triggered=lambda: self.new_file(fnames[-1])) new_module_act = create_action(self, _("Module..."), icon=ima.icon('spyder'), triggered=lambda: - self.new_module(fnames[-1])) + self.new_module(fnames[-1])) new_folder_act = create_action(self, _("Folder..."), icon=ima.icon('folder_new'), triggered=lambda: - self.new_folder(fnames[-1])) + self.new_folder(fnames[-1])) new_package_act = create_action(self, _("Package..."), icon=ima.icon('package_new'), triggered=lambda: - self.new_package(fnames[-1])) + self.new_package(fnames[-1])) return [new_file_act, new_folder_act, None, new_module_act, new_package_act] - + def create_file_import_actions(self, fnames): """Return actions for submenu 'Import...'""" return [] @@ -399,24 +407,24 @@ def create_file_manage_actions(self, fnames): rename_action = create_action(self, _("Rename..."), icon=ima.icon('rename'), triggered=self.rename) - open_external_action = create_action(self, _("Open With OS"), + open_external_action = create_action(self, _("Open With OS"), triggered=self.open_external) ipynb_convert_action = create_action(self, _("Convert to Python script"), icon=ima.icon('python'), triggered=self.convert_notebooks) - + actions = [] if only_modules: actions.append(run_action) if only_valid and only_files: actions.append(edit_action) - + if sys.platform == 'darwin': - text=_("Show in Finder") + text = _("Show in Finder") else: - text=_("Show in Folder") - external_fileexp_action = create_action(self, text, - triggered=self.show_in_external_file_explorer) + text = _("Show in Folder") + external_fileexp_action = create_action(self, text, + triggered=self.show_in_external_file_explorer) actions += [delete_action, rename_action] basedir = fixpath(osp.dirname(fnames[0])) if all([fixpath(osp.dirname(_fn)) == basedir for _fn in fnames]): @@ -433,8 +441,8 @@ def create_file_manage_actions(self, fnames): # related actions only when a single file/folder is selected: dirname = fnames[0] if osp.isdir(fnames[0]) else osp.dirname(fnames[0]) if len(fnames) == 1 and vcs.is_vcs_repository(dirname): - commit_slot = lambda : self.vcs_command([dirname], 'commit') - browse_slot = lambda : self.vcs_command([dirname], 'browse') + commit_slot = lambda: self.vcs_command([dirname], 'commit') + browse_slot = lambda: self.vcs_command([dirname], 'browse') vcs_ci = create_action(self, _("Commit"), icon=ima.icon('vcs_commit'), triggered=commit_slot) @@ -458,7 +466,7 @@ def create_folder_manage_actions(self, fnames): self.open_interpreter(fnames)) actions.append(action) return actions - + def create_context_menu_actions(self): """Create context menu actions""" actions = [] @@ -493,14 +501,14 @@ def update_menu(self): """Update context menu""" self.menu.clear() add_actions(self.menu, self.create_context_menu_actions()) - + #---- Events def viewportEvent(self, event): """Reimplement Qt method""" # Prevent Qt from crashing or showing warnings like: - # "QSortFilterProxyModel: index from wrong model passed to - # mapFromSource", probably due to the fact that the file system model + # "QSortFilterProxyModel: index from wrong model passed to + # mapFromSource", probably due to the fact that the file system model # is being built. See Issue 1250. # # This workaround was inspired by the following KDE bug: @@ -508,9 +516,9 @@ def viewportEvent(self, event): # # Apparently, this is a bug from Qt itself. self.executeDelayedItemsLayout() - - return QTreeView.viewportEvent(self, event) - + + return QTreeView.viewportEvent(self, event) + def contextMenuEvent(self, event): """Override Qt method""" # Needed to handle not initialized menu. @@ -522,7 +530,7 @@ def contextMenuEvent(self, event): pass def keyPressEvent(self, event): - """Reimplement Qt method""" + """Reimplement Q t method""" if event.key() in (Qt.Key_Enter, Qt.Key_Return): self.clicked() elif event.key() == Qt.Key_F2: @@ -548,11 +556,11 @@ def clicked(self): self.directory_clicked(fname) else: self.open([fname]) - + def directory_clicked(self, dirname): """Directory was just clicked""" pass - + #---- Drag def dragEnterEvent(self, event): """Drag and Drop - Enter event""" @@ -565,7 +573,7 @@ def dragMoveEvent(self, event): event.accept() else: event.ignore() - + def startDrag(self, dropActions): """Reimplement Qt Method - handle drag event""" data = QMimeData() @@ -573,7 +581,7 @@ def startDrag(self, dropActions): drag = QDrag(self) drag.setMimeData(data) drag.exec_() - + #---- File/Directory actions @Slot() def open(self, fnames=None): @@ -585,7 +593,7 @@ def open(self, fnames=None): self.parent_widget.sig_open_file.emit(fname) else: self.open_outside_spyder([fname]) - + @Slot() def open_external(self, fnames=None): """Open files with default application""" @@ -593,7 +601,7 @@ def open_external(self, fnames=None): fnames = self.get_selected_filenames() for fname in fnames: self.open_outside_spyder([fname]) - + def open_outside_spyder(self, fnames): """Open file outside Spyder with the appropriate application If this does not work, opening unknown file in Spyder, as text file""" @@ -615,12 +623,12 @@ def run(self, fnames=None): fnames = self.get_selected_filenames() for fname in fnames: self.sig_run.emit(fname) - + def remove_tree(self, dirname): """Remove whole directory tree Reimplemented in project explorer widget""" shutil.rmtree(dirname, onerror=misc.onerror) - + def delete_file(self, fname, multiple, yes_to_all): """Delete file""" if multiple: @@ -630,9 +638,9 @@ def delete_file(self, fname, multiple, yes_to_all): buttons = QMessageBox.Yes|QMessageBox.No if yes_to_all is None: answer = QMessageBox.warning(self, _("Delete"), - _("Do you really want " - "to delete %s?" - ) % osp.basename(fname), buttons) + _("Do you really want " + "to delete %s?" + ) % osp.basename(fname), buttons) if answer == QMessageBox.No: return yes_to_all elif answer == QMessageBox.Cancel: @@ -650,9 +658,10 @@ def delete_file(self, fname, multiple, yes_to_all): except EnvironmentError as error: action_str = _('delete') QMessageBox.critical(self, _("Project Explorer"), - _("Unable to %s %s" - "

Error message:
%s" - ) % (action_str, fname, to_text_string(error))) + _("Unable to %s %s" + "

Error message:
%s" + ) % (action_str, fname, + to_text_string(error))) return False @Slot() @@ -663,27 +672,27 @@ def delete(self, fnames=None): multiple = len(fnames) > 1 yes_to_all = None for fname in fnames: - spyproject_path = osp.join(fname,'.spyproject') + spyproject_path = osp.join(fname, '.spyproject') if osp.isdir(fname) and osp.exists(spyproject_path): QMessageBox.information(self, _('File Explorer'), _("The current directory contains a " - "project.

" - "If you want to delete" - " the project, please go to " - "Projects » Delete " - "Project")) - else: + "project.

" + "If you want to delete" + " the project, please go to " + "Projects » Delete " + "Project")) + else: yes_to_all = self.delete_file(fname, multiple, yes_to_all) if yes_to_all is not None and not yes_to_all: # Canceled break - + def convert_notebook(self, fname): """Convert an IPython notebook to a Python script in editor""" - try: + try: script = nbexporter().from_filename(fname)[0] except Exception as e: - QMessageBox.critical(self, _('Conversion error'), + QMessageBox.critical(self, _('Conversion error'), _("It was not possible to convert this " "notebook. The error is:\n\n") + \ to_text_string(e)) @@ -702,8 +711,8 @@ def convert_notebooks(self): def rename_file(self, fname): """Rename file""" path, valid = QInputDialog.getText(self, _('Rename'), - _('New name:'), QLineEdit.Normal, - osp.basename(fname)) + _('New name:'), QLineEdit.Normal, + osp.basename(fname)) if valid: path = osp.join(osp.dirname(fname), to_text_string(path)) if path == fname: @@ -774,7 +783,7 @@ def move(self, fnames=None, directory=None): _("Unable to move %s" "

Error message:
%s" ) % (basename, to_text_string(error))) - + def create_new_folder(self, current_path, title, subtitle, is_package): """Create new folder""" if current_path is None: @@ -813,13 +822,13 @@ def new_folder(self, basedir): title = _('New folder') subtitle = _('Folder name:') self.create_new_folder(basedir, title, subtitle, is_package=False) - + def new_package(self, basedir): """New package""" title = _('New package') subtitle = _('Package name:') self.create_new_folder(basedir, title, subtitle, is_package=True) - + def create_new_file(self, current_path, title, filters, create_func): """Create new file Returns True if successful""" @@ -854,7 +863,7 @@ def create_func(fname): fname = self.create_new_file(basedir, title, filters, create_func) if fname is not None: self.open([fname]) - + def new_module(self, basedir): """New module""" title = _("New module") @@ -867,7 +876,7 @@ def create_func(fname): def go_to_parent_directory(self): pass - + #----- VCS actions def vcs_command(self, fnames, action): """VCS action (commit, browse)""" @@ -887,30 +896,30 @@ def get_scrollbar_position(self): """Return scrollbar positions""" return (self.horizontalScrollBar().value(), self.verticalScrollBar().value()) - + def set_scrollbar_position(self, position): """Set scrollbar positions""" # Scrollbars will be restored after the expanded state self._scrollbar_positions = position if self._to_be_loaded is not None and len(self._to_be_loaded) == 0: self.restore_scrollbar_positions() - + def restore_scrollbar_positions(self): """Restore scrollbar positions once tree is loaded""" hor, ver = self._scrollbar_positions self.horizontalScrollBar().setValue(hor) self.verticalScrollBar().setValue(ver) - + def get_expanded_state(self): """Return expanded state""" self.save_expanded_state() return self.__expanded_state - + def set_expanded_state(self, state): """Set expanded state""" self.__expanded_state = state self.restore_expanded_state() - + def save_expanded_state(self): """Save all items expanded state""" model = self.model() @@ -938,7 +947,7 @@ def restore_directory_state(self, fname): self.setExpanded(self.get_index(path), True) if not self.__expanded_state: self.fsmodel.directoryLoaded.disconnect(self.restore_directory_state) - + def follow_directories_loaded(self, fname): """Follow directories loaded during startup""" if self._to_be_loaded is None: @@ -962,7 +971,7 @@ def restore_expanded_state(self): self.restore_directory_state) self.fsmodel.directoryLoaded.connect( self.follow_directories_loaded) - + def filter_directories(self): """Filter the directories to show""" index = self.get_index('.spyproject') @@ -976,7 +985,7 @@ def __init__(self, parent): self.root_path = None self.path_list = [] self.setDynamicSortFilter(True) - + def setup_filter(self, root_path, path_list): """Setup proxy model filter parameters""" self.root_path = osp.normpath(to_text_string(root_path)) @@ -986,7 +995,7 @@ def setup_filter(self, root_path, path_list): def sort(self, column, order=Qt.AscendingOrder): """Reimplement Qt method""" self.sourceModel().sort(column, order) - + def filterAcceptsRow(self, row, parent_index): """Reimplement Qt method""" if self.root_path is None: @@ -1018,25 +1027,25 @@ def __init__(self, parent=None): self.proxymodel = None self.setup_proxy_model() self.root_path = None - + #---- Model def setup_proxy_model(self): """Setup proxy model""" self.proxymodel = ProxyModel(self) self.proxymodel.setSourceModel(self.fsmodel) - + def install_model(self): """Install proxy model""" if self.root_path is not None: self.setModel(self.proxymodel) - + def set_root_path(self, root_path): """Set root path""" self.root_path = root_path self.install_model() index = self.fsmodel.setRootPath(root_path) self.setRootIndex(self.proxymodel.mapFromSource(index)) - + def get_index(self, filename): """Return index associated with filename""" index = self.fsmodel.index(filename) @@ -1068,7 +1077,7 @@ def setup_project_view(self): for i in [1, 2, 3]: self.hideColumn(i) self.setHeaderHidden(True) - # Disable the view of .spyproject. + # Disable the view of .spyproject. self.filter_directories() @@ -1080,10 +1089,10 @@ class ExplorerTreeWidget(DirView): set_previous_enabled = Signal(bool) set_next_enabled = Signal(bool) sig_open_dir = Signal(str) - + def __init__(self, parent=None, show_cd_only=None): DirView.__init__(self, parent) - + self.history = [] self.histindex = None @@ -1093,10 +1102,10 @@ def __init__(self, parent=None, show_cd_only=None): self.menu = None self.common_actions = None - + # Enable drag events self.setDragEnabled(True) - + #---- Context menu def setup_common_actions(self): """Setup context menu common actions""" @@ -1125,7 +1134,7 @@ def toggle_show_cd_only(self, checked): self.set_current_folder(self.__last_folder) elif self.__original_root_index is not None: self.setRootIndex(self.__original_root_index) - + #---- Refreshing widget def set_current_folder(self, folder): """Set current folder and return associated model index""" @@ -1136,7 +1145,7 @@ def set_current_folder(self, folder): self.__original_root_index = self.rootIndex() self.setRootIndex(index) return index - + def get_current_folder(self): return self.__last_folder @@ -1153,14 +1162,14 @@ def refresh(self, new_path=None, force_current=False): self.histindex is not None and self.histindex > 0) self.set_next_enabled.emit(self.histindex is not None and \ self.histindex < len(self.history)-1) - # Disable the view of .spyproject. + # Disable the view of .spyproject. self.filter_directories() - + #---- Events def directory_clicked(self, dirname): """Directory was just clicked""" self.chdir(directory=dirname) - + #---- Files/Directories Actions @Slot() def go_to_parent_directory(self): @@ -1178,7 +1187,7 @@ def go_to_next_directory(self): """Return to next directory""" self.histindex += 1 self.chdir(browsing_history=True) - + def update_history(self, directory): """Update browse history""" try: @@ -1188,7 +1197,7 @@ def update_history(self, directory): except Exception: user_directory = get_home_dir() self.chdir(directory=user_directory, browsing_history=True) - + def chdir(self, directory=None, browsing_history=False): """Set directory as working directory""" if directory is not None: @@ -1258,8 +1267,8 @@ def __init__(self, parent=None, name_filters=['*.py', '*.pyw'], icontext_action = create_action(self, _("Show icons and text"), toggled=self.toggle_icontext) previous_action = create_action(self, text=_("Previous"), - icon=ima.icon('ArrowBack'), - triggered=self.treewidget.go_to_previous_directory) + icon=ima.icon('ArrowBack'), + triggered=self.treewidget.go_to_previous_directory) next_action = create_action(self, text=_("Next"), icon=ima.icon('ArrowForward'), triggered=self.treewidget.go_to_next_directory) @@ -1330,7 +1339,7 @@ def __init__(self): self.setLayout(vlayout) self.explorer = ExplorerWidget(self, show_cd_only=None) vlayout.addWidget(self.explorer) - + hlayout1 = QHBoxLayout() vlayout.addLayout(hlayout1) label = QLabel("Open file:") @@ -1339,7 +1348,7 @@ def __init__(self): self.label1 = QLabel() hlayout1.addWidget(self.label1) self.explorer.sig_open_file.connect(self.label1.setText) - + hlayout2 = QHBoxLayout() vlayout.addLayout(hlayout2) label = QLabel("Open dir:") @@ -1348,7 +1357,7 @@ def __init__(self): self.label2 = QLabel() hlayout2.addWidget(self.label2) self.explorer.open_dir.connect(self.label2.setText) - + hlayout3 = QHBoxLayout() vlayout.addLayout(hlayout3) label = QLabel("Option changed:") diff --git a/spyder/utils/vcs.py b/spyder/utils/vcs.py index ddc47f5400a..31d7da4941a 100644 --- a/spyder/utils/vcs.py +++ b/spyder/utils/vcs.py @@ -29,7 +29,7 @@ ('hgtk', ['commit'])), browse=(('thg', ['log']), ('hgtk', ['log'])), - cstate=(('thg', ['status'])) + cstate=(('hg', 'status -A'), ) ) }, { 'name': 'Git', @@ -37,7 +37,7 @@ 'actions': dict( commit=(('git', ['gui' if os.name == 'nt' else 'cola']), ), browse=(('gitk', []), ), - cstate=(('git status --ignored --porcelain', []), ), + cstate=(('git', 'status --ignored --porcelain'), ) ) }] @@ -106,19 +106,24 @@ def get_vcs_status(path): # Status list (in Order): untracked, ignored, modified, added if info['name'] == 'Git': stat = ["??", "!!", "M", "A"] + o = 3 # position at which the filename starts elif info['name'] == 'Mercurial': stat = ["?", "I", "M", "A"] + o = 2 - tool = info['actions']['cstate'] - if tool is not None: - if programs.find_program('git'): + for tool, args in info['actions']['cstate']: + if programs.find_program(tool): if not running_under_pytest(): - proc = programs.run_shell_command(tool[0][0], cwd=path) - out, err = proc.communicate() + proc = programs.run_shell_command(tool + " " + args, cwd=path) + out, _ = proc.communicate() if proc.returncode >= 0: vcsst = {} for fString in (x for x in out[:-1].split("\n") if x): - vcsst[fString[3:]] = stat.index(fString[:2].strip()) + try: + index = stat.index(fString[:o-1].strip()) + except ValueError: + continue + vcsst[fString[o:]] = index return vcsst else: return None