# -*- coding: utf-8 -*- # # Copyright © Spyder Project Contributors # Licensed under the terms of the MIT License # (see spyder/__init__.py for details) """ Language Server Protocol configuration tabs. """ # Standard library imports import re # Third party imports from qtpy.QtCore import Qt, Slot from qtpy.QtWidgets import (QGridLayout, QLabel, QMessageBox, QVBoxLayout, QWidget) # Local imports from spyder.api.preferences import SpyderPreferencesTab from spyder.config.base import _ class DocstringConfigTab(SpyderPreferencesTab): """Docstring style configuration tab.""" TITLE = _('Docstring style') def __init__(self, parent): super().__init__(parent) numpy_url = ( "Numpy") pep257_url = ( "PEP 257") docstring_style_codes = _( "page") docstring_style_label = QLabel( _("Here you can decide if you want to perform style analysis on " "your docstrings according to the {} or {} conventions. You can " "also decide if you want to show or ignore specific errors, " "according to the codes found on this {}.").format( numpy_url, pep257_url, docstring_style_codes)) docstring_style_label.setOpenExternalLinks(True) docstring_style_label.setWordWrap(True) # Docstring style checkbox self.docstring_style_check = self.create_checkbox( _("Enable docstring style linting"), 'pydocstyle') # Docstring style options docstring_style_convention = self.create_combobox( _("Choose the convention used to lint docstrings: "), (("Numpy", 'numpy'), ("PEP 257", 'pep257'), ("Custom", 'custom')), 'pydocstyle/convention') self.docstring_style_select = self.create_lineedit( _("Show the following errors:"), 'pydocstyle/select', alignment=Qt.Horizontal, word_wrap=False, placeholder=_("Example codes: D413, D414")) self.docstring_style_ignore = self.create_lineedit( _("Ignore the following errors:"), 'pydocstyle/ignore', alignment=Qt.Horizontal, word_wrap=False, placeholder=_("Example codes: D107, D402")) self.docstring_style_match = self.create_lineedit( _("Only check filenames matching these patterns:"), 'pydocstyle/match', alignment=Qt.Horizontal, word_wrap=False, placeholder=_("Skip test files: (?!test_).*\\.py")) self.docstring_style_match_dir = self.create_lineedit( _("Only check in directories matching these patterns:"), 'pydocstyle/match_dir', alignment=Qt.Horizontal, word_wrap=False, placeholder=_("Skip dot directories: [^\\.].*")) # Custom option handling docstring_style_convention.combobox.currentTextChanged.connect( self.setup_docstring_style_convention) current_convention = docstring_style_convention.combobox.currentText() self.setup_docstring_style_convention(current_convention) # Docstring style layout docstring_style_g_layout = QGridLayout() docstring_style_g_layout.addWidget( docstring_style_convention.label, 1, 0) docstring_style_g_layout.addWidget( docstring_style_convention.combobox, 1, 1) docstring_style_g_layout.addWidget( self.docstring_style_select.label, 2, 0) docstring_style_g_layout.addWidget( self.docstring_style_select.textbox, 2, 1) docstring_style_g_layout.addWidget( self.docstring_style_ignore.label, 3, 0) docstring_style_g_layout.addWidget( self.docstring_style_ignore.textbox, 3, 1) docstring_style_g_layout.addWidget( self.docstring_style_match.label, 4, 0) docstring_style_g_layout.addWidget( self.docstring_style_match.textbox, 4, 1) docstring_style_g_layout.addWidget( self.docstring_style_match_dir.label, 5, 0) docstring_style_g_layout.addWidget( self.docstring_style_match_dir.textbox, 5, 1) # Set Docstring style options enabled/disabled docstring_style_g_widget = QWidget() docstring_style_g_widget.setLayout(docstring_style_g_layout) docstring_style_g_widget.setEnabled(self.get_option('pydocstyle')) self.docstring_style_check.toggled.connect( docstring_style_g_widget.setEnabled) # Docstring style layout docstring_style_layout = QVBoxLayout() docstring_style_layout.addWidget(docstring_style_label) docstring_style_layout.addWidget(self.docstring_style_check) docstring_style_layout.addWidget(docstring_style_g_widget) self.setLayout(docstring_style_layout) @Slot(str) def setup_docstring_style_convention(self, text): """Handle convention changes.""" if text == 'Custom': self.docstring_style_select.label.setText( _("Show the following errors:")) self.docstring_style_ignore.label.setText( _("Ignore the following errors:")) else: self.docstring_style_select.label.setText( _("Show the following errors in addition " "to the specified convention:")) self.docstring_style_ignore.label.setText( _("Ignore the following errors in addition " "to the specified convention:")) def report_invalid_regex(self, files=True): """ Report that matching files/directories should be valid regular expressions. """ msg = _('Directory patterns listed for matching should be valid ' 'regular expressions') if files: msg = _('File patterns listed for matching should be valid ' 'regular expressions') QMessageBox.critical(self, _("Error"), msg) def is_valid(self): # Check regex of docstring style options try: docstring_style_match = ( self.docstring_style_match.textbox.text()) re.compile(docstring_style_match) except re.error: self.report_invalid_regex() return False try: docstring_style_match_dir = ( self.docstring_style_match_dir.textbox.text()) re.compile(docstring_style_match_dir) except re.error: self.report_invalid_regex(files=False) return False return True