def _find(self): needle = self.ui.lineedit_needle.text().strip() self._canceled = False if not needle: return filter = self.ui.lineedit_filter.text().strip() self.ui.button_cancel.show() self.ui.button_find.hide() self.ui.treewidget_results.clear() self._last_path = None self._queue = multiprocessing.Queue() self._finder = multiprocessing.Process( target=find_text_in_files, args=(self._queue, needle, list(self._ide.project_files()), filter)) self._n_matches = 0 self._n_files = 0 self._finder.start() oslogger.debug(u'finding {} (PID={})'.format(needle, self._finder.pid)) self.extension_manager.fire( 'register_subprocess', pid=self._finder.pid, description='find_text_in_files:{}'.format(needle)) QTimer.singleShot(1000, self._check_finder)
def file_list(self): while self._indexing: oslogger.debug(u'still indexing {}'.format(self._path)) time.sleep(.1) QApplication.processEvents() return self._file_list
def _set_language(self, language, editor=None): if language is None: return # Getting the current editor if none was given if editor is None: if 'OpenSesameIDE' not in self.extension_manager: oslogger.warning('SpellCheck requires OpenSesameIDE') return editor = self.extension_manager['OpenSesameIDE']._current_editor() if editor is None: return if 'SpellCheckerMode' in editor.modes.keys(): editor.modes.remove('SpellCheckerMode') try: import spellchecker except ImportError: oslogger.warning('failed to import spellchecker') self.extension_manager.fire( 'notify', message=_('Please install pyspellchecker for spell checking')) return oslogger.debug('enabling spellcheck for {}'.format(editor)) spellchecker = modes.SpellCheckerMode() spellchecker.set_ignore_rules(language) editor.modes.append(spellchecker)
def toggle_folder_browsers(self): hidden = not self.folder_browsers_visible() oslogger.debug( 'setting folder-browser visibility to {}'.format(hidden)) for dockwidget in self._dock_widgets.values(): dockwidget.setVisible(hidden)
def event_startup(self): # Loop through all code edit classes that are bundles with the # extension and register them if they're enabled in the configuration. for key in dir(lsp_code_edit_widgets): cls = getattr(lsp_code_edit_widgets, key) # Check if it's a code edit class if not isinstance(cls, type) or not issubclass(cls, CodeEdit): continue # Check if the language server is configured and enabled try: enabled = cfg['lsp_enable_{}'.format(cls.language.lower())] except BaseException: oslogger.warning( '{} language server is missing in config'.format( cls.language)) continue if not enabled: oslogger.debug( '{} language server is disabled in config'.format( cls.language)) continue oslogger.debug('{} language server enabled'.format(cls.language)) cls.extension_manager = self.extension_manager SplittableCodeEditTabWidget.register_code_edit(cls)
def _check_file_indexer(self): if self._queue.empty(): oslogger.debug(u'queue still empty for {}'.format(self._path)) QTimer.singleShot(1000, self._check_file_indexer) return self._file_list = self._queue.get() self._indexing = False if self._file_list is None: self._ide.extension_manager.fire( u'notify', message=_(u'Not indexing {} (too many files)').format( self._path), category=u'warning') self._file_list = [] return oslogger.debug(u'{} files indexed for {}'.format( len(self._file_list), self._path)) self._file_indexer.join() try: self._file_indexer.close() except AttributeError: # Process.close() was introduced only in Python 3.7 pass QTimer.singleShot(300000, self._index_files)
def fire(self, event, **kwdict): if event != 'startup': oslogger.debug('ignoring events until after startup') return JupyterConsole.fire = BaseExtension.fire self.fire(event, **kwdict)
def event_close(self): for pid in self._active_processes: oslogger.debug('killing process {} ({})'.format( pid, self._processes[pid])) p = psutil.Process(pid) p.kill()
def restart(self): oslogger.debug(u'restarting kernel') self._jupyter_widget.request_restart_kernel() self._jupyter_widget.reset(clear=True) self.extension_manager.fire('workspace_restart', name=self.name, workspace_func=self.get_workspace_globals)
def kill(self): self.main_window.set_busy(True) if self._running: oslogger.debug('killing jupyter-lab') self._process.kill() time.sleep(1) self._update() self.main_window.set_busy(False)
def event_register_subprocess(self, pid, description): if not hasattr(self, '_parachute'): self._processes = {} self._parachute_start() self._ended = [] oslogger.debug('{}: {}'.format(pid, description)) self._processes[pid] = description self._queue.put(pid)
def event_startup(self): try: self._mimetypes = [ safe_decode(s) for s in cfg.spellcheck_mimetypes.split(';') ] except Exception as e: oslogger.debug('failed to parse mimetypes: {}'.format(e)) self._mimetypes = [] oslogger.debug('enabling spellcheck for {}'.format(self._mimetypes))
def _stop_indexing(self): """Stops the file indexer by stopping any active timers and by killing running indexer processes. """ if self._timer is not None and self._timer.isActive(): oslogger.debug(u'stopping timer for {}'.format(self._path)) self._timer.stop() if self._indexing: oslogger.debug(u'killing indexer for {}'.format(self._path)) self._file_indexer.terminate() self._indexing = False
def _inspect_fnc(self, cls): try: m = importlib.import_module( 'data_viewer_inspectors.inspect_{}'.format(cls)) except ModuleNotFoundError: oslogger.debug('using fallback inspector for type {}'.format(cls)) return self._inspect_fallback else: oslogger.debug('using dedicated inspector for type {}'.format(cls)) return getattr(m, 'inspect_{}'.format(cls))
def _cancel(self): self._canceled = True try: alive = self._finder is not None and self._finder.is_alive() except ValueError: # process is closed return if alive: oslogger.debug(u'terminating finder (PID={})'.format( self._finder.pid)) self._finder.terminate()
def _restore_open_folders(self): folders = [ folder for folder in cfg.opensesame_ide_last_folder.split(u';') if os.path.isdir(folder) ] if not folders: oslogger.debug('opening current working directory') folders = [os.getcwd()] for folder in folders: self._open_folder(folder)
def __init__(self, main_window, info={}): BaseExtension.__init__(self, main_window, info=info) try: qm_path = self.ext_resource(main_window.locale + u'.qm') except Exception as e: return oslogger.debug('installing translator {}'.format(qm_path)) self._rapunzel_translator = main_window.translators.pop() self._rapunzel_translator.load(qm_path) QCoreApplication.installTranslator(self._rapunzel_translator)
def refresh(self, value): self._value = value cls = self._value.__class__.__name__ fnc = self._inspect_fnc(cls) try: widget = fnc(value) except Exception as e: oslogger.debug('failed to inspect {}: {}'.format(self._name, e)) widget = self._inspect_fallback(value) self.setWidget(widget) self.setWindowTitle('{}: {}'.format(self._name, cls))
def restart(self): oslogger.debug(u'restarting kernel') self._jupyter_widget.request_restart_kernel() self._jupyter_widget.reset(clear=True) self.extension_manager.fire('workspace_restart', name=self.name, workspace_func=self.get_workspace_globals) self.extension_manager.fire('register_subprocess', pid=self.pid, description='jupyter_console:{}'.format( self.name))
def _open_folder(self, path): path = os.path.abspath(path) if path in list(self._dock_widgets): return oslogger.debug(u'adding folder browser: {}'.format(path)) dock_widget = FolderBrowserDockWidget(self.main_window, self, path) self.main_window.addDockWidget(Qt.LeftDockWidgetArea, dock_widget) self._dock_widgets[path] = dock_widget if not self.folder_browsers_visible(): self.toggle_folder_browsers() self._remember_open_folders() self._add_recent_folder(path)
def _installed_kernels(self): if cfg.jupyter_kernels: return safe_decode(cfg.jupyter_kernels).split(u';') kernelspec_manager = kernelspec.KernelSpecManager() kernels = list(kernelspec_manager.find_kernel_specs().keys()) # Python 2 and 3 kernels apparently just start the same kernel that # corresponds to the active Python kernel. So if they are both # installed, we expose only one. if 'python2' in kernels and 'python3' in kernels: kernels.remove('python2') oslogger.debug('installed kernels: {}'.format(str(kernels))) return kernels
def provide_jupyter_notebook_cells(self, code=u'', cell_types=None): """Dynamically loads a parser function for the language of the current editor, and uses this to parse the code into cells. The `cell_types` keyword allows specific kinds of cells to be returned. """ language = self.extension_manager.provide('ide_current_language') try: m = importlib.import_module( 'jupyter_notebook_cell_parsers.parse_{}'.format(language)) except ModuleNotFoundError: oslogger.debug('no cell parser for language {}'.format(language)) return return getattr(m, 'parse_{}'.format(language))(code, cell_types)
def _index_files(self, _=None): if self._indexing: oslogger.debug(u'indexing in progress for {}'.format(self._path)) return self._indexing = True self._queue = multiprocessing.Queue() self._file_indexer = multiprocessing.Process( target=file_indexer, args=(self._queue, self._path, self._ide.ignore_patterns, cfg.opensesame_ide_max_index_files)) self._file_indexer.start() oslogger.debug(u'indexing {} (PID={})'.format(self._path, self._file_indexer.pid)) QTimer.singleShot(1000, self._check_file_indexer)
def _set_language(self, language, editor=None): # Getting the current editor if none was given if editor is None: if 'OpenSesameIDE' not in self.extension_manager: oslogger.warning('SpellCheck requires OpenSesameIDE') return editor = self.extension_manager['OpenSesameIDE']._current_editor() if editor is None: return if 'SpellCheckerMode' in editor.modes.keys(): editor.modes.remove('SpellCheckerMode') if hasattr(editor, 'action_ignore_word'): editor.action_ignore_word.triggered.disconnect( self._ignore_current) editor.remove_action(editor.action_ignore_word, sub_menu=_('Spell checking')) editor.action_clear_ignore.triggered.disconnect( self._clear_ignore) editor.remove_action(editor.action_clear_ignore, sub_menu=_('Spell checking')) if language is None: return # disable spell checker try: import spellchecker except ImportError: oslogger.warning('failed to import spellchecker') self.extension_manager.fire( 'notify', message=_('Please install pyspellchecker for spell checking')) return oslogger.debug('enabling spellcheck for {}'.format(editor)) spellchecker = modes.SpellCheckerMode() spellchecker.add_extra_info('language', language) spellchecker.add_extra_info('ignore', self._ignore_list()) editor.modes.append(spellchecker) # Add context menu actions editor.action_ignore_word = QAction(_('Add word to custom dictionary'), editor) editor.action_ignore_word.triggered.connect(self._ignore_current) editor.add_action(editor.action_ignore_word, sub_menu=_('Spell checking')) editor.action_clear_ignore = QAction(_('Clear custom dictionary'), editor) editor.action_clear_ignore.triggered.connect(self._clear_ignore) editor.add_action(editor.action_clear_ignore, sub_menu=_('Spell checking'))
def toggle_folder_browsers(self): hidden = not self.folder_browsers_visible() oslogger.debug( 'setting folder-browser visibility to {}'.format(hidden)) # This ensures that, when multiple dockwidgets are tabified together, # the correct one is on top when the dockwidgets are revealed again. # This is done by moving the invisible dockwidgets to the end of the # dict of dockwidgets so that they are made visible last. This only # works for recent versions of Python that support the # OrderDict.move_to_end() function. if not hidden and hasattr(self._dock_widgets, 'move_to_end'): for path, dockwidget in list(self._dock_widgets.items()): if dockwidget.visibleRegion().isEmpty(): self._dock_widgets.move_to_end(path) for dockwidget in self.dock_widgets: dockwidget.setVisible(hidden)
def open_document(self, path): # First normalize the path and check if there's a custom handler for it path = os.path.abspath(os.path.normpath(path)) ext = os.path.splitext(path)[1].lstrip('.').lower() handler = self.extension_manager.provide( 'open_file_extension_{}'.format(ext)) if not handler: self._open_document_as_text(path) return oslogger.debug('custom handler for .{} extension'.format(ext)) handler_fnc, handler_desc = handler self.extension_manager.fire( u'quick_select', haystack=[(handler_desc, path, handler_fnc), (_('Open as text'), path, self._open_document_as_text)], placeholder_text=_(u'How do you want to open this file?'))
def _set_language(self, language, editor=None): if language is None: return # Getting the current editor if none was given if editor is None: if 'OpenSesameIDE' not in self.extension_manager: oslogger.warning('SpellCheck requires OpenSesameIDE') return editor = self.extension_manager['OpenSesameIDE']._current_editor() if editor is None: return if 'SpellCheckerMode' in editor.modes.keys(): editor.modes.remove('SpellCheckerMode') oslogger.debug('enabling spellcheck for {}'.format(editor)) spellchecker = modes.SpellCheckerMode() spellchecker.set_ignore_rules(language) editor.modes.append(spellchecker)
def _img_to_file(self, img, fmt): """Save an image to file and return the filename. Inspired by Spyder's `figurebrowser.py`. """ if fmt == 'image/svg+xml': ext = '.svg' elif fmt == 'image/png': ext = '.png' elif fmt == 'image/jpeg': ext = '.jpg' else: raise ValueError('invalid image format: {}'.format(fmt)) path = os.path.join(self._image_folder, uuid.uuid4().hex + ext) oslogger.debug('writing image to {}'.format(path)) if fmt == 'image/svg+xml' and isinstance(img, str): img = img.encode('utf-8') with open(path, 'wb') as fd: fd.write(img) return path
def _launch(self): self.main_window.set_busy(True) if self._running: oslogger.debug('jupyter-lab is already running') return try: self._process = subprocess.Popen(self._executable) except Exception as e: self._jupyter.notify( _(u'Failed to launch Jupyter Lab. ' u'See debug window for error message.')) self.console.write(e) self.main_window.set_busy(False) else: time.sleep(1) self._update() oslogger.debug('jupyterlab started (PID={})'.format( self._process.pid)) self.main_window.set_busy(False)
def _check_finder(self): if self._queue.empty(): try: oslogger.debug(u'no results yet for finder (PID={})'.format( self._finder.pid)) except ValueError: # Is raised when getting the pid of a closed process return QTimer.singleShot(1000, self._check_finder) return path, line_number, matching_line = self._queue.get() if path is None or self._canceled: self.ui.button_cancel.hide() self.ui.button_find.show() self._finder.join() oslogger.debug(u'finder done (PID={})'.format(self._finder.pid)) try: self._finder.close() except AttributeError: # Process.close() was introduced only in Python 3.7 pass self.extension_manager.fire( u'notify', message=_('Found {} match(es) in {} file(s)').format( self._n_matches, self._n_files) if self._n_matches else _('No matches found')) return if path != self._last_path: self._path_item = QTreeWidgetItem(self.ui.treewidget_results, [path]) self._path_item.result = path, 1 self.ui.treewidget_results.addTopLevelItem(self._path_item) self._last_path = path self._n_files += 1 self._n_matches += 1 line_item = QTreeWidgetItem( self._path_item, [u'{}: {}'.format(line_number, matching_line)]) line_item.result = path, line_number self._path_item.addChild(line_item) QTimer.singleShot(10, self._check_finder)