def setup_page(self): # Connections group connections_group = QGroupBox(_("Automatic connections")) connections_label = QLabel(_("This pane can automatically " "show an object's help information after " "a left parenthesis is written next to it. " "Below you can decide to which plugin " "you want to connect it to turn on this " "feature.")) connections_label.setWordWrap(True) editor_box = self.create_checkbox(_("Editor"), 'connect/editor') rope_installed = programs.is_module_installed('rope') jedi_installed = programs.is_module_installed('jedi', '>=0.8.1') editor_box.setEnabled(rope_installed or jedi_installed) if not rope_installed and not jedi_installed: editor_tip = _("This feature requires the Rope or Jedi libraries.\n" "It seems you don't have either installed.") editor_box.setToolTip(editor_tip) ipython_box = self.create_checkbox(_("IPython Console"), 'connect/ipython_console') connections_layout = QVBoxLayout() connections_layout.addWidget(connections_label) connections_layout.addWidget(editor_box) connections_layout.addWidget(ipython_box) connections_group.setLayout(connections_layout) # Features group features_group = QGroupBox(_("Additional features")) math_box = self.create_checkbox(_("Render mathematical equations"), 'math') req_sphinx = programs.is_module_installed('sphinx', '>=1.1') math_box.setEnabled(req_sphinx) if not req_sphinx: sphinx_ver = programs.get_module_version('sphinx') sphinx_tip = _("This feature requires Sphinx 1.1 or superior.") sphinx_tip += "\n" + _("Sphinx %s is currently installed.") % sphinx_ver math_box.setToolTip(sphinx_tip) features_layout = QVBoxLayout() features_layout.addWidget(math_box) features_group.setLayout(features_layout) # Source code group sourcecode_group = QGroupBox(_("Source code")) wrap_mode_box = self.create_checkbox(_("Wrap lines"), 'wrap') sourcecode_layout = QVBoxLayout() sourcecode_layout.addWidget(wrap_mode_box) sourcecode_group.setLayout(sourcecode_layout) # Final layout vlayout = QVBoxLayout() vlayout.addWidget(connections_group) vlayout.addWidget(features_group) vlayout.addWidget(sourcecode_group) vlayout.addStretch(1) self.setLayout(vlayout)
def is_qtconsole_installed(): pyzmq_installed = programs.is_module_installed('zmq', version=ZMQ_REQVER) pygments_installed = programs.is_module_installed('pygments') qtconsole_installed = programs.is_module_installed('qtconsole', version=QTCONSOLE_REQVER) if pyzmq_installed and pygments_installed and qtconsole_installed: return True else: return False
def load_plugin(self): """Load the Jedi introspection plugin""" if not programs.is_module_installed('jedi', JEDI_REQVER): raise ImportError('Requires Jedi %s' % JEDI_REQVER) jedi.settings.case_insensitive_completion = False for lib in ['numpy', 'matplotlib']: jedi.preload_module(lib)
def import_test(self): """Raise ImportError if feature is not supported.""" from spyder.utils import programs if not programs.is_module_installed('psutil', '>=0.2.0'): # The `interval` argument in `psutil.cpu_percent` function # was introduced in v0.2.0 raise ImportError
def long_banner(self): """Banner for IPython widgets with pylab message""" # Default banner from IPython.core.usage import quick_guide banner_parts = [ "Python %s\n" % self.interpreter_versions["python_version"], 'Type "copyright", "credits" or "license" for more information.\n\n', "IPython %s -- An enhanced Interactive Python.\n" % self.interpreter_versions["ipython_version"], quick_guide, ] banner = "".join(banner_parts) # Pylab additions pylab_o = self.additional_options["pylab"] autoload_pylab_o = self.additional_options["autoload_pylab"] mpl_installed = programs.is_module_installed("matplotlib") if mpl_installed and (pylab_o and autoload_pylab_o): pylab_message = "\nPopulating the interactive namespace from " "numpy and matplotlib" banner = banner + pylab_message # Sympy additions sympy_o = self.additional_options["sympy"] if sympy_o: lines = """ These commands were executed: >>> from __future__ import division >>> from sympy import * >>> x, y, z, t = symbols('x y z t') >>> k, m, n = symbols('k m n', integer=True) >>> f, g, h = symbols('f g h', cls=Function) """ banner = banner + lines return banner
def set_umr_namelist(self): """Set UMR excluded modules name list""" arguments, valid = QInputDialog.getText(self, _('UMR'), _("Set the list of excluded modules as " "this: <i>numpy, scipy</i>"), QLineEdit.Normal, ", ".join(self.get_option('umr/namelist'))) if valid: arguments = to_text_string(arguments) if arguments: namelist = arguments.replace(' ', '').split(',') fixed_namelist = [module_name for module_name in namelist if programs.is_module_installed(module_name)] invalid = ", ".join(set(namelist)-set(fixed_namelist)) if invalid: QMessageBox.warning(self, _('UMR'), _("The following modules are not " "installed on your machine:\n%s" ) % invalid, QMessageBox.Ok) QMessageBox.information(self, _('UMR'), _("Please note that these changes will " "be applied only to new Python/IPython " "consoles"), QMessageBox.Ok) else: fixed_namelist = [] self.set_option('umr/namelist', fixed_namelist)
def setup_page(self): ar_group = QGroupBox(_("Autorefresh")) ar_box = self.create_checkbox(_("Enable autorefresh"), 'autorefresh') ar_spin = self.create_spinbox(_("Refresh interval: "), _(" ms"), 'autorefresh/timeout', min_=100, max_=1000000, step=100) filter_group = QGroupBox(_("Filter")) filter_data = [ ('exclude_private', _("Exclude private references")), ('exclude_capitalized', _("Exclude capitalized references")), ('exclude_uppercase', _("Exclude all-uppercase references")), ('exclude_unsupported', _("Exclude unsupported data types")), ] filter_boxes = [self.create_checkbox(text, option) for option, text in filter_data] display_group = QGroupBox(_("Display")) display_data = [('truncate', _("Truncate values"), '')] if programs.is_module_installed('numpy'): display_data.append(('minmax', _("Show arrays min/max"), '')) display_data.append( ('remote_editing', _("Edit data in the remote process"), _("Editors are opened in the remote process for NumPy " "arrays, PIL images, lists, tuples and dictionaries.\n" "This avoids transfering large amount of data between " "the remote process and Spyder (through the socket).")) ) display_boxes = [self.create_checkbox(text, option, tip=tip) for option, text, tip in display_data] ar_layout = QVBoxLayout() ar_layout.addWidget(ar_box) ar_layout.addWidget(ar_spin) ar_group.setLayout(ar_layout) filter_layout = QVBoxLayout() for box in filter_boxes: filter_layout.addWidget(box) filter_group.setLayout(filter_layout) display_layout = QVBoxLayout() for box in display_boxes: display_layout.addWidget(box) display_group.setLayout(display_layout) vlayout = QVBoxLayout() vlayout.addWidget(ar_group) vlayout.addWidget(filter_group) vlayout.addWidget(display_group) vlayout.addStretch(1) self.setLayout(vlayout)
def set_umr_namelist(self): """Set UMR excluded modules name list""" arguments, valid = QInputDialog.getText(self, _('UMR'), _("Set the list of excluded modules as " "this: <i>numpy, scipy</i>"), QLineEdit.Normal, ", ".join(self.get_option('umr/namelist'))) if valid: arguments = to_text_string(arguments) if arguments: namelist = arguments.replace(' ', '').split(',') fixed_namelist = [] non_ascii_namelist = [] for module_name in namelist: if PY2: if all(ord(c) < 128 for c in module_name): if programs.is_module_installed(module_name): fixed_namelist.append(module_name) else: QMessageBox.warning(self, _('Warning'), _("You are working with Python 2, this means that " "you can not import a module that contains non-" "ascii characters."), QMessageBox.Ok) non_ascii_namelist.append(module_name) elif programs.is_module_installed(module_name): fixed_namelist.append(module_name) invalid = ", ".join(set(namelist)-set(fixed_namelist)- set(non_ascii_namelist)) if invalid: QMessageBox.warning(self, _('UMR'), _("The following modules are not " "installed on your machine:\n%s" ) % invalid, QMessageBox.Ok) QMessageBox.information(self, _('UMR'), _("Please note that these changes will " "be applied only to new Python/IPython " "consoles"), QMessageBox.Ok) else: fixed_namelist = [] self.set_option('umr/namelist', fixed_namelist)
def register_plugin(self): """Register plugin in Spyder's main window""" self.pylint.treewidget.sig_edit_goto.connect(self.main.editor.load) self.pylint.redirect_stdio.connect( self.main.redirect_internalshell_stdio) self.main.add_dockwidget(self) pylint_act = create_action(self, _("Run static code analysis"), triggered=self.run_pylint) pylint_act.setEnabled(is_module_installed('pylint')) self.register_shortcut(pylint_act, context="Pylint", name="Run analysis") self.main.source_menu_actions += [MENU_SEPARATOR, pylint_act] self.main.editor.pythonfile_dependent_actions += [pylint_act]
def load_plugin(self): """Load the Rope introspection plugin""" if not programs.is_module_installed('rope', ROPE_REQVER): raise ImportError('Requires Rope %s' % ROPE_REQVER) self.project = None self.create_rope_project(root_path=get_conf_path()) submods = get_preferred_submodules() actual = [] for submod in submods: try: imp.find_module(submod) actual.append(submod) except ImportError: pass if self.project is not None: self.project.prefs.set('extension_modules', actual)
def find_return_types(module_context, func): """ Determines a set of potential return types for `func` using docstring hints :type evaluator: jedi.evaluate.Evaluator :type param: jedi.parser.tree.Param :rtype: list >>> from jedi.evaluate.docstrings import * # NOQA >>> from jedi.evaluate.docstrings import _search_param_in_docstr >>> from jedi.evaluate.docstrings import _evaluate_for_statement_string >>> from jedi.evaluate.docstrings import _search_return_in_gooogledocstr >>> from jedi.evaluate.docstrings import _search_return_in_numpydocstr >>> from jedi._compatibility import builtins >>> source = open(jedi.evaluate.docstrings.__file__.replace('.pyc', '.py'), 'r').read() >>> script = jedi.Script(source) >>> evaluator = script._evaluator >>> func = script._get_module().names_dict['find_return_types'][0].parent >>> types = find_return_types(evaluator, func) >>> print('types = %r' % (types,)) >>> assert len(types) == 1 >>> assert types[0].base.obj is builtins.list """ def search_return_in_docstr(docstr): # Check for Sphinx/Epydoc return hint for p in DOCSTRING_RETURN_PATTERNS: match = p.search(docstr) if match: return [_strip_rst_role(match.group(1))] found = [] if not found: # Check for numpy style return hint found = _search_return_in_numpydocstr(docstr) return found try: docstr = u(func.raw_doc) except AttributeError: docstr = u(func.doc) types = [] for type_str in search_return_in_docstr(docstr): if is_module_installed('jedi', '>=0.10.0;<0.11'): type_ = _evaluate_for_statement_string(module_context, type_str) else: module = func.get_parent_until() type_ = _evaluate_for_statement_string(module_context, type_str, module) types.extend(type_) return types
def create_module_bookmark_actions(parent, bookmarks): """ Create bookmark actions depending on module installation: bookmarks = ((module_name, url, title), ...) """ actions = [] for key, url, title in bookmarks: # Create actions for scientific distros only if Spyder is installed # under them create_act = True if key == 'xy' or key == 'winpython': if not programs.is_module_installed(key): create_act = False if create_act: act = create_bookmark_action(parent, url, title) actions.append(act) return actions
def create_module_bookmark_actions(parent, bookmarks): """ Create bookmark actions depending on module installation: bookmarks = ((module_name, url, title), ...) """ actions = [] for key, url, title in bookmarks: # Create actions for scientific distros only if Spyder is installed # under them create_act = True if key == 'winpython': if not programs.is_module_installed(key): create_act = False if create_act: act = create_bookmark_action(parent, url, title) actions.append(act) return actions
def register(self): widget = self.get_widget() editor = self.get_plugin(Plugins.Editor) mainmenu = self.get_plugin(Plugins.MainMenu) preferences = self.get_plugin(Plugins.Preferences) preferences.register_plugin_preferences(self) # Expose widget signals at the plugin level widget.sig_edit_goto_requested.connect(self.sig_edit_goto_requested) widget.sig_redirect_stdio_requested.connect( self.sig_redirect_stdio_requested) widget.sig_start_analysis_requested.connect( lambda: self.start_code_analysis()) # Connect to Editor widget.sig_edit_goto_requested.connect(editor.load) editor.sig_editor_focus_changed.connect(self._set_filename) # Connect to projects projects = self.get_plugin(Plugins.Projects) if projects: projects.sig_project_loaded.connect( lambda value: widget.set_conf("project_dir", value)) projects.sig_project_closed.connect( lambda value: widget.set_conf("project_dir", None)) # Add action to application menus pylint_act = self.create_action( PylintActions.AnalyzeCurrentFile, text=_("Run code analysis"), tip=_("Run code analysis"), icon=self.create_icon("pylint"), triggered=lambda: self.start_code_analysis(), context=Qt.ApplicationShortcut, register_shortcut=True ) pylint_act.setEnabled(is_module_installed("pylint")) if mainmenu: source_menu = mainmenu.get_application_menu( ApplicationMenus.Source) mainmenu.add_item_to_application_menu(pylint_act, menu=source_menu) # TODO: use new API when editor has migrated self.main.editor.pythonfile_dependent_actions += [pylint_act]
def long_banner(self): """Banner for IPython widgets with pylab message""" # Default banner try: from IPython.core.usage import quick_guide except Exception: quick_guide = '' banner_parts = [ 'Python %s\n' % self.interpreter_versions['python_version'], 'Type "copyright", "credits" or "license" for more information.\n\n', 'IPython %s -- An enhanced Interactive Python.\n' % \ self.interpreter_versions['ipython_version'], quick_guide ] banner = ''.join(banner_parts) # Pylab additions pylab_o = self.additional_options['pylab'] autoload_pylab_o = self.additional_options['autoload_pylab'] mpl_installed = programs.is_module_installed('matplotlib') if mpl_installed and (pylab_o and autoload_pylab_o): pylab_message = ("\nPopulating the interactive namespace from " "numpy and matplotlib\n") banner = banner + pylab_message # Sympy additions sympy_o = self.additional_options['sympy'] if sympy_o: lines = """ These commands were executed: >>> from __future__ import division >>> from sympy import * >>> x, y, z, t = symbols('x y z t') >>> k, m, n = symbols('k m n', integer=True) >>> f, g, h = symbols('f g h', cls=Function) """ banner = banner + lines if (pylab_o and sympy_o): lines = """ Warning: pylab (numpy and matplotlib) and symbolic math (sympy) are both enabled at the same time. Some pylab functions are going to be overrided by the sympy module (e.g. plot) """ banner = banner + lines return banner
def setup_option_actions(self, exclude_private, exclude_uppercase, exclude_capitalized, exclude_unsupported): """Setup the actions to show in the cog menu.""" self.setup_in_progress = True self.exclude_private_action = create_action(self, _("Exclude private references"), tip=_("Exclude references which name starts" " with an underscore"), toggled=lambda state: self.sig_option_changed.emit('exclude_private', state)) self.exclude_private_action.setChecked(exclude_private) self.exclude_uppercase_action = create_action(self, _("Exclude all-uppercase references"), tip=_("Exclude references which name is uppercase"), toggled=lambda state: self.sig_option_changed.emit('exclude_uppercase', state)) self.exclude_uppercase_action.setChecked(exclude_uppercase) self.exclude_capitalized_action = create_action(self, _("Exclude capitalized references"), tip=_("Exclude references which name starts with an " "uppercase character"), toggled=lambda state: self.sig_option_changed.emit('exclude_capitalized', state)) self.exclude_capitalized_action.setChecked(exclude_capitalized) self.exclude_unsupported_action = create_action(self, _("Exclude unsupported data types"), tip=_("Exclude references to unsupported data types" " (i.e. which won't be handled/saved correctly)"), toggled=lambda state: self.sig_option_changed.emit('exclude_unsupported', state)) self.exclude_unsupported_action.setChecked(exclude_unsupported) self.actions = [ self.exclude_private_action, self.exclude_uppercase_action, self.exclude_capitalized_action, self.exclude_unsupported_action] if is_module_installed('numpy'): self.actions.extend([MENU_SEPARATOR, self.editor.minmax_action]) self.setup_in_progress = False
def update_actions(self): action = self.get_action(VariableExplorerWidgetActions.ToggleMinMax) action.setEnabled(is_module_installed('numpy')) nsb = self.current_widget() for __, action in self.get_actions().items(): if action: # IMPORTANT: Since we are defining the main actions in here # and the context is WidgetWithChildrenShortcut we need to # assign the same actions to the children widgets in order # for shortcuts to work if nsb: save_data_action = self.get_action( VariableExplorerWidgetActions.SaveData) save_data_action.setEnabled(nsb.filename is not None) nsb_actions = nsb.actions() if action not in nsb_actions: nsb.addAction(action)
def setup_page(self): filter_group = QGroupBox(_("Filter")) filter_data = [ ('exclude_private', _("Exclude private references")), ('exclude_capitalized', _("Exclude capitalized references")), ('exclude_uppercase', _("Exclude all-uppercase references")), ('exclude_unsupported', _("Exclude unsupported data types")), ] filter_boxes = [ self.create_checkbox(text, option) for option, text in filter_data ] display_group = QGroupBox(_("Display")) display_data = [] if programs.is_module_installed('numpy'): display_data.append(('minmax', _("Show arrays min/max"), '')) display_data.append( ('remote_editing', _("Edit data in the remote process"), _("Editors are opened in the remote process for NumPy " "arrays, PIL images, lists, tuples and dictionaries.\n" "This avoids transfering large amount of data between " "the remote process and Spyder (through the socket)."))) display_boxes = [ self.create_checkbox(text, option, tip=tip) for option, text, tip in display_data ] filter_layout = QVBoxLayout() for box in filter_boxes: filter_layout.addWidget(box) filter_group.setLayout(filter_layout) display_layout = QVBoxLayout() for box in display_boxes: display_layout.addWidget(box) display_group.setLayout(display_layout) vlayout = QVBoxLayout() vlayout.addWidget(filter_group) vlayout.addWidget(display_group) vlayout.addStretch(1) self.setLayout(vlayout)
def on_initialize(self): widget = self.get_widget() # Expose widget signals at the plugin level widget.sig_edit_goto_requested.connect(self.sig_edit_goto_requested) widget.sig_redirect_stdio_requested.connect( self.sig_redirect_stdio_requested) widget.sig_start_analysis_requested.connect( lambda: self.start_code_analysis()) # Add action to application menus pylint_act = self.create_action( PylintActions.AnalyzeCurrentFile, text=_("Run code analysis"), tip=_("Run code analysis"), icon=self.create_icon("pylint"), triggered=lambda: self.start_code_analysis(), context=Qt.ApplicationShortcut, register_shortcut=True) pylint_act.setEnabled(is_module_installed("pylint"))
def _shape_text(self, text, colsep=u"\t", rowsep=u"\n", transpose=False, skiprows=0, comments='#'): """Decode the shape of the given text""" assert colsep != rowsep out = [] text_rows = text.split(rowsep)[skiprows:] for row in text_rows: stripped = to_text_string(row).strip() if len(stripped) == 0 or stripped.startswith(comments): continue line = to_text_string(row).split(colsep) line = [try_to_parse(to_text_string(x)) for x in line] out.append(line) # Replace missing elements with np.nan's or None's if programs.is_module_installed('numpy'): from numpy import nan out = list(zip_longest(*out, fillvalue=nan)) else: out = list(zip_longest(*out, fillvalue=None)) # Tranpose the last result to get the expected one out = [[r[col] for r in out] for col in range(len(out[0]))] if transpose: return [[r[col] for r in out] for col in range(len(out[0]))] return out
def is_pyflakes_installed(): """Return True if pyflakes required version is installed""" return programs.is_module_installed('pyflakes', PYFLAKES_REQVER)
def test_is_module_installed(): """Test if a module with the proper version is installed""" assert is_module_installed('qtconsole', '>=4.0') assert not is_module_installed('IPython', '>=1.0;<3.0') assert is_module_installed('jedi', '>=0.7.0')
def psutil_phymem_usage(): """ Return physical memory usage (float) Requires the cross-platform psutil (>=v0.3) library (https://github.com/giampaolo/psutil) """ import psutil # This is needed to avoid a deprecation warning error with # newer psutil versions try: percent = psutil.virtual_memory().percent except: percent = psutil.phymem_usage().percent return percent if programs.is_module_installed('psutil', '>=0.3.0'): # Function `psutil.phymem_usage` was introduced in psutil v0.3.0 memory_usage = psutil_phymem_usage elif os.name == 'nt': # Backup plan for Windows platforms memory_usage = windows_memory_usage else: raise ImportError("Feature requires psutil 0.3+ on non Windows platforms") if __name__ == '__main__': print("*"*80) # spyder: test-skip print(memory_usage.__doc__) # spyder: test-skip print(memory_usage()) # spyder: test-skip if os.name == 'nt': # windll can only be imported if os.name = 'nt' or 'ce'
print("*. Skipping GUI toolkit detection") os.environ['QT_API'] = args.gui # Checking versions (among other things, this has the effect of setting the # QT_API environment variable if this has not yet been done just above) from spyder import get_versions versions = get_versions(reporev=True) print("*. Imported Spyder %s - Revision %s, Branch: %s" % (versions['spyder'], versions['revision'], versions['branch'])) print(" [Python %s %dbits, Qt %s, %s %s on %s]" % (versions['python'], versions['bitness'], versions['qt'], versions['qt_api'], versions['qt_api_ver'], versions['system'])) # Check that we have the right qtpy version from spyder.utils import programs if not programs.is_module_installed('qtpy', '>=1.1.0'): print("") sys.exit("ERROR: Your qtpy version is outdated. Please install qtpy " "1.1.0 or higher to be able to work with Spyder!") # --- Executing Spyder if args.show_console: print("(Deprecated) --show console does nothing, now the default behavior " "is to show the console, use --hide-console if you want to hide it") if args.hide_console and os.name == 'nt': print("*. Hiding parent console (Windows only)") sys.argv.append("--hide-console") # Windows only: show parent console # Reset temporary config directory if starting in --safe-mode
def apply(): """Monkey patching rope See [1], [2], [3], [4] and [5] in module docstring.""" from spyder.utils.programs import is_module_installed if is_module_installed('rope', '<0.9.4'): import rope raise ImportError("rope %s can't be patched" % rope.VERSION) # [1] Patching project.Project for compatibility with py2exe/cx_Freeze # distributions from spyder.config.base import is_py2exe_or_cx_Freeze if is_py2exe_or_cx_Freeze(): from rope.base import project class PatchedProject(project.Project): def _default_config(self): # py2exe/cx_Freeze distribution from spyder.config.base import get_module_source_path fname = get_module_source_path('spyder', 'default_config.py') return open(fname, 'rb').read() project.Project = PatchedProject # Patching pycore.PyCore... from rope.base import pycore class PatchedPyCore(pycore.PyCore): # [2] ...so that forced builtin modules (i.e. modules that were # declared as 'extension_modules' in rope preferences) will be indeed # recognized as builtins by rope, as expected # # This patch is included in rope 0.9.4+ but applying it anyway is ok def get_module(self, name, folder=None): """Returns a `PyObject` if the module was found.""" # check if this is a builtin module pymod = self._builtin_module(name) if pymod is not None: return pymod module = self.find_module(name, folder) if module is None: raise pycore.ModuleNotFoundError( 'Module %s not found' % name) return self.resource_to_pyobject(module) # [3] ...to avoid considering folders without __init__.py as Python # packages def _find_module_in_folder(self, folder, modname): module = folder packages = modname.split('.') for pkg in packages[:-1]: if module.is_folder() and module.has_child(pkg): module = module.get_child(pkg) else: return None if module.is_folder(): if module.has_child(packages[-1]) and \ module.get_child(packages[-1]).is_folder() and \ module.get_child(packages[-1]).has_child('__init__.py'): return module.get_child(packages[-1]) elif module.has_child(packages[-1] + '.py') and \ not module.get_child(packages[-1] + '.py').is_folder(): return module.get_child(packages[-1] + '.py') pycore.PyCore = PatchedPyCore # [2] Patching BuiltinName for the go to definition feature to simply work # with forced builtins from rope.base import builtins, libutils, pyobjects import inspect import os.path as osp class PatchedBuiltinName(builtins.BuiltinName): def _pycore(self): p = self.pyobject while p.parent is not None: p = p.parent if isinstance(p, builtins.BuiltinModule) and p.pycore is not None: return p.pycore def get_definition_location(self): if not inspect.isbuiltin(self.pyobject): _lines, lineno = inspect.getsourcelines(self.pyobject.builtin) path = inspect.getfile(self.pyobject.builtin) if path.endswith('pyc') and osp.isfile(path[:-1]): path = path[:-1] pycore = self._pycore() if pycore and pycore.project: resource = libutils.path_to_resource(pycore.project, path) module = pyobjects.PyModule(pycore, None, resource) return (module, lineno) return (None, None) builtins.BuiltinName = PatchedBuiltinName # [4] Patching several PyDocExtractor methods: # 1. get_doc: # To force rope to return the docstring of any object which has one, even # if it's not an instance of AbstractFunction, AbstractClass, or # AbstractModule. # Also, to use utils.dochelpers.getdoc to get docs from forced builtins. # # 2. _get_class_docstring and _get_single_function_docstring: # To not let rope add a 2 spaces indentation to every docstring, which was # breaking our rich text mode. The only value that we are modifying is the # 'indents' keyword of those methods, from 2 to 0. # # 3. get_calltip # To easily get calltips of forced builtins from rope.contrib import codeassist from spyder.utils.dochelpers import getdoc from rope.base import exceptions class PatchedPyDocExtractor(codeassist.PyDocExtractor): def get_builtin_doc(self, pyobject): buitin = pyobject.builtin return getdoc(buitin) def get_doc(self, pyobject): if hasattr(pyobject, 'builtin'): doc = self.get_builtin_doc(pyobject) return doc elif isinstance(pyobject, builtins.BuiltinModule): docstring = pyobject.get_doc() if docstring is not None: docstring = self._trim_docstring(docstring) else: docstring = '' # TODO: Add a module_name key, so that the name could appear # on the OI text filed but not be used by sphinx to render # the page doc = {'name': '', 'argspec': '', 'note': '', 'docstring': docstring } return doc elif isinstance(pyobject, pyobjects.AbstractFunction): return self._get_function_docstring(pyobject) elif isinstance(pyobject, pyobjects.AbstractClass): return self._get_class_docstring(pyobject) elif isinstance(pyobject, pyobjects.AbstractModule): return self._trim_docstring(pyobject.get_doc()) elif pyobject.get_doc() is not None: # Spyder patch return self._trim_docstring(pyobject.get_doc()) return None def get_calltip(self, pyobject, ignore_unknown=False, remove_self=False): if hasattr(pyobject, 'builtin'): doc = self.get_builtin_doc(pyobject) return doc['name'] + doc['argspec'] try: if isinstance(pyobject, pyobjects.AbstractClass): pyobject = pyobject['__init__'].get_object() if not isinstance(pyobject, pyobjects.AbstractFunction): pyobject = pyobject['__call__'].get_object() except exceptions.AttributeNotFoundError: return None if ignore_unknown and not isinstance(pyobject, pyobjects.PyFunction): return if isinstance(pyobject, pyobjects.AbstractFunction): result = self._get_function_signature(pyobject, add_module=True) if remove_self and self._is_method(pyobject): return result.replace('(self)', '()').replace('(self, ', '(') return result def _get_class_docstring(self, pyclass): contents = self._trim_docstring(pyclass.get_doc(), indents=0) supers = [super.get_name() for super in pyclass.get_superclasses()] doc = 'class %s(%s):\n\n' % (pyclass.get_name(), ', '.join(supers)) + contents if '__init__' in pyclass: init = pyclass['__init__'].get_object() if isinstance(init, pyobjects.AbstractFunction): doc += '\n\n' + self._get_single_function_docstring(init) return doc def _get_single_function_docstring(self, pyfunction): docs = pyfunction.get_doc() docs = self._trim_docstring(docs, indents=0) return docs codeassist.PyDocExtractor = PatchedPyDocExtractor # [5] Get the right matplotlib docstrings for Help try: import matplotlib as mpl mpl.rcParams['docstring.hardcopy'] = True except: pass
def is_lineprofiler_installed(): """ Checks if the program and the library for line_profiler is installed. """ return (programs.is_module_installed('line_profiler') and programs.find_program('kernprof') is not None)
def setup_page(self): # Connections group connections_group = QGroupBox(_("Automatic connections")) connections_label = QLabel( _("This pane can automatically " "show an object's help information after " "a left parenthesis is written next to it. " "Below you can decide to which plugin " "you want to connect it to turn on this " "feature.")) connections_label.setWordWrap(True) editor_box = self.create_checkbox(_("Editor"), 'connect/editor') rope_installed = programs.is_module_installed('rope') jedi_installed = programs.is_module_installed('jedi', '>=0.8.1') editor_box.setEnabled(rope_installed or jedi_installed) if not rope_installed and not jedi_installed: editor_tip = _( "This feature requires the Rope or Jedi libraries.\n" "It seems you don't have either installed.") editor_box.setToolTip(editor_tip) ipython_box = self.create_checkbox(_("IPython Console"), 'connect/ipython_console') connections_layout = QVBoxLayout() connections_layout.addWidget(connections_label) connections_layout.addWidget(editor_box) connections_layout.addWidget(ipython_box) connections_group.setLayout(connections_layout) # Features group features_group = QGroupBox(_("Additional features")) math_box = self.create_checkbox(_("Render mathematical equations"), 'math') req_sphinx = programs.is_module_installed('sphinx', '>=1.1') math_box.setEnabled(req_sphinx) if not req_sphinx: sphinx_ver = programs.get_module_version('sphinx') sphinx_tip = _("This feature requires Sphinx 1.1 or superior.") sphinx_tip += "\n" + _( "Sphinx %s is currently installed.") % sphinx_ver math_box.setToolTip(sphinx_tip) features_layout = QVBoxLayout() features_layout.addWidget(math_box) features_group.setLayout(features_layout) # Source code group sourcecode_group = QGroupBox(_("Source code")) wrap_mode_box = self.create_checkbox(_("Wrap lines"), 'wrap') sourcecode_layout = QVBoxLayout() sourcecode_layout.addWidget(wrap_mode_box) sourcecode_group.setLayout(sourcecode_layout) # Final layout vlayout = QVBoxLayout() vlayout.addWidget(connections_group) vlayout.addWidget(features_group) vlayout.addWidget(sourcecode_group) vlayout.addStretch(1) self.setLayout(vlayout)
def __init__(self, parent, max_entries=100): QWidget.__init__(self, parent) self.setWindowTitle("Pylint") self.output = None self.error_output = None self.max_entries = max_entries self.rdata = [] if osp.isfile(self.DATAPATH): try: data = pickle.loads(open(self.DATAPATH, 'rb').read()) if data[0] == self.VERSION: self.rdata = data[1:] except (EOFError, ImportError): pass self.filecombo = PythonModulesComboBox(self) if self.rdata: self.remove_obsolete_items() self.filecombo.addItems(self.get_filenames()) self.start_button = create_toolbutton(self, icon=ima.icon('run'), text=_("Analyze"), tip=_("Run analysis"), triggered=self.start, text_beside_icon=True) self.stop_button = create_toolbutton(self, icon=ima.icon('stop'), text=_("Stop"), tip=_("Stop current analysis"), text_beside_icon=True) self.filecombo.valid.connect(self.start_button.setEnabled) self.filecombo.valid.connect(self.show_data) browse_button = create_toolbutton(self, icon=ima.icon('fileopen'), tip=_('Select Python file'), triggered=self.select_file) self.ratelabel = QLabel() self.datelabel = QLabel() self.log_button = create_toolbutton(self, icon=ima.icon('log'), text=_("Output"), text_beside_icon=True, tip=_("Complete output"), triggered=self.show_log) self.treewidget = ResultsTree(self) hlayout1 = QHBoxLayout() hlayout1.addWidget(self.filecombo) hlayout1.addWidget(browse_button) hlayout1.addWidget(self.start_button) hlayout1.addWidget(self.stop_button) hlayout2 = QHBoxLayout() hlayout2.addWidget(self.ratelabel) hlayout2.addStretch() hlayout2.addWidget(self.datelabel) hlayout2.addStretch() hlayout2.addWidget(self.log_button) layout = QVBoxLayout() layout.addLayout(hlayout1) layout.addLayout(hlayout2) layout.addWidget(self.treewidget) self.setLayout(layout) self.process = None self.set_running_state(False) if PYLINT_PATH is None: for widget in (self.treewidget, self.filecombo, self.start_button, self.stop_button): widget.setDisabled(True) if os.name == 'nt' \ and programs.is_module_installed("pylint"): # Pylint is installed but pylint script is not in PATH # (AFAIK, could happen only on Windows) text = _('Pylint script was not found. Please add "%s" to PATH.') text = to_text_string(text) % osp.join(sys.prefix, "Scripts") else: text = _('Please install <b>pylint</b>:') url = 'http://www.logilab.fr' text += ' <a href=%s>%s</a>' % (url, url) self.ratelabel.setText(text) else: self.show_data()
assert data_header(header, 1, 4) == 'one' assert data_header(header, 0, 5) == 'foo' assert data_header(header, 1, 5) == 'two' def test_header_bom(): """Test for BOM data in the headers.""" df = read_csv(os.path.join(FILES_PATH, 'issue_2514.csv')) editor = DataFrameEditor(None) editor.setup_and_check(df) header = editor.table_header.model() assert header.headerData(0, Qt.Horizontal, Qt.DisplayRole) == "Date (MMM-YY)" @pytest.mark.skipif(is_module_installed('pandas', '<0.19'), reason="It doesn't work for Pandas 0.19-") def test_header_encoding(): """Test for header encoding handling.""" df = read_csv(os.path.join(FILES_PATH, 'issue_3896.csv')) editor = DataFrameEditor(None) editor.setup_and_check(df) header = editor.table_header.model() assert header.headerData(0, Qt.Horizontal, Qt.DisplayRole) == "Unnamed: 0" assert "Unieke_Idcode" in header.headerData(1, Qt.Horizontal, Qt.DisplayRole) assert header.headerData(2, Qt.Horizontal, Qt.DisplayRole) == "a" assert header.headerData(3, Qt.Horizontal, Qt.DisplayRole) == "b"
df = DataFrame([[0]]) editor = DataFrameEditor(None) editor.setup_and_check(df) with qtbot.assertNotEmitted(editor.sig_option_changed): editor.change_format() def test_header_bom(): df = read_csv(os.path.join(FILES_PATH, 'issue_2514.csv')) editor = DataFrameEditor(None) editor.setup_and_check(df) model = editor.dataModel assert model.headerData(1, orientation=Qt.Horizontal) == "Date (MMM-YY)" @pytest.mark.skipif(is_module_installed('pandas', '<0.19'), reason="It doesn't work for Pandas 0.19-") def test_header_encoding(): df = read_csv(os.path.join(FILES_PATH, 'issue_3896.csv')) editor = DataFrameEditor(None) editor.setup_and_check(df) model = editor.dataModel assert model.headerData(0, orientation=Qt.Horizontal) == "Index" assert model.headerData(1, orientation=Qt.Horizontal) == "Unnamed: 0" assert model.headerData(2, orientation=Qt.Horizontal) == "Unieke_Idcode" assert model.headerData(3, orientation=Qt.Horizontal) == "a" assert model.headerData(4, orientation=Qt.Horizontal) == "b" assert model.headerData(5, orientation=Qt.Horizontal) == "c" assert model.headerData(6, orientation=Qt.Horizontal) == "d"
def __init__(self, parent): if PYQT5: SpyderPluginWidget.__init__(self, parent, main = parent) else: SpyderPluginWidget.__init__(self, parent) self.internal_shell = None # Initialize plugin self.initialize_plugin() self.no_doc_string = _("No further documentation available") self._last_console_cb = None self._last_editor_cb = None self.plain_text = PlainText(self) self.rich_text = RichText(self) color_scheme = self.get_color_scheme() self.set_plain_text_font(self.get_plugin_font(), color_scheme) self.plain_text.editor.toggle_wrap_mode(self.get_option('wrap')) # Add entries to read-only editor context-menu self.wrap_action = create_action(self, _("Wrap lines"), toggled=self.toggle_wrap_mode) self.wrap_action.setChecked(self.get_option('wrap')) self.plain_text.editor.readonly_menu.addSeparator() add_actions(self.plain_text.editor.readonly_menu, (self.wrap_action,)) self.set_rich_text_font(self.get_plugin_font('rich_text')) self.shell = None self.external_console = None # locked = disable link with Console self.locked = False self._last_texts = [None, None] self._last_editor_doc = None # Object name layout_edit = QHBoxLayout() layout_edit.setContentsMargins(0, 0, 0, 0) txt = _("Source") if sys.platform == 'darwin': source_label = QLabel(" " + txt) else: source_label = QLabel(txt) layout_edit.addWidget(source_label) self.source_combo = QComboBox(self) self.source_combo.addItems([_("Console"), _("Editor")]) self.source_combo.currentIndexChanged.connect(self.source_changed) if (not programs.is_module_installed('rope') and not programs.is_module_installed('jedi', '>=0.8.1')): self.source_combo.hide() source_label.hide() layout_edit.addWidget(self.source_combo) layout_edit.addSpacing(10) layout_edit.addWidget(QLabel(_("Object"))) self.combo = ObjectComboBox(self) layout_edit.addWidget(self.combo) self.object_edit = QLineEdit(self) self.object_edit.setReadOnly(True) layout_edit.addWidget(self.object_edit) self.combo.setMaxCount(self.get_option('max_history_entries')) self.combo.addItems( self.load_history() ) self.combo.setItemText(0, '') self.combo.valid.connect(lambda valid: self.force_refresh()) # Plain text docstring option self.docstring = True self.rich_help = self.get_option('rich_mode', True) self.plain_text_action = create_action(self, _("Plain Text"), toggled=self.toggle_plain_text) # Source code option self.show_source_action = create_action(self, _("Show Source"), toggled=self.toggle_show_source) # Rich text option self.rich_text_action = create_action(self, _("Rich Text"), toggled=self.toggle_rich_text) # Add the help actions to an exclusive QActionGroup help_actions = QActionGroup(self) help_actions.setExclusive(True) help_actions.addAction(self.plain_text_action) help_actions.addAction(self.rich_text_action) # Automatic import option self.auto_import_action = create_action(self, _("Automatic import"), toggled=self.toggle_auto_import) auto_import_state = self.get_option('automatic_import') self.auto_import_action.setChecked(auto_import_state) # Lock checkbox self.locked_button = create_toolbutton(self, triggered=self.toggle_locked) layout_edit.addWidget(self.locked_button) self._update_lock_icon() # Option menu options_button = create_toolbutton(self, text=_('Options'), icon=ima.icon('tooloptions')) options_button.setPopupMode(QToolButton.InstantPopup) menu = QMenu(self) add_actions(menu, [self.rich_text_action, self.plain_text_action, self.show_source_action, None, self.auto_import_action]) options_button.setMenu(menu) layout_edit.addWidget(options_button) if self.rich_help: self.switch_to_rich_text() else: self.switch_to_plain_text() self.plain_text_action.setChecked(not self.rich_help) self.rich_text_action.setChecked(self.rich_help) self.source_changed() # Main layout layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addLayout(layout_edit) layout.addWidget(self.plain_text) layout.addWidget(self.rich_text) self.setLayout(layout) # Add worker thread for handling rich text rendering self._sphinx_thread = SphinxThread( html_text_no_doc=warning(self.no_doc_string)) self._sphinx_thread.html_ready.connect( self._on_sphinx_thread_html_ready) self._sphinx_thread.error_msg.connect(self._on_sphinx_thread_error_msg) # Handle internal and external links view = self.rich_text.webview if not WEBENGINE: view.page().setLinkDelegationPolicy(QWebEnginePage.DelegateAllLinks) view.linkClicked.connect(self.handle_link_clicks) self._starting_up = True
""" # Assert that all paths are checked. for row in range(pathmanager.listwidget.count()): assert pathmanager.listwidget.item(row).checkState() == Qt.Checked # Uncheck a path and assert that it is added to the not active path list. pathmanager.listwidget.item(3).setCheckState(Qt.Unchecked) assert pathmanager.not_active_pathlist != [] # Check an uncheked path and assert that it is removed from the not active # path list. pathmanager.listwidget.item(3).setCheckState(Qt.Checked) assert pathmanager.not_active_pathlist == [] @pytest.mark.skipif(os.name != 'nt' or not is_module_installed('win32con'), reason=("This feature is not applicable for Unix " "systems and pywin32 is needed")) @pytest.mark.parametrize('pathmanager', [(['path1', 'path2', 'path3'], ['path4', 'path5', 'path6'])], indirect=True) def test_synchronize_with_PYTHONPATH(pathmanager, mocker): # Import here to prevent an ImportError when testing on unix systems from spyder.utils.environ import (get_user_env, set_user_env, listdict2envdict) # Store PYTHONPATH original state env = get_user_env() original_pathlist = env.get('PYTHONPATH', []) # Mock the dialog window and answer "Yes" to clear contents of PYTHONPATH
def psutil_phymem_usage(): """ Return physical memory usage (float) Requires the cross-platform psutil (>=v0.3) library (http://code.google.com/p/psutil/) """ import psutil # This is needed to avoid a deprecation warning error with # newer psutil versions try: percent = psutil.virtual_memory().percent except: percent = psutil.phymem_usage().percent return percent if programs.is_module_installed('psutil', '>=0.3.0'): # Function `psutil.phymem_usage` was introduced in psutil v0.3.0 memory_usage = psutil_phymem_usage elif os.name == 'nt': # Backup plan for Windows platforms memory_usage = windows_memory_usage else: raise ImportError("Feature requires psutil 0.3+ on non Windows platforms") if __name__ == '__main__': print("*"*80) print(memory_usage.__doc__) print(memory_usage()) if os.name == 'nt': # windll can only be imported if os.name = 'nt' or 'ce'
def kernel_config(): """Create a config object with IPython kernel options.""" from IPython.core.application import get_ipython_dir from traitlets.config.loader import Config, load_pyconfig_files if not IS_EXT_INTERPRETER: from spyder.config.main import CONF from spyder.utils.programs import is_module_installed else: # We add "spyder" to sys.path for external interpreters, # so this works! # See create_kernel_spec of plugins/ipythonconsole from config.main import CONF from utils.programs import is_module_installed # ---- IPython config ---- try: profile_path = osp.join(get_ipython_dir(), 'profile_default') cfg = load_pyconfig_files(['ipython_config.py', 'ipython_kernel_config.py'], profile_path) except: cfg = Config() # ---- Spyder config ---- spy_cfg = Config() # Until we implement Issue 1052 spy_cfg.InteractiveShell.xmode = 'Plain' spy_cfg.IPCompleter.use_jedi = False # Run lines of code at startup run_lines_o = CONF.get('ipython_console', 'startup/run_lines') if run_lines_o: spy_cfg.IPKernelApp.exec_lines = [x.strip() for x in run_lines_o.split(',')] else: spy_cfg.IPKernelApp.exec_lines = [] # Clean terminal arguments input clear_argv = "import sys;sys.argv = [''];del sys" spy_cfg.IPKernelApp.exec_lines.append(clear_argv) # Pylab configuration mpl_backend = None mpl_installed = is_module_installed('matplotlib') pylab_o = CONF.get('ipython_console', 'pylab') if mpl_installed and pylab_o: # Get matplotlib backend backend_o = CONF.get('ipython_console', 'pylab/backend') if backend_o == 1: if is_module_installed('PyQt5'): auto_backend = 'qt5' elif is_module_installed('PyQt4'): auto_backend = 'qt4' elif is_module_installed('_tkinter'): auto_backend = 'tk' else: auto_backend = 'inline' else: auto_backend = '' backends = {0: 'inline', 1: auto_backend, 2: 'qt5', 3: 'qt4', 4: 'osx', 5: 'gtk3', 6: 'gtk', 7: 'wx', 8: 'tk'} mpl_backend = backends[backend_o] # Automatically load Pylab and Numpy, or only set Matplotlib # backend autoload_pylab_o = CONF.get('ipython_console', 'pylab/autoload') if autoload_pylab_o: spy_cfg.IPKernelApp.exec_lines.append( "%pylab {0}".format(mpl_backend)) else: spy_cfg.IPKernelApp.exec_lines.append( "%matplotlib {0}".format(mpl_backend)) # Inline backend configuration if mpl_backend == 'inline': # Figure format format_o = CONF.get('ipython_console', 'pylab/inline/figure_format', 0) formats = {0: 'png', 1: 'svg'} spy_cfg.InlineBackend.figure_format = formats[format_o] # Resolution if is_module_installed('ipykernel', '<4.5'): dpi_option = 'savefig.dpi' else: dpi_option = 'figure.dpi' spy_cfg.InlineBackend.rc = {'figure.figsize': (6.0, 4.0), dpi_option: 72, 'font.size': 10, 'figure.subplot.bottom': .125, 'figure.facecolor': 'white', 'figure.edgecolor': 'white'} resolution_o = CONF.get('ipython_console', 'pylab/inline/resolution') spy_cfg.InlineBackend.rc[dpi_option] = resolution_o # Figure size width_o = float(CONF.get('ipython_console', 'pylab/inline/width')) height_o = float(CONF.get('ipython_console', 'pylab/inline/height')) spy_cfg.InlineBackend.rc['figure.figsize'] = (width_o, height_o) # Enable Cython magic if is_module_installed('Cython'): spy_cfg.IPKernelApp.exec_lines.append('%load_ext Cython') # Run a file at startup use_file_o = CONF.get('ipython_console', 'startup/use_run_file') run_file_o = CONF.get('ipython_console', 'startup/run_file') if use_file_o and run_file_o: spy_cfg.IPKernelApp.file_to_run = run_file_o # Autocall autocall_o = CONF.get('ipython_console', 'autocall') spy_cfg.ZMQInteractiveShell.autocall = autocall_o # To handle the banner by ourselves in IPython 3+ spy_cfg.ZMQInteractiveShell.banner1 = '' # Greedy completer greedy_o = CONF.get('ipython_console', 'greedy_completer') spy_cfg.IPCompleter.greedy = greedy_o # Sympy loading sympy_o = CONF.get('ipython_console', 'symbolic_math') if sympy_o and is_module_installed('sympy'): lines = sympy_config(mpl_backend) spy_cfg.IPKernelApp.exec_lines.append(lines) # Merge IPython and Spyder configs. Spyder prefs will have prevalence # over IPython ones cfg._merge(spy_cfg) return cfg
from spyder.utils.dochelpers import getsignaturefromtext from spyder.utils.introspection.manager import (DEBUG_EDITOR, LOG_FILENAME, IntrospectionPlugin) from spyder.utils.introspection.utils import get_parent_until from spyder.utils.introspection.manager import JEDI_REQVER try: try: from spyder.utils.introspection import jedi_patch jedi = jedi_patch.apply() except ImportError: import jedi except ImportError: jedi = None JEDI_010 = programs.is_module_installed('jedi', '>=0.10.0') class JediPlugin(IntrospectionPlugin): """ Jedi based introspection plugin for jedi Experimental Editor's code completion, go-to-definition and help """ # ---- IntrospectionPlugin API -------------------------------------------- name = 'jedi' def load_plugin(self): """Load the Jedi introspection plugin""" if not programs.is_module_installed('jedi', JEDI_REQVER):
# Numpy scalars all inherit from np.generic. # Numpy arrays all inherit from np.ndarray. # If we check that we are certain we have one of these # types then we are less likely to generate an exception below. try: return obj.dtype.type except (AttributeError, RuntimeError): # AttributeError: some NumPy objects have no dtype attribute # RuntimeError: happens with NetCDF objects (Issue 998) return #============================================================================== # Pandas support #============================================================================== if programs.is_module_installed('pandas', PANDAS_REQVER): from pandas import DataFrame, DatetimeIndex, Series else: DataFrame = DatetimeIndex = Series = FakeObject # analysis:ignore #============================================================================== # PIL Images support #============================================================================== try: from spyder import pil_patch Image = pil_patch.Image.Image except ImportError: Image = FakeObject # analysis:ignore
# Numpy scalars all inherit from np.generic. # Numpy arrays all inherit from np.ndarray. # If we check that we are certain we have one of these # types then we are less likely to generate an exception below. try: return obj.dtype.type except (AttributeError, RuntimeError): # AttributeError: some NumPy objects have no dtype attribute # RuntimeError: happens with NetCDF objects (Issue 998) return #============================================================================== # Pandas support #============================================================================== if programs.is_module_installed('pandas', PANDAS_REQVER): from pandas import DataFrame, Series else: DataFrame = Series = FakeObject # analysis:ignore #============================================================================== # PIL Images support #============================================================================== try: from spyder import pil_patch Image = pil_patch.Image.Image except ImportError: Image = FakeObject # analysis:ignore
def setup_page(self): interface_group = QGroupBox(_("Interface")) newcb = self.create_checkbox singletab_box = newcb(_("One tab per script"), 'single_tab') showtime_box = newcb(_("Show elapsed time"), 'show_elapsed_time') icontext_box = newcb(_("Show icons and text"), 'show_icontext') # Interface Group interface_layout = QVBoxLayout() interface_layout.addWidget(singletab_box) interface_layout.addWidget(showtime_box) interface_layout.addWidget(icontext_box) interface_group.setLayout(interface_layout) # Source Code Group display_group = QGroupBox(_("Source code")) buffer_spin = self.create_spinbox(_("Buffer: "), _(" lines"), 'max_line_count', min_=0, max_=1000000, step=100, tip=_("Set maximum line count")) wrap_mode_box = newcb(_("Wrap lines"), 'wrap') merge_channels_box = newcb( _("Merge process standard output/error channels"), 'merge_output_channels', tip=_("Merging the output channels of the process means that\n" "the standard error won't be written in red anymore,\n" "but this has the effect of speeding up display.")) colorize_sys_stderr_box = newcb( _("Colorize standard error channel using ANSI escape codes"), 'colorize_sys_stderr', tip=_("This method is the only way to have colorized standard\n" "error channel when the output channels have been " "merged.")) merge_channels_box.toggled.connect(colorize_sys_stderr_box.setEnabled) merge_channels_box.toggled.connect(colorize_sys_stderr_box.setChecked) colorize_sys_stderr_box.setEnabled( self.get_option('merge_output_channels')) display_layout = QVBoxLayout() display_layout.addWidget(buffer_spin) display_layout.addWidget(wrap_mode_box) display_layout.addWidget(merge_channels_box) display_layout.addWidget(colorize_sys_stderr_box) display_group.setLayout(display_layout) # Background Color Group bg_group = QGroupBox(_("Background color")) bg_label = QLabel( _("This option will be applied the next time " "a Python console or a terminal is opened.")) bg_label.setWordWrap(True) lightbg_box = newcb(_("Light background (white color)"), 'light_background') bg_layout = QVBoxLayout() bg_layout.addWidget(bg_label) bg_layout.addWidget(lightbg_box) bg_group.setLayout(bg_layout) # Advanced settings source_group = QGroupBox(_("Source code")) completion_box = newcb(_("Automatic code completion"), 'codecompletion/auto') case_comp_box = newcb(_("Case sensitive code completion"), 'codecompletion/case_sensitive') comp_enter_box = newcb(_("Enter key selects completion"), 'codecompletion/enter_key') calltips_box = newcb(_("Display balloon tips"), 'calltips') source_layout = QVBoxLayout() source_layout.addWidget(completion_box) source_layout.addWidget(case_comp_box) source_layout.addWidget(comp_enter_box) source_layout.addWidget(calltips_box) source_group.setLayout(source_layout) # PYTHONSTARTUP replacement pystartup_group = QGroupBox(_("PYTHONSTARTUP replacement")) pystartup_bg = QButtonGroup(pystartup_group) pystartup_label = QLabel( _("This option will override the " "PYTHONSTARTUP environment variable which\n" "defines the script to be executed during " "the Python console startup.")) def_startup_radio = self.create_radiobutton( _("Default PYTHONSTARTUP script"), 'pythonstartup/default', button_group=pystartup_bg) cus_startup_radio = self.create_radiobutton( _("Use the following startup script:"), 'pythonstartup/custom', button_group=pystartup_bg) pystartup_file = self.create_browsefile('', 'pythonstartup', '', filters=_("Python scripts")+\ " (*.py)") def_startup_radio.toggled.connect(pystartup_file.setDisabled) cus_startup_radio.toggled.connect(pystartup_file.setEnabled) pystartup_layout = QVBoxLayout() pystartup_layout.addWidget(pystartup_label) pystartup_layout.addWidget(def_startup_radio) pystartup_layout.addWidget(cus_startup_radio) pystartup_layout.addWidget(pystartup_file) pystartup_group.setLayout(pystartup_layout) # Monitor Group monitor_group = QGroupBox(_("Monitor")) monitor_label = QLabel( _("The monitor provides introspection " "features to console: code completion, " "calltips and variable explorer. " "Because it relies on several modules, " "disabling the monitor may be useful " "to accelerate console startup.")) monitor_label.setWordWrap(True) monitor_box = newcb(_("Enable monitor"), 'monitor/enabled') for obj in (completion_box, case_comp_box, comp_enter_box, calltips_box): monitor_box.toggled.connect(obj.setEnabled) obj.setEnabled(self.get_option('monitor/enabled')) monitor_layout = QVBoxLayout() monitor_layout.addWidget(monitor_label) monitor_layout.addWidget(monitor_box) monitor_group.setLayout(monitor_layout) # Qt Group opts = [ (_("Default library"), 'default'), ('PyQt5', 'pyqt5'), ('PyQt4', 'pyqt'), ('PySide', 'pyside'), ] qt_group = QGroupBox(_("Qt-Python Bindings")) qt_setapi_box = self.create_combobox( _("Library:") + " ", opts, 'qt/api', default='default', tip=_("This option will act on<br> " "libraries such as Matplotlib, guidata " "or ETS")) qt_layout = QVBoxLayout() qt_layout.addWidget(qt_setapi_box) qt_group.setLayout(qt_layout) # Matplotlib Group mpl_group = QGroupBox(_("Graphics")) mpl_label = QLabel( _("Decide which backend to use to display graphics. " "If unsure, please select the <b>Automatic</b> " "backend.<br><br>" "<b>Note:</b> We support a very limited number " "of backends in our Python consoles. If you " "prefer to work with a different one, please use " "an IPython console.")) mpl_label.setWordWrap(True) backends = [("Automatic", 0), ("None", 1)] if not os.name == 'nt' and programs.is_module_installed('_tkinter'): backends.append(("Tkinter", 2)) backends = tuple(backends) mpl_backend_box = self.create_combobox( _("Backend:") + " ", backends, 'matplotlib/backend/value', tip=_("This option will be applied the " "next time a console is opened.")) mpl_installed = programs.is_module_installed('matplotlib') mpl_layout = QVBoxLayout() mpl_layout.addWidget(mpl_label) mpl_layout.addWidget(mpl_backend_box) mpl_group.setLayout(mpl_layout) mpl_group.setEnabled(mpl_installed) # ETS Group ets_group = QGroupBox(_("Enthought Tool Suite")) ets_label = QLabel( _("Enthought Tool Suite (ETS) supports " "PyQt4 (qt4) and wxPython (wx) graphical " "user interfaces.")) ets_label.setWordWrap(True) ets_edit = self.create_lineedit(_("ETS_TOOLKIT:"), 'ets_backend', alignment=Qt.Horizontal) ets_layout = QVBoxLayout() ets_layout.addWidget(ets_label) ets_layout.addWidget(ets_edit) ets_group.setLayout(ets_layout) if CONF.get('main_interpreter', 'default'): interpreter = get_python_executable() else: interpreter = CONF.get('main_interpreter', 'executable') ets_group.setEnabled( programs.is_module_installed("enthought.etsconfig.api", interpreter=interpreter)) tabs = QTabWidget() tabs.addTab(self.create_tab(interface_group, display_group, bg_group), _("Display")) tabs.addTab(self.create_tab(monitor_group, source_group), _("Introspection")) tabs.addTab(self.create_tab(pystartup_group), _("Advanced settings")) tabs.addTab(self.create_tab(qt_group, mpl_group, ets_group), _("External modules")) vlayout = QVBoxLayout() vlayout.addWidget(tabs) self.setLayout(vlayout)
def apply(): """Monkey patching jedi See [1] and [2] module docstring.""" from spyder.utils.programs import is_module_installed if is_module_installed('jedi', '=0.9.0'): import jedi else: raise ImportError("jedi %s can't be patched" % jedi.__version__) # [1] Adding numpydoc type returns to docstrings from spyder.utils.introspection import docstrings jedi.evaluate.representation.docstrings = docstrings # [2] Adding type returns for compiled objects in jedi # Patching jedi.evaluate.compiled.CompiledObject... from jedi.evaluate.compiled import ( CompiledObject, builtin, _create_from_name, debug) class CompiledObject(CompiledObject): # ...adding docstrings int _execute_function... def _execute_function(self, evaluator, params): if self.type != 'funcdef': return # patching docstrings here from spyder.utils.introspection import docstrings types = docstrings.find_return_types(evaluator, self) if types: for result in types: debug.dbg('docstrings type return: %s in %s', result, self) yield result # end patch for name in self._parse_function_doc()[1].split(): try: bltn_obj = _create_from_name(builtin, builtin, name) except AttributeError: continue else: if isinstance(bltn_obj, CompiledObject) and bltn_obj.obj is None: # We want everything except None. continue for result in evaluator.execute(bltn_obj, params): yield result # ...docstrings needs a raw_doc property @property def raw_doc(self): try: doc = unicode(self.doc) except NameError: # python 3 doc = self.doc return doc jedi.evaluate.compiled.CompiledObject = CompiledObject # [3] Fixing introspection for matplotlib Axes objects # Patching jedi.evaluate.precedence... from jedi.evaluate.precedence import tree, calculate def calculate_children(evaluator, children): """ Calculate a list of children with operators. """ iterator = iter(children) types = evaluator.eval_element(next(iterator)) for operator in iterator: try:# PATCH: Catches StopIteration error right = next(iterator) if tree.is_node(operator, 'comp_op'): # not in / is not operator = ' '.join(str(c.value) for c in operator.children) # handle lazy evaluation of and/or here. if operator in ('and', 'or'): left_bools = set([left.py__bool__() for left in types]) if left_bools == set([True]): if operator == 'and': types = evaluator.eval_element(right) elif left_bools == set([False]): if operator != 'and': types = evaluator.eval_element(right) # Otherwise continue, because of uncertainty. else: types = calculate(evaluator, types, operator, evaluator.eval_element(right)) except StopIteration: debug.warning('calculate_children StopIteration %s', types) debug.dbg('calculate_children types %s', types) return types jedi.evaluate.precedence.calculate_children = calculate_children # [4] Fixing introspection for matplotlib Axes objects # Patching jedi.evaluate.precedence... from jedi.evaluate.representation import ( tree, InstanceName, Instance, compiled, FunctionExecution, InstanceElement) def get_instance_el(evaluator, instance, var, is_class_var=False): """ Returns an InstanceElement if it makes sense, otherwise leaves the object untouched. Basically having an InstanceElement is context information. That is needed in quite a lot of cases, which includes Nodes like ``power``, that need to know where a self name comes from for example. """ if isinstance(var, tree.Name): parent = get_instance_el(evaluator, instance, var.parent, is_class_var) return InstanceName(var, parent) # PATCH: compiled objects can be None elif var is None: return var elif var.type != 'funcdef' \ and isinstance(var, (Instance, compiled.CompiledObject, tree.Leaf, tree.Module, FunctionExecution)): return var var = evaluator.wrap(var) return InstanceElement(evaluator, instance, var, is_class_var) jedi.evaluate.representation.get_instance_el = get_instance_el return jedi
def __init__(self, parent=None, css_path=CSS_PATH): SpyderPluginWidget.__init__(self, parent) self.internal_shell = None self.console = None self.css_path = css_path self.no_doc_string = _("No documentation available") self._last_console_cb = None self._last_editor_cb = None self.plain_text = PlainText(self) self.rich_text = RichText(self) color_scheme = self.get_color_scheme() self.set_plain_text_font(self.get_font(), color_scheme) self.plain_text.editor.toggle_wrap_mode(self.get_option('wrap')) # Add entries to read-only editor context-menu self.wrap_action = create_action(self, _("Wrap lines"), toggled=self.toggle_wrap_mode) self.wrap_action.setChecked(self.get_option('wrap')) self.plain_text.editor.readonly_menu.addSeparator() add_actions(self.plain_text.editor.readonly_menu, (self.wrap_action,)) self.set_rich_text_font(self.get_font(rich_text=True)) self.shell = None # locked = disable link with Console self.locked = False self._last_texts = [None, None] self._last_editor_doc = None # Object name layout_edit = QHBoxLayout() layout_edit.setContentsMargins(0, 0, 0, 0) txt = _("Source") if sys.platform == 'darwin': source_label = QLabel(" " + txt) else: source_label = QLabel(txt) layout_edit.addWidget(source_label) self.source_combo = QComboBox(self) self.source_combo.addItems([_("Console"), _("Editor")]) self.source_combo.currentIndexChanged.connect(self.source_changed) if (not programs.is_module_installed('rope') and not programs.is_module_installed('jedi', '>=0.11.0')): self.source_combo.hide() source_label.hide() layout_edit.addWidget(self.source_combo) layout_edit.addSpacing(10) layout_edit.addWidget(QLabel(_("Object"))) self.combo = ObjectComboBox(self) layout_edit.addWidget(self.combo) self.object_edit = QLineEdit(self) self.object_edit.setReadOnly(True) layout_edit.addWidget(self.object_edit) self.combo.setMaxCount(self.get_option('max_history_entries')) self.combo.addItems( self.load_history() ) self.combo.setItemText(0, '') self.combo.valid.connect(self.force_refresh) # Plain text docstring option self.docstring = True self.rich_help = self.get_option('rich_mode', True) self.plain_text_action = create_action(self, _("Plain Text"), toggled=self.toggle_plain_text) # Source code option self.show_source_action = create_action(self, _("Show Source"), toggled=self.toggle_show_source) # Rich text option self.rich_text_action = create_action(self, _("Rich Text"), toggled=self.toggle_rich_text) # Add the help actions to an exclusive QActionGroup help_actions = QActionGroup(self) help_actions.setExclusive(True) help_actions.addAction(self.plain_text_action) help_actions.addAction(self.rich_text_action) # Automatic import option self.auto_import_action = create_action(self, _("Automatic import"), toggled=self.toggle_auto_import) auto_import_state = self.get_option('automatic_import') self.auto_import_action.setChecked(auto_import_state) # Lock checkbox self.locked_button = create_toolbutton(self, triggered=self.toggle_locked) layout_edit.addWidget(self.locked_button) self._update_lock_icon() # Option menu layout_edit.addWidget(self.options_button) if self.rich_help: self.switch_to_rich_text() else: self.switch_to_plain_text() self.plain_text_action.setChecked(not self.rich_help) self.rich_text_action.setChecked(self.rich_help) self.source_changed() # Main layout layout = create_plugin_layout(layout_edit) # we have two main widgets, but only one of them is shown at a time layout.addWidget(self.plain_text) layout.addWidget(self.rich_text) self.setLayout(layout) # Add worker thread for handling rich text rendering self._sphinx_thread = SphinxThread( html_text_no_doc=warning(self.no_doc_string, css_path=self.css_path), css_path=self.css_path) self._sphinx_thread.html_ready.connect( self._on_sphinx_thread_html_ready) self._sphinx_thread.error_msg.connect(self._on_sphinx_thread_error_msg) # Handle internal and external links view = self.rich_text.webview if not WEBENGINE: view.page().setLinkDelegationPolicy(QWebEnginePage.DelegateAllLinks) view.linkClicked.connect(self.handle_link_clicks) self._starting_up = True
# Change directory in the explorer widget explorer.chdir(temp_dir) qtbot.wait(1000) # Assert that cwd changed in workingdirectory assert osp.normpath(wdir.history[-1]) == osp.normpath(temp_dir) # Assert that cwd changed in IPython console assert osp.normpath(temp_dir) == osp.normpath(shell._cwd) @pytest.mark.slow @flaky(max_runs=3) @pytest.mark.skipif( os.name == 'nt' or not is_module_installed('Cython'), reason="It times out sometimes on Windows and Cython is needed") def test_run_cython_code(main_window, qtbot): """Test all the different ways we have to run Cython code""" # ---- Setup ---- # Wait until the window is fully up shell = main_window.ipyconsole.get_current_shellwidget() qtbot.waitUntil(lambda: shell._prompt_html is not None, timeout=SHELL_TIMEOUT) # Get a reference to the namespace browser widget nsb = main_window.variableexplorer.get_focus_widget() # Get a reference to the code editor widget code_editor = main_window.editor.get_focus_widget()
def kernel_config(): """Create a config object with IPython kernel options.""" from IPython.core.application import get_ipython_dir from traitlets.config.loader import Config, load_pyconfig_files if not IS_EXT_INTERPRETER: from spyder.config.main import CONF from spyder.utils.programs import is_module_installed else: # We add "spyder" to sys.path for external interpreters, # so this works! # See create_kernel_spec of plugins/ipythonconsole from config.main import CONF from utils.programs import is_module_installed # ---- IPython config ---- try: profile_path = osp.join(get_ipython_dir(), 'profile_default') cfg = load_pyconfig_files(['ipython_config.py', 'ipython_kernel_config.py'], profile_path) except: cfg = Config() # ---- Spyder config ---- spy_cfg = Config() # Until we implement Issue 1052 spy_cfg.InteractiveShell.xmode = 'Plain' # Using Jedi slow completions a lot for objects # with big repr's spy_cfg.IPCompleter.use_jedi = False # Run lines of code at startup run_lines_o = CONF.get('ipython_console', 'startup/run_lines') if run_lines_o: spy_cfg.IPKernelApp.exec_lines = [x.strip() for x in run_lines_o.split(',')] else: spy_cfg.IPKernelApp.exec_lines = [] # Clean terminal arguments input clear_argv = "import sys;sys.argv = [''];del sys" spy_cfg.IPKernelApp.exec_lines.append(clear_argv) # Pylab configuration mpl_backend = None mpl_installed = is_module_installed('matplotlib') pylab_o = CONF.get('ipython_console', 'pylab') if mpl_installed and pylab_o: # Get matplotlib backend backend_o = CONF.get('ipython_console', 'pylab/backend') if backend_o == 1: if is_module_installed('PyQt5'): auto_backend = 'qt5' elif is_module_installed('PyQt4'): auto_backend = 'qt4' elif is_module_installed('_tkinter'): auto_backend = 'tk' else: auto_backend = 'inline' else: auto_backend = '' backends = {0: 'inline', 1: auto_backend, 2: 'qt5', 3: 'qt4', 4: 'osx', 5: 'gtk3', 6: 'gtk', 7: 'wx', 8: 'tk'} mpl_backend = backends[backend_o] # Automatically load Pylab and Numpy, or only set Matplotlib # backend autoload_pylab_o = CONF.get('ipython_console', 'pylab/autoload') if autoload_pylab_o: spy_cfg.IPKernelApp.exec_lines.append( "%pylab {0}".format(mpl_backend)) else: spy_cfg.IPKernelApp.exec_lines.append( "%matplotlib {0}".format(mpl_backend)) # Inline backend configuration if mpl_backend == 'inline': # Figure format format_o = CONF.get('ipython_console', 'pylab/inline/figure_format', 0) formats = {0: 'png', 1: 'svg'} spy_cfg.InlineBackend.figure_format = formats[format_o] # Resolution if is_module_installed('ipykernel', '<4.5'): dpi_option = 'savefig.dpi' else: dpi_option = 'figure.dpi' spy_cfg.InlineBackend.rc = {'figure.figsize': (6.0, 4.0), dpi_option: 72, 'font.size': 10, 'figure.subplot.bottom': .125, 'figure.facecolor': 'white', 'figure.edgecolor': 'white'} resolution_o = CONF.get('ipython_console', 'pylab/inline/resolution') spy_cfg.InlineBackend.rc[dpi_option] = resolution_o # Figure size width_o = float(CONF.get('ipython_console', 'pylab/inline/width')) height_o = float(CONF.get('ipython_console', 'pylab/inline/height')) spy_cfg.InlineBackend.rc['figure.figsize'] = (width_o, height_o) # Enable Cython magic if is_module_installed('Cython'): spy_cfg.IPKernelApp.exec_lines.append('%load_ext Cython') # Run a file at startup use_file_o = CONF.get('ipython_console', 'startup/use_run_file') run_file_o = CONF.get('ipython_console', 'startup/run_file') if use_file_o and run_file_o: spy_cfg.IPKernelApp.file_to_run = run_file_o # Autocall autocall_o = CONF.get('ipython_console', 'autocall') spy_cfg.ZMQInteractiveShell.autocall = autocall_o # To handle the banner by ourselves in IPython 3+ spy_cfg.ZMQInteractiveShell.banner1 = '' # Greedy completer greedy_o = CONF.get('ipython_console', 'greedy_completer') spy_cfg.IPCompleter.greedy = greedy_o # Sympy loading sympy_o = CONF.get('ipython_console', 'symbolic_math') if sympy_o and is_module_installed('sympy'): lines = sympy_config(mpl_backend) spy_cfg.IPKernelApp.exec_lines.append(lines) # Merge IPython and Spyder configs. Spyder prefs will have prevalence # over IPython ones cfg._merge(spy_cfg) return cfg
def check(self): """Check if dependency is installed""" return programs.is_module_installed(self.modname, self.required_version, self.installed_version)
def setup(self, check_all=None, exclude_private=None, exclude_uppercase=None, exclude_capitalized=None, exclude_unsupported=None, excluded_names=None, minmax=None, dataframe_format=None): """ Setup the namespace browser with provided settings. Args: dataframe_format (string): default floating-point format for DataFrame editor """ assert self.shellwidget is not None self.check_all = check_all self.exclude_private = exclude_private self.exclude_uppercase = exclude_uppercase self.exclude_capitalized = exclude_capitalized self.exclude_unsupported = exclude_unsupported self.excluded_names = excluded_names self.minmax = minmax self.dataframe_format = dataframe_format if self.editor is not None: self.editor.setup_menu(minmax) self.editor.set_dataframe_format(dataframe_format) self.exclude_private_action.setChecked(exclude_private) self.exclude_uppercase_action.setChecked(exclude_uppercase) self.exclude_capitalized_action.setChecked(exclude_capitalized) self.exclude_unsupported_action.setChecked(exclude_unsupported) self.refresh_table() return self.editor = RemoteCollectionsEditorTableView( self, data=None, minmax=minmax, shellwidget=self.shellwidget, dataframe_format=dataframe_format) self.editor.sig_option_changed.connect(self.sig_option_changed.emit) self.editor.sig_files_dropped.connect(self.import_data) # Setup layout layout = QVBoxLayout() blayout = QHBoxLayout() toolbar = self.setup_toolbar(exclude_private, exclude_uppercase, exclude_capitalized, exclude_unsupported) for widget in toolbar: blayout.addWidget(widget) # Options menu options_button = create_toolbutton(self, text=_('Options'), icon=ima.icon('tooloptions')) options_button.setPopupMode(QToolButton.InstantPopup) menu = QMenu(self) editor = self.editor actions = [ self.exclude_private_action, self.exclude_uppercase_action, self.exclude_capitalized_action, self.exclude_unsupported_action, None ] if is_module_installed('numpy'): actions.append(editor.minmax_action) add_actions(menu, actions) options_button.setMenu(menu) blayout.addStretch() blayout.addWidget(options_button) layout.addLayout(blayout) layout.addWidget(self.editor) self.setLayout(layout) layout.setContentsMargins(0, 0, 0, 0) self.sig_option_changed.connect(self.option_changed)
"""Test default info response.""" source_code = 'foo' docs = p.get_info(CodeInfo('info', source_code, len(source_code), __file__, is_python_like=True)) assert sorted(list(docs.keys())) == sorted(['name', 'argspec', 'note', 'docstring', 'calltip']) assert not docs['name'] assert not docs['argspec'] assert not docs['note'] assert not docs['docstring'] assert not docs['calltip'] @pytest.mark.skipif(not(numpy and numpydoc), reason="numpy and numpydoc required") @pytest.mark.skipif(not is_module_installed('jedi', '<0.12.0'), reason="Fails under jedi >=0.12") def test_numpy_returns(): source_code = dedent(''' import numpy as np x = np.array([1,2,3]) x.a''') completions = p.get_completions(CodeInfo('completions', source_code, len(source_code))) assert ('argmax', 'function') in completions @pytest.mark.skipif(not(matplotlib and numpydoc), reason="matplotlib required") @pytest.mark.skipif(not is_module_installed('jedi', '<0.12.0'), reason="Fails under jedi >=0.12")
def is_memoryprofiler_installed(): """ Checks if the library for memory_profiler is installed. """ return programs.is_module_installed('memory_profiler')
from spyder.utils.dochelpers import getsignaturefromtext from spyder.utils.introspection.manager import ( DEBUG_EDITOR, LOG_FILENAME, IntrospectionPlugin) from spyder.utils.introspection.utils import get_parent_until from spyder.utils.introspection.manager import JEDI_REQVER try: try: from spyder.utils.introspection import jedi_patch jedi = jedi_patch.apply() except ImportError: import jedi except ImportError: jedi = None JEDI_010 = programs.is_module_installed('jedi', '>=0.10.0') class JediPlugin(IntrospectionPlugin): """ Jedi based introspection plugin for jedi Experimental Editor's code completion, go-to-definition and help """ # ---- IntrospectionPlugin API -------------------------------------------- name = 'jedi' def load_plugin(self): """Load the Jedi introspection plugin""" if not programs.is_module_installed('jedi', JEDI_REQVER):
def kernel_config(): """Create a config object with IPython kernel options""" import os from IPython.core.application import get_ipython_dir from spyder.config.main import CONF from spyder.utils.programs import is_module_installed from traitlets.config.loader import Config, load_pyconfig_files # ---- IPython config ---- try: profile_path = osp.join(get_ipython_dir(), 'profile_default') ip_cfg = load_pyconfig_files(['ipython_config.py', 'ipython_qtconsole_config.py'], profile_path) except: ip_cfg = Config() # ---- Spyder config ---- spy_cfg = Config() # Until we implement Issue 1052 spy_cfg.InteractiveShell.xmode = 'Plain' # Run lines of code at startup run_lines_o = CONF.get('ipython_console', 'startup/run_lines') if run_lines_o: spy_cfg.IPKernelApp.exec_lines = [x.strip() for x in run_lines_o.split(',')] else: spy_cfg.IPKernelApp.exec_lines = [] # Pylab configuration mpl_backend = None mpl_installed = is_module_installed('matplotlib') pylab_o = CONF.get('ipython_console', 'pylab') external_interpreter = \ os.environ.get('EXTERNAL_INTERPRETER', '').lower() == "true" if mpl_installed and pylab_o: # Get matplotlib backend if not external_interpreter: if os.environ["QT_API"] == 'pyqt5': qt_backend = 'qt5' else: qt_backend = 'qt' backend_o = CONF.get('ipython_console', 'pylab/backend', 0) backends = {0: 'inline', 1: qt_backend, 2: qt_backend, 3: 'osx', 4: 'gtk', 5: 'wx', 6: 'tk'} mpl_backend = backends[backend_o] else: mpl_backend = 'inline' # Automatically load Pylab and Numpy, or only set Matplotlib # backend autoload_pylab_o = CONF.get('ipython_console', 'pylab/autoload') if autoload_pylab_o: spy_cfg.IPKernelApp.exec_lines.append( "%pylab {0}".format(mpl_backend)) else: spy_cfg.IPKernelApp.exec_lines.append( "%matplotlib {0}".format(mpl_backend)) # Inline backend configuration if mpl_backend == 'inline': # Figure format format_o = CONF.get('ipython_console', 'pylab/inline/figure_format', 0) formats = {0: 'png', 1: 'svg'} spy_cfg.InlineBackend.figure_format = formats[format_o] # Resolution spy_cfg.InlineBackend.rc = {'figure.figsize': (6.0, 4.0), 'savefig.dpi': 72, 'font.size': 10, 'figure.subplot.bottom': .125, 'figure.facecolor': 'white', 'figure.edgecolor': 'white' } resolution_o = CONF.get('ipython_console', 'pylab/inline/resolution') spy_cfg.InlineBackend.rc['savefig.dpi'] = resolution_o # Figure size width_o = float(CONF.get('ipython_console', 'pylab/inline/width')) height_o = float(CONF.get('ipython_console', 'pylab/inline/height')) spy_cfg.InlineBackend.rc['figure.figsize'] = (width_o, height_o) # Run a file at startup use_file_o = CONF.get('ipython_console', 'startup/use_run_file') run_file_o = CONF.get('ipython_console', 'startup/run_file') if use_file_o and run_file_o: spy_cfg.IPKernelApp.file_to_run = run_file_o # Autocall autocall_o = CONF.get('ipython_console', 'autocall') spy_cfg.ZMQInteractiveShell.autocall = autocall_o # To handle the banner by ourselves in IPython 3+ spy_cfg.ZMQInteractiveShell.banner1 = '' # Greedy completer greedy_o = CONF.get('ipython_console', 'greedy_completer') spy_cfg.IPCompleter.greedy = greedy_o # Sympy loading sympy_o = CONF.get('ipython_console', 'symbolic_math') if sympy_o: lines = sympy_config(mpl_backend) spy_cfg.IPKernelApp.exec_lines.append(lines) # Merge IPython and Spyder configs. Spyder prefs will have prevalence # over IPython ones ip_cfg._merge(spy_cfg) return ip_cfg
def test_is_module_installed_with_custom_interpreter(): """Test if a module with the proper version is installed""" current = sys.executable assert is_module_installed('qtconsole', '>=4.0', interpreter=current) assert not is_module_installed('IPython', '>=1.0;<3.0', interpreter=current) assert is_module_installed('jedi', '>=0.7.0', interpreter=current)
def is_profiler_installed(): from spyder.utils.programs import is_module_installed return is_module_installed('cProfile') and is_module_installed('pstats')
def __init__(self, name=None, plugin=None, parent=None, options=DEFAULT_OPTIONS): super().__init__(name, plugin, parent, options) # Attributes self._starting_up = True self._current_color_scheme = None self._last_texts = [None, None] self._last_editor_doc = None self._last_console_cb = None self._last_editor_cb = None self.css_path = self.get_option('css_path') self.no_docs = _("No documentation available") self.docstring = True # TODO: What is this used for? # Widgets self._sphinx_thread = SphinxThread( html_text_no_doc=warning(self.no_docs, css_path=self.css_path), css_path=self.css_path, ) self.shell = None self.internal_console = None self.internal_shell = None self.plain_text = PlainText(self) self.rich_text = RichText(self) self.source_label = QLabel(_("Source")) self.source_combo = QComboBox(self) self.object_label = QLabel(_("Object")) self.object_combo = ObjectComboBox(self) self.object_edit = QLineEdit(self) # Setup self.object_edit.setReadOnly(True) self.object_combo.setMaxCount(self.get_option('max_history_entries')) self.object_combo.setItemText(0, '') self.plain_text.set_wrap_mode(self.get_option('wrap')) self.source_combo.addItems([_("Console"), _("Editor")]) if (not programs.is_module_installed('rope') and not programs.is_module_installed('jedi', '>=0.11.0')): self.source_combo.hide() self.source_label.hide() # Layout self.stack_layout = layout = QStackedLayout() layout.addWidget(self.rich_text) layout.addWidget(self.plain_text) self.setLayout(layout) # Signals self._sphinx_thread.html_ready.connect( self._on_sphinx_thread_html_ready) self._sphinx_thread.error_msg.connect(self._on_sphinx_thread_error_msg) self.object_combo.valid.connect(self.force_refresh) self.rich_text.sig_link_clicked.connect(self.handle_link_clicks) self.source_combo.currentIndexChanged.connect( lambda x: self.source_changed()) self.sig_render_started.connect(self.start_spinner) self.sig_render_finished.connect(self.stop_spinner)
from spyder.utils.programs import is_module_installed # ---- Auxiliary constants and functions HERE = osp.dirname(osp.abspath(__file__)) ASSETS = osp.join(HERE, 'assets') autopep8 = pytest.param( 'autopep8', marks=pytest.mark.skipif( os.name == 'nt', reason='autopep8 produces a different output on Windows')) yapf = pytest.param( 'yapf', marks=pytest.mark.skipif( is_module_installed('yapf', '<0.32.0'), reason='Versions older than 0.32 produce different outputs')) black = pytest.param( 'black', marks=pytest.mark.skipif( is_module_installed('python-lsp-black', '<1.2.0'), reason="Versions older than 1.2 don't handle eol's correctly")) def get_formatter_values(formatter, newline, range_fmt=False, max_line=False): if range_fmt: suffix = 'range' elif max_line: suffix = 'max_line' else: